models: require belong_to associations on champ

- Make `champ.dossier` a requirement;
- Move the dossier_id assignation to `before_validation` (otherwise
the record is invalid, and never gets saved);
- Allow specs to only build the champ (instead of saving it to the
database), which bypasses the requirement to have a dossier.
This commit is contained in:
Pierre de La Morinerie 2020-07-20 15:18:44 +00:00
parent eb22dc9d8f
commit 6328011f60
13 changed files with 318 additions and 274 deletions

View file

@ -15,8 +15,8 @@
# type_de_champ_id :integer
#
class Champ < ApplicationRecord
belongs_to :dossier, -> { with_discarded }, inverse_of: :champs, touch: true
belongs_to :type_de_champ, inverse_of: :champ
belongs_to :dossier, -> { with_discarded }, inverse_of: :champs, touch: true, optional: false
belongs_to :type_de_champ, inverse_of: :champ, optional: false
belongs_to :parent, class_name: 'Champ', optional: true
has_many :commentaires
has_one_attached :piece_justificative_file
@ -49,7 +49,7 @@ class Champ < ApplicationRecord
scope :ordered, -> { includes(:type_de_champ).order(:row, 'types_de_champ.order_place') }
scope :root, -> { where(parent_id: nil) }
before_create :set_dossier_id, if: :needs_dossier_id?
before_validation :set_dossier_id, if: :needs_dossier_id?
validates :type_de_champ_id, uniqueness: { scope: [:dossier_id, :row] }

View file

@ -1,14 +1,14 @@
describe Champs::SiretController, type: :controller do
let(:user) { create(:user) }
let(:procedure) { create(:procedure, :published) }
let(:procedure) do
tdc_siret = build(:type_de_champ_siret, procedure: nil)
create(:procedure, :published, types_de_champ: [tdc_siret])
end
describe '#show' do
let(:dossier) { create(:dossier, user: user, procedure: procedure) }
let(:champ) do
d = dossier
type_de_champ = create(:type_de_champ_siret, procedure: procedure)
type_de_champ.champ.create(dossier: d, value: nil, etablissement: nil)
end
let(:champ) { dossier.champs.first }
let(:params) do
{
champ_id: champ.id,
@ -27,6 +27,7 @@ describe Champs::SiretController, type: :controller do
let(:api_etablissement_status) { 200 }
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
let(:token_expired) { false }
before do
sign_in user
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v2\/etablissements\/#{siret}?.*token=/)
@ -112,7 +113,7 @@ describe Champs::SiretController, type: :controller do
champ.reload
expect(champ.value).to eq(siret)
expect(champ.etablissement.siret).to eq(siret)
expect(champ.reload.etablissement.naf).to eq("6202A")
expect(champ.etablissement.naf).to eq("6202A")
expect(dossier.reload.etablissement).to eq(nil)
end
end

View file

@ -561,32 +561,35 @@ describe Instructeurs::DossiersController, type: :controller do
describe "#update_annotations" do
let(:champ_multiple_drop_down_list) do
create(:type_de_champ_multiple_drop_down_list, :private, libelle: 'libelle').champ.create
tdc = create(:type_de_champ_multiple_drop_down_list, :private, procedure: procedure, libelle: 'libelle')
create(:champ_multiple_drop_down_list, :private, type_de_champ: tdc, dossier: dossier)
end
let(:champ_linked_drop_down_list) do
create(:type_de_champ_linked_drop_down_list, :private, libelle: 'libelle').champ.create
tdc = create(:type_de_champ_linked_drop_down_list, :private, procedure: procedure, libelle: 'libelle')
create(:champ_linked_drop_down_list, :private, type_de_champ: tdc, dossier: dossier)
end
let(:champ_datetime) do
create(:type_de_champ_datetime, :private, libelle: 'libelle').champ.create
tdc = create(:type_de_champ_datetime, :private, procedure: procedure, libelle: 'libelle')
create(:champ_datetime, :private, type_de_champ: tdc, dossier: dossier)
end
let(:champ_repetition) do
tdc = create(:type_de_champ_repetition, :private, libelle: 'libelle')
tdc.types_de_champ << create(:type_de_champ_text, libelle: 'libelle')
champ = tdc.champ.create
tdc = create(:type_de_champ_repetition, :private, :with_types_de_champ, procedure: procedure, libelle: 'libelle')
tdc.types_de_champ << create(:type_de_champ_text, procedure: procedure, libelle: 'libelle')
champ = create(:champ_repetition, :private, type_de_champ: tdc, dossier: dossier)
champ.add_row
champ
end
let(:dossier) do
create(:dossier, :en_construction, procedure: procedure, champs_private: [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition])
end
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
let(:now) { Time.zone.parse('01/01/2100') }
before do
dossier.champs_private << [champ_multiple_drop_down_list, champ_linked_drop_down_list, champ_datetime, champ_repetition]
Timecop.freeze(now)
patch :update_annotations, params: params

View file

@ -1,156 +1,142 @@
FactoryBot.define do
factory :champ do
type_de_champ { create(:type_de_champ) }
add_attribute(:private) { false }
trait :checkbox do
type_de_champ { create(:type_de_champ_checkbox) }
end
dossier { association :dossier }
type_de_champ { association :type_de_champ, procedure: dossier.procedure }
trait :header_section do
type_de_champ { create(:type_de_champ_header_section) }
end
trait :explication do
type_de_champ { create(:type_de_champ_explication) }
end
trait :dossier_link do
type_de_champ { create(:type_de_champ_dossier_link) }
end
trait :piece_justificative do
type_de_champ { create(:type_de_champ_piece_justificative) }
trait :private do
add_attribute(:private) { true }
end
trait :with_piece_justificative_file do
after(:create) do |champ, _evaluator|
after(:build) do |champ, _evaluator|
champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
end
end
end
factory :champ_text, class: 'Champs::TextChamp' do
type_de_champ { create(:type_de_champ_text) }
type_de_champ { association :type_de_champ_text, procedure: dossier.procedure }
value { 'text' }
end
factory :champ_textarea, class: 'Champs::TextareaChamp' do
type_de_champ { create(:type_de_champ_textarea) }
type_de_champ { association :type_de_champ_textarea, procedure: dossier.procedure }
value { 'textarea' }
end
factory :champ_date, class: 'Champs::DateChamp' do
type_de_champ { create(:type_de_champ_date) }
type_de_champ { association :type_de_champ_date, procedure: dossier.procedure }
value { '2019-07-10' }
end
factory :champ_datetime, class: 'Champs::DatetimeChamp' do
type_de_champ { create(:type_de_champ_datetime) }
type_de_champ { association :type_de_champ_datetime, procedure: dossier.procedure }
value { '15/09/1962 15:35' }
end
factory :champ_number, class: 'Champs::NumberChamp' do
type_de_champ { create(:type_de_champ_number) }
type_de_champ { association :type_de_champ_number, procedure: dossier.procedure }
value { '42' }
end
factory :champ_decimal_number, class: 'Champs::DecimalNumberChamp' do
type_de_champ { create(:type_de_champ_decimal_number) }
type_de_champ { association :type_de_champ_decimal_number, procedure: dossier.procedure }
value { '42.1' }
end
factory :champ_integer_number, class: 'Champs::IntegerNumberChamp' do
type_de_champ { create(:type_de_champ_integer_number) }
type_de_champ { association :type_de_champ_integer_number, procedure: dossier.procedure }
value { '42' }
end
factory :champ_checkbox, class: 'Champs::CheckboxChamp' do
type_de_champ { create(:type_de_champ_checkbox) }
type_de_champ { association :type_de_champ_checkbox, procedure: dossier.procedure }
value { 'on' }
end
factory :champ_civilite, class: 'Champs::CiviliteChamp' do
type_de_champ { create(:type_de_champ_civilite) }
type_de_champ { association :type_de_champ_civilite, procedure: dossier.procedure }
value { 'M.' }
end
factory :champ_email, class: 'Champs::EmailChamp' do
type_de_champ { create(:type_de_champ_email) }
type_de_champ { association :type_de_champ_email, procedure: dossier.procedure }
value { 'yoda@beta.gouv.fr' }
end
factory :champ_phone, class: 'Champs::PhoneChamp' do
type_de_champ { create(:type_de_champ_phone) }
type_de_champ { association :type_de_champ_phone, procedure: dossier.procedure }
value { '0666666666' }
end
factory :champ_address, class: 'Champs::AddressChamp' do
type_de_champ { create(:type_de_champ_address) }
type_de_champ { association :type_de_champ_address, procedure: dossier.procedure }
value { '2 rue des Démarches' }
end
factory :champ_yes_no, class: 'Champs::YesNoChamp' do
type_de_champ { create(:type_de_champ_yes_no) }
type_de_champ { association :type_de_champ_yes_no, procedure: dossier.procedure }
value { 'true' }
end
factory :champ_drop_down_list, class: 'Champs::DropDownListChamp' do
type_de_champ { create(:type_de_champ_drop_down_list) }
type_de_champ { association :type_de_champ_drop_down_list, procedure: dossier.procedure }
value { 'choix 1' }
end
factory :champ_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do
type_de_champ { create(:type_de_champ_multiple_drop_down_list) }
type_de_champ { association :type_de_champ_multiple_drop_down_list, procedure: dossier.procedure }
value { '["choix 1", "choix 2"]' }
end
factory :champ_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do
type_de_champ { create(:type_de_champ_linked_drop_down_list) }
type_de_champ { association :type_de_champ_linked_drop_down_list, procedure: dossier.procedure }
value { '["categorie 1", "choix 1"]' }
end
factory :champ_pays, class: 'Champs::PaysChamp' do
type_de_champ { create(:type_de_champ_pays) }
type_de_champ { association :type_de_champ_pays, procedure: dossier.procedure }
value { 'France' }
end
factory :champ_regions, class: 'Champs::RegionChamp' do
type_de_champ { create(:type_de_champ_regions) }
type_de_champ { association :type_de_champ_regions, procedure: dossier.procedure }
value { 'Guadeloupe' }
end
factory :champ_departements, class: 'Champs::DepartementChamp' do
type_de_champ { create(:type_de_champ_departements) }
type_de_champ { association :type_de_champ_departements, procedure: dossier.procedure }
value { '971 - Guadeloupe' }
end
factory :champ_communes, class: 'Champs::CommuneChamp' do
type_de_champ { create(:type_de_champ_communes) }
type_de_champ { association :type_de_champ_communes, procedure: dossier.procedure }
value { 'Paris' }
end
factory :champ_engagement, class: 'Champs::EngagementChamp' do
type_de_champ { create(:type_de_champ_engagement) }
type_de_champ { association :type_de_champ_engagement, procedure: dossier.procedure }
value { 'true' }
end
factory :champ_header_section, class: 'Champs::HeaderSectionChamp' do
type_de_champ { create(:type_de_champ_header_section) }
type_de_champ { association :type_de_champ_header_section, procedure: dossier.procedure }
value { 'une section' }
end
factory :champ_explication, class: 'Champs::ExplicationChamp' do
type_de_champ { create(:type_de_champ_explication) }
type_de_champ { association :type_de_champ_explication, procedure: dossier.procedure }
value { '' }
end
factory :champ_dossier_link, class: 'Champs::DossierLinkChamp' do
type_de_champ { create(:type_de_champ_dossier_link) }
type_de_champ { association :type_de_champ_dossier_link, procedure: dossier.procedure }
value { create(:dossier).id }
end
factory :champ_piece_justificative, class: 'Champs::PieceJustificativeChamp' do
type_de_champ { create(:type_de_champ_piece_justificative) }
type_de_champ { association :type_de_champ_piece_justificative, procedure: dossier.procedure }
after(:build) do |champ, _evaluator|
champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
@ -158,7 +144,7 @@ FactoryBot.define do
end
factory :champ_carte, class: 'Champs::CarteChamp' do
type_de_champ { create(:type_de_champ_carte) }
type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure }
end
factory :champ_siret, class: 'Champs::SiretChamp' do
@ -168,30 +154,67 @@ FactoryBot.define do
end
factory :champ_repetition, class: 'Champs::RepetitionChamp' do
type_de_champ { create(:type_de_champ_repetition) }
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
after(:build) do |champ_repetition, _evaluator|
type_de_champ_text = create(:type_de_champ_text, order_place: 0, parent: champ_repetition.type_de_champ, libelle: 'Nom')
type_de_champ_number = create(:type_de_champ_number, order_place: 1, parent: champ_repetition.type_de_champ, libelle: 'Age')
types_de_champ = champ_repetition.type_de_champ.types_de_champ
existing_type_de_champ_text = types_de_champ.find { |tdc| tdc.libelle == 'Nom' }
type_de_champ_text = existing_type_de_champ_text || build(
:type_de_champ_text,
order_place: 0,
procedure: champ_repetition.dossier.procedure,
parent: champ_repetition.type_de_champ,
libelle: 'Nom'
)
create(:champ_text, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition)
create(:champ_text, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition)
create(:champ_number, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
types_de_champ << type_de_champ_text
existing_type_de_champ_number = types_de_champ.find { |tdc| tdc.libelle == 'Age' }
type_de_champ_number = existing_type_de_champ_number || build(
:type_de_champ_number,
order_place: 1,
procedure: champ_repetition.dossier.procedure,
parent: champ_repetition.type_de_champ,
libelle: 'Age'
)
types_de_champ << type_de_champ_number
champ_repetition.champs << [
build(:champ_text, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_text, parent: champ_repetition),
build(:champ_number, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_number, parent: champ_repetition),
build(:champ_text, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_text, parent: champ_repetition),
build(:champ_number, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_number, parent: champ_repetition)
]
end
trait :without_champs do
after(:build) do |champ_repetition, _evaluator|
champ_repetition.champs = []
end
end
end
factory :champ_repetition_with_piece_jointe, class: 'Champs::RepetitionChamp' do
type_de_champ { create(:type_de_champ_repetition) }
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
after(:build) do |champ_repetition, _evaluator|
type_de_champ_pj0 = create(:type_de_champ_piece_justificative, order_place: 0, parent: champ_repetition.type_de_champ, libelle: 'Justificatif de domicile')
type_de_champ_pj1 = create(:type_de_champ_piece_justificative, order_place: 1, parent: champ_repetition.type_de_champ, libelle: 'Carte d\'identité')
type_de_champ_pj0 = build(:type_de_champ_piece_justificative,
procedure: champ_repetition.dossier.procedure,
order_place: 0,
parent: champ_repetition.type_de_champ,
libelle: 'Justificatif de domicile')
type_de_champ_pj1 = build(:type_de_champ_piece_justificative,
procedure: champ_repetition.dossier.procedure,
order_place: 1,
parent: champ_repetition.type_de_champ,
libelle: 'Carte d\'identité')
create(:champ_piece_justificative, row: 0, type_de_champ: type_de_champ_pj0, parent: champ_repetition)
create(:champ_piece_justificative, row: 0, type_de_champ: type_de_champ_pj1, parent: champ_repetition)
create(:champ_piece_justificative, row: 1, type_de_champ: type_de_champ_pj0, parent: champ_repetition)
create(:champ_piece_justificative, row: 1, type_de_champ: type_de_champ_pj1, parent: champ_repetition)
champ_repetition.champs << [
build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_pj0),
build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 0, type_de_champ: type_de_champ_pj1),
build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_pj0),
build(:champ_piece_justificative, dossier: champ_repetition.dossier, row: 1, type_de_champ: type_de_champ_pj1)
]
end
end
end
end

View file

@ -203,7 +203,7 @@ FactoryBot.define do
trait :with_all_champs do
after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", type_de_champ: type_de_champ)
build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ)
end
dossier.save!
end
@ -212,7 +212,7 @@ FactoryBot.define do
trait :with_all_annotations do
after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", type_de_champ: type_de_champ)
build(:"champ_#{type_de_champ.type_champ}", dossier: dossier, type_de_champ: type_de_champ)
end
dossier.save!
end

View file

@ -232,10 +232,10 @@ FactoryBot.define do
if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list'
end
build(:"type_de_champ_#{type_champ}", mandatory: true, libelle: libelle, order_place: index)
build(:"type_de_champ_#{type_champ}", procedure: procedure, mandatory: true, libelle: libelle, order_place: index)
end
procedure.types_de_champ << build(:type_de_champ_drop_down_list, :long, mandatory: true, libelle: 'simple_choice_drop_down_list_long')
procedure.types_de_champ << build(:type_de_champ_multiple_drop_down_list, :long, mandatory: true, libelle: 'multiple_choice_drop_down_list_long')
procedure.types_de_champ << build(:type_de_champ_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'simple_choice_drop_down_list_long')
procedure.types_de_champ << build(:type_de_champ_multiple_drop_down_list, :long, procedure: procedure, mandatory: true, libelle: 'multiple_choice_drop_down_list_long')
end
end
@ -245,7 +245,7 @@ FactoryBot.define do
if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list'
end
build(:"type_de_champ_#{type_champ}", libelle: libelle, order_place: index)
build(:"type_de_champ_#{type_champ}", procedure: procedure, libelle: libelle, order_place: index)
end
end
end
@ -256,7 +256,7 @@ FactoryBot.define do
if libelle == 'drop_down_list'
libelle = 'simple_drop_down_list'
end
build(:"type_de_champ_#{type_champ}", private: true, libelle: libelle, order_place: index)
build(:"type_de_champ_#{type_champ}", procedure: procedure, private: true, libelle: libelle, order_place: index)
end
end
end

View file

@ -94,7 +94,7 @@ FactoryBot.define do
factory :type_de_champ_piece_justificative do
type_champ { TypeDeChamp.type_champs.fetch(:piece_justificative) }
after(:create) do |tc, _evaluator|
after(:build) do |tc, _evaluator|
tc.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
end
end
@ -109,7 +109,7 @@ FactoryBot.define do
trait :with_types_de_champ do
after(:build) do |type_de_champ, _evaluator|
type_de_champ.types_de_champ << create(:type_de_champ, libelle: 'sub type de champ')
type_de_champ.types_de_champ << build(:type_de_champ, procedure: type_de_champ.procedure, libelle: 'sub type de champ')
end
end
end

View file

@ -2,7 +2,7 @@ RSpec.describe VirusScannerJob, type: :job do
include ActiveJob::TestHelper
let(:champ) do
champ = create(:champ, :piece_justificative)
champ = create(:champ_piece_justificative)
champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
champ.save
champ

View file

@ -1,5 +1,5 @@
describe ActiveStorage::DownloadableFile do
let(:dossier) { create(:dossier) }
let(:dossier) { create(:dossier, :en_construction) }
subject(:list) { ActiveStorage::DownloadableFile.create_list_from_dossier(dossier) }
@ -10,7 +10,7 @@ describe ActiveStorage::DownloadableFile do
context 'when there is a piece_justificative' do
before do
dossier.champs << create(:champ, :piece_justificative, :with_piece_justificative_file)
dossier.champs << create(:champ_piece_justificative, :with_piece_justificative_file, dossier: dossier)
end
it { expect(list.length).to eq 1 }
@ -18,15 +18,16 @@ describe ActiveStorage::DownloadableFile do
context 'when there is a private piece_justificative' do
before do
dossier.champs_private << create(:champ, :piece_justificative, :with_piece_justificative_file, private: true)
dossier.champs_private << create(:champ_piece_justificative, :with_piece_justificative_file, private: true, dossier: dossier)
end
it { expect(list.length).to eq 1 }
end
context 'when there is a repetition bloc' do
let(:champ) { build(:champ_repetition_with_piece_jointe) }
let(:dossier) { create(:dossier, :en_construction, champs: [champ]) }
before do
dossier.champs << build(:champ_repetition_with_piece_jointe, dossier: dossier)
end
it 'should have 4 piece_justificatives' do
expect(list.size).to eq 4
@ -35,7 +36,7 @@ describe ActiveStorage::DownloadableFile do
context 'when there is a message with no attachment' do
before do
dossier.commentaires << build(:commentaire, dossier: dossier)
dossier.commentaires << create(:commentaire, dossier: dossier)
end
it { expect(list.length).to eq 0 }
@ -43,7 +44,7 @@ describe ActiveStorage::DownloadableFile do
context 'when there is a message with an attachment' do
before do
dossier.commentaires << build(:commentaire, :with_file, dossier: dossier)
dossier.commentaires << create(:commentaire, :with_file, dossier: dossier)
end
it { expect(list.length).to eq 1 }

View file

@ -1,7 +1,7 @@
shared_examples 'champ_spec' do
describe 'mandatory_and_blank?' do
let(:type_de_champ) { build(:type_de_champ, mandatory: mandatory) }
let(:champ) { type_de_champ.champ.build(value: value) }
let(:champ) { build(:champ, type_de_champ: type_de_champ, value: value) }
let(:value) { '' }
let(:mandatory) { true }
@ -33,8 +33,7 @@ shared_examples 'champ_spec' do
end
context "when type_champ=date" do
let(:type_de_champ) { create(:type_de_champ_date) }
let(:champ) { type_de_champ.champ.create }
let(:champ) { build(:champ_date) }
it "should convert %d/%m/%Y format to ISO" do
champ.value = "31/12/2017"

View file

@ -47,7 +47,7 @@ describe Champ do
let(:public_champ) { dossier.champs.first }
let(:private_champ) { dossier.champs_private.first }
let(:champ_in_repetition) { dossier.champs.find(&:repetition?).champs.first }
let(:standalone_champ) { create(:champ, dossier: nil) }
let(:standalone_champ) { build(:champ, type_de_champ: build(:type_de_champ), dossier: nil) }
it 'returns the sibling champs of a champ' do
expect(public_champ.siblings).to eq(dossier.champs)
@ -58,10 +58,9 @@ describe Champ do
end
describe '#format_datetime' do
let(:type_de_champ) { build(:type_de_champ_datetime) }
let(:champ) { type_de_champ.champ.build(value: value) }
let(:champ) { build(:champ_datetime, value: value) }
before { champ.save }
before { champ.save! }
context 'when the value is sent by a modern browser' do
let(:value) { '2017-12-31 10:23' }
@ -77,10 +76,9 @@ describe Champ do
end
describe '#multiple_select_to_string' do
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list) }
let(:champ) { type_de_champ.champ.build(value: value) }
let(:champ) { build(:champ_multiple_drop_down_list, value: value) }
before { champ.save }
before { champ.save! }
# when using the old form, and the ChampsService Class
# TODO: to remove
@ -412,7 +410,7 @@ describe Champ do
end
describe '#enqueue_virus_check' do
let(:champ) { type_de_champ.champ.build(value: nil) }
let(:champ) { build(:champ_piece_justificative, type_de_champ: type_de_champ) }
context 'when type_champ is type_de_champ_piece_justificative' do
let(:type_de_champ) { create(:type_de_champ_piece_justificative) }
@ -420,7 +418,7 @@ describe Champ do
context 'and there is a blob' do
before do
champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
champ.save
champ.save!
end
it { expect(champ.piece_justificative_file.virus_scanner.started?).to be_truthy }
@ -428,50 +426,69 @@ describe Champ do
end
end
describe "repetition" do
let(:dossier) { create(:dossier) }
let(:champ) { Champs::RepetitionChamp.create(dossier: dossier) }
let(:champ_text) { create(:champ_text, row: 0) }
let(:champ_integer_number) { create(:champ_integer_number, row: 0) }
let(:champ_text_attrs) { attributes_for(:champ_text, row: 1) }
let(:champ_text_row_1) { create(:champ_text, row: 1, parent: champ) }
describe 'repetition' do
let(:procedure) { build(:procedure, :published, :with_type_de_champ, :with_type_de_champ_private) }
let(:tdc_text) { build(:type_de_champ_text, procedure: procedure) }
let(:tdc_integer) { build(:type_de_champ_integer_number, procedure: procedure) }
let(:tdc_repetition) { build(:type_de_champ_repetition, procedure: procedure, types_de_champ: [tdc_text, tdc_integer]) }
it "associates nested champs to the parent dossier" do
expect(champ.rows.size).to eq(0)
dossier.reload
expect(dossier.champs.size).to eq(2)
let(:dossier) { create(:dossier, procedure: procedure) }
let(:champ) { dossier.champs.find(&:repetition?) }
let(:champ_text) { champ.champs.find { |c| c.type_champ == 'text' } }
let(:champ_integer) { champ.champs.find { |c| c.type_champ == 'integer_number' } }
let(:champ_text_attrs) { attributes_for(:champ_text, type_de_champ: tdc_text, row: 1) }
dossier.update(champs_attributes: [
before do
procedure.types_de_champ << tdc_repetition
procedure.save!
procedure.reload
end
context 'when creating the model directly' do
let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row: 2, parent: champ, dossier: nil) }
it 'associates nested champs to the parent dossier' do
expect(champ_text_row_1.dossier_id).to eq(champ.dossier_id)
end
end
context 'when updating using nested attributes' do
subject do
dossier.update!(champs_attributes: [
{
id: champ.id,
champs_attributes: [champ_text_attrs]
}
])
champ.reload
dossier.reload
expect(dossier.champs.size).to eq(2)
expect(champ.rows.size).to eq(1)
end
expect(champ.champs.first.dossier).to eq(dossier)
it 'associates nested champs to the parent dossier' do
subject
expect(dossier.champs.size).to eq(2)
expect(champ.rows.size).to eq(2)
second_row = champ.rows.second
expect(second_row.size).to eq(1)
expect(second_row.first.dossier).to eq(dossier)
# Make champs ordered
champ_integer_number.type_de_champ.update(order_place: 0)
champ_integer.type_de_champ.update(order_place: 0)
champ_text.type_de_champ.update(order_place: 1)
champ.champs << champ_integer_number
row = champ.reload.rows.first
expect(row.size).to eq(1)
expect(row.first).to eq(champ_integer_number)
champ.champs << champ_integer
first_row = champ.reload.rows.first
expect(first_row.size).to eq(2)
expect(first_row.first).to eq(champ_integer)
champ.champs << champ_text
row = champ.reload.rows.first
expect(row.size).to eq(2)
expect(row.second).to eq(champ_text)
first_row = champ.reload.rows.first
expect(first_row.size).to eq(2)
expect(first_row.second).to eq(champ_text)
expect(champ.rows.size).to eq(2)
expect(champ_text_row_1.dossier_id).to eq(champ.dossier_id)
end
end
end
end

View file

@ -21,11 +21,11 @@ describe DossierSerializer do
let(:dossier) { create(:dossier, :en_construction, procedure: create(:procedure, :published, :with_type_de_champ)) }
before do
dossier.champs << create(:champ_carte)
dossier.champs << create(:champ_siret)
dossier.champs << create(:champ_integer_number)
dossier.champs << create(:champ_decimal_number)
dossier.champs << create(:champ_linked_drop_down_list)
dossier.champs << build(:champ_carte)
dossier.champs << build(:champ_siret)
dossier.champs << build(:champ_integer_number)
dossier.champs << build(:champ_decimal_number)
dossier.champs << build(:champ_linked_drop_down_list)
end
it {

View file

@ -13,11 +13,11 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
context "there are some champs" do
let(:dossier) { create(:dossier) }
let(:avis) { create :avis, dossier: dossier, instructeur: instructeur }
let(:champ1) { create(:champ, :checkbox, value: "on") }
let(:champ2) { create(:champ, :header_section, value: "Section") }
let(:champ3) { create(:champ, :explication, value: "mazette") }
let(:champ4) { create(:champ, :dossier_link, value: dossier.id) }
let(:champ5) { create(:champ_textarea, value: "Some long text in a textarea.") }
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: "on") }
let(:champ2) { create(:champ_header_section, dossier: dossier, value: "Section") }
let(:champ3) { create(:champ_explication, dossier: dossier, value: "mazette") }
let(:champ4) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
let(:champ5) { create(:champ_textarea, dossier: dossier, value: "Some long text in a textarea.") }
let(:champs) { [champ1, champ2, champ3, champ4, champ5] }
before { dossier.avis << avis }
@ -71,7 +71,7 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
context "with seen_at" do
let(:dossier) { create(:dossier) }
let(:nouveau_groupe_instructeur) { create(:groupe_instructeur, procedure: dossier.procedure) }
let(:champ1) { create(:champ, :checkbox, value: "on") }
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: "on") }
let(:champs) { [champ1] }
context "with a demande_seen_at after groupe_instructeur_updated_at" do
@ -96,7 +96,7 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
context "with a dossier champ, but we are not authorized to acces the dossier" do
let(:dossier) { create(:dossier) }
let(:champ) { create(:champ, :dossier_link, value: dossier.id) }
let(:champ) { create(:champ_dossier_link, dossier: dossier, value: dossier.id) }
let(:champs) { [champ] }
it { is_expected.not_to have_link("Dossier nº #{dossier.id}") }
@ -106,7 +106,7 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
context "with a dossier_link champ but without value" do
let(:dossier) { create(:dossier) }
let(:champ) { create(:champ, :dossier_link, value: nil) }
let(:champ) { create(:champ_dossier_link, dossier: dossier, value: nil) }
let(:champs) { [champ] }
it { is_expected.to include("Pas de dossier associé") }
@ -114,7 +114,7 @@ describe 'shared/dossiers/champs.html.haml', type: :view do
context "with seen_at" do
let(:dossier) { create(:dossier) }
let(:champ1) { create(:champ, :checkbox, value: "on") }
let(:champ1) { create(:champ_checkbox, dossier: dossier, value: "on") }
let(:champs) { [champ1] }
context "with a demande_seen_at after champ updated_at" do