Merge pull request #10569 from demarches-simplifiees/refactor-remove-champ-factories

refactor: remove champ factories
This commit is contained in:
Paul Chavard 2024-07-22 13:56:55 +00:00 committed by GitHub
commit bf1a057ac3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
120 changed files with 1144 additions and 1540 deletions

View file

@ -476,7 +476,7 @@ module Administrateurs
procedures_result = procedures_result.where(aasm_state: filter.statuses) if filter.statuses.present? procedures_result = procedures_result.where(aasm_state: filter.statuses) if filter.statuses.present?
procedures_result = procedures_result.where("tags @> ARRAY[?]::text[]", filter.tags) if filter.tags.present? procedures_result = procedures_result.where("tags @> ARRAY[?]::text[]", filter.tags) if filter.tags.present?
procedures_result = procedures_result.where(template: true) if filter.template? procedures_result = procedures_result.where(template: true) if filter.template?
procedures_result = procedures_result.where('published_at >= ?', filter.from_publication_date) if filter.from_publication_date.present? procedures_result = procedures_result.where(published_at: filter.from_publication_date..) if filter.from_publication_date.present?
procedures_result = procedures_result.where(service: service) if filter.service_siret.present? procedures_result = procedures_result.where(service: service) if filter.service_siret.present?
procedures_result = procedures_result.where(service: services) if services procedures_result = procedures_result.where(service: services) if services
procedures_result = procedures_result.where(for_individual: filter.for_individual) if filter.for_individual.present? procedures_result = procedures_result.where(for_individual: filter.for_individual) if filter.for_individual.present?

View file

@ -19,9 +19,7 @@ module Loaders
private private
def query(keys) def query(keys)
::Champ.where(@where) ::Champ.where(@where).where(stable_id: keys)
.includes(:type_de_champ)
.where(types_de_champ: { stable_id: keys })
end end
end end
end end

View file

@ -7,10 +7,10 @@ class Migrations::BackfillDossierRepetitionJob < ApplicationJob
.revision .revision
.types_de_champ .types_de_champ
.filter do |type_de_champ| .filter do |type_de_champ|
type_de_champ.type_champ == 'repetition' && dossier.champs.none? { _1.type_de_champ_id == type_de_champ.id } type_de_champ.type_champ == 'repetition' && dossier.champs.none? { _1.stable_id == type_de_champ.stable_id }
end end
.each do |type_de_champ| .each do |type_de_champ|
dossier.champs << type_de_champ.champ.build dossier.champs << type_de_champ.build_champ
end end
end end
end end

View file

@ -1,69 +0,0 @@
class Recovery::AlignChampWithDossierRevision
def initialize(dossiers, progress: nil)
@dossiers = dossiers
@progress = progress
@logs = []
end
attr_reader :logs
def run(destroy_extra_champs: false)
@logs = []
bad_dossier_ids = find_broken_dossier_ids
Dossier
.where(id: bad_dossier_ids)
.includes(:procedure, champs: { type_de_champ: :revisions })
.find_each do |dossier|
bad_champs = dossier.champs.filter { !dossier.revision_id.in?(_1.type_de_champ.revisions.ids) }
bad_champs.each do |champ|
type_de_champ = dossier.revision.types_de_champ.find { _1.stable_id == champ.stable_id }
state = {
champ_id: champ.id,
champ_type_de_champ_id: champ.type_de_champ_id,
dossier_id: dossier.id,
dossier_revision_id: dossier.revision_id,
procedure_id: dossier.procedure.id
}
if type_de_champ.present?
logs << state.merge(status: :updated, type_de_champ_id: type_de_champ.id)
champ.update_column(:type_de_champ_id, type_de_champ.id)
else
logs << state.merge(status: :not_found)
champ.destroy! if destroy_extra_champs
end
end
end
end
def find_broken_dossier_ids
bad_dossier_ids = []
@dossiers.in_batches(of: 15_000) do |dossiers|
dossier_ids_revision_ids = dossiers.pluck(:id, :revision_id)
dossier_ids = dossier_ids_revision_ids.map(&:first)
dossier_ids_type_de_champ_ids = Champ.where(dossier_id: dossier_ids).pluck(:dossier_id, :type_de_champ_id)
type_de_champ_ids = dossier_ids_type_de_champ_ids.map(&:second).uniq
revision_ids_by_type_de_champ_id = ProcedureRevisionTypeDeChamp
.where(type_de_champ_id: type_de_champ_ids)
.pluck(:type_de_champ_id, :revision_id)
.group_by(&:first).transform_values { _1.map(&:second).uniq }
type_de_champ_ids_by_dossier_id = dossier_ids_type_de_champ_ids
.group_by(&:first)
.transform_values { _1.map(&:second).uniq }
bad_dossier_ids += dossier_ids_revision_ids.filter do |(dossier_id, revision_id)|
type_de_champ_ids_by_dossier_id.fetch(dossier_id, []).any? do |type_de_champ_id|
!revision_id.in?(revision_ids_by_type_de_champ_id.fetch(type_de_champ_id, []))
end
end.map(&:first)
@progress.inc(dossiers.count) if @progress
end
@progress.finish if @progress
bad_dossier_ids
end
end

View file

@ -2,8 +2,9 @@ class Champ < ApplicationRecord
include ChampConditionalConcern include ChampConditionalConcern
include ChampsValidateConcern include ChampsValidateConcern
self.ignored_columns += [:type_de_champ_id]
belongs_to :dossier, inverse_of: false, touch: true, optional: false belongs_to :dossier, inverse_of: false, touch: true, optional: false
belongs_to :type_de_champ, inverse_of: :champ, optional: false
belongs_to :parent, class_name: 'Champ', optional: true belongs_to :parent, class_name: 'Champ', optional: true
has_many_attached :piece_justificative_file has_many_attached :piece_justificative_file
@ -15,6 +16,12 @@ class Champ < ApplicationRecord
delegate :procedure, to: :dossier delegate :procedure, to: :dossier
def type_de_champ
@type_de_champ ||= dossier.revision
.types_de_champ
.find(-> { raise "Type De Champ #{stable_id} not found in Revision #{dossier.revision_id}" }) { _1.stable_id == stable_id }
end
delegate :libelle, delegate :libelle,
:type_champ, :type_champ,
:description, :description,
@ -222,7 +229,7 @@ class Champ < ApplicationRecord
end end
def clone(fork = false) def clone(fork = false)
champ_attributes = [:parent_id, :private, :row_id, :type, :type_de_champ_id, :stable_id, :stream] champ_attributes = [:parent_id, :private, :row_id, :type, :stable_id, :stream]
value_attributes = fork || !private? ? [:value, :value_json, :data, :external_id] : [] value_attributes = fork || !private? ? [:value, :value_json, :data, :external_id] : []
relationships = fork || !private? ? [:etablissement, :geo_areas] : [] relationships = fork || !private? ? [:etablissement, :geo_areas] : []

View file

@ -12,13 +12,11 @@ module ChampsValidateConcern
private private
def validate_champ_value? def validate_champ_value?
return false unless visible?
case validation_context case validation_context
when :champs_public_value when :champs_public_value
public? public? && visible?
when :champs_private_value when :champs_private_value
private? private? && visible?
else else
false false
end end

View file

@ -97,7 +97,7 @@ module DossierChampsConcern
attributes = type_de_champ.params_for_champ attributes = type_de_champ.params_for_champ
# TODO: Once we have the right index in place, we should change this to use `create_or_find_by` instead of `find_or_create_by` # TODO: Once we have the right index in place, we should change this to use `create_or_find_by` instead of `find_or_create_by`
champ = champs champ = champs
.create_with(type_de_champ:, **attributes) .create_with(**attributes)
.find_or_create_by!(stable_id: type_de_champ.stable_id, row_id:) .find_or_create_by!(stable_id: type_de_champ.stable_id, row_id:)
attributes[:id] = champ.id attributes[:id] = champ.id
@ -113,7 +113,7 @@ module DossierChampsConcern
parent = revision.parent_of(type_de_champ) parent = revision.parent_of(type_de_champ)
if parent.present? if parent.present?
attributes[:parent] = champs.find { _1.type_de_champ_id == parent.id } attributes[:parent] = champs.find { _1.stable_id == parent.stable_id }
else else
attributes[:parent] = nil attributes[:parent] = nil
end end

View file

@ -50,7 +50,7 @@ module DossierRebaseConcern
# index published types de champ coordinates by stable_id # index published types de champ coordinates by stable_id
target_coordinates_by_stable_id = target_revision target_coordinates_by_stable_id = target_revision
.revision_types_de_champ .revision_types_de_champ
.includes(:type_de_champ, :parent) .includes(:parent)
.index_by(&:stable_id) .index_by(&:stable_id)
changes_by_op = pending_changes changes_by_op = pending_changes
@ -58,7 +58,6 @@ module DossierRebaseConcern
.tap { _1.default = [] } .tap { _1.default = [] }
champs_by_stable_id = champs champs_by_stable_id = champs
.includes(:type_de_champ)
.group_by(&:stable_id) .group_by(&:stable_id)
.transform_values { Champ.where(id: _1) } .transform_values { Champ.where(id: _1) }
.tap { _1.default = Champ.none } .tap { _1.default = Champ.none }
@ -78,14 +77,6 @@ module DossierRebaseConcern
# update champ # update champ
changes_by_op[:update].each { apply(_1, champs_by_stable_id[_1.stable_id]) } changes_by_op[:update].each { apply(_1, champs_by_stable_id[_1.stable_id]) }
# due to repetition tdc clone on update or erase
# we must reassign tdc to the latest version
champs_by_stable_id.each do |stable_id, champs|
if target_coordinates_by_stable_id[stable_id].present? && champs.present?
champs.update_all(type_de_champ_id: target_coordinates_by_stable_id[stable_id].type_de_champ_id)
end
end
# update dossier revision # update dossier revision
update_column(:revision_id, target_revision.id) update_column(:revision_id, target_revision.id)
end end
@ -134,7 +125,7 @@ module DossierRebaseConcern
champ_repetition.champs.map(&:row_id).uniq.each do |row_id| champ_repetition.champs.map(&:row_id).uniq.each do |row_id|
champs << create_champ(target_coordinate, champ_repetition, row_id:) champs << create_champ(target_coordinate, champ_repetition, row_id:)
end end
elsif champ_repetition.mandatory? elsif target_coordinate.parent.mandatory?
champs << create_champ(target_coordinate, champ_repetition, row_id: ULID.generate) champs << create_champ(target_coordinate, champ_repetition, row_id: ULID.generate)
end end
end end

View file

@ -242,10 +242,7 @@ class Dossier < ApplicationRecord
scope :hidden_by_administration_since, -> (since) { where('dossiers.hidden_by_administration_at IS NOT NULL AND dossiers.hidden_by_administration_at >= ?', since) } scope :hidden_by_administration_since, -> (since) { where('dossiers.hidden_by_administration_at IS NOT NULL AND dossiers.hidden_by_administration_at >= ?', since) }
scope :hidden_since, -> (since) { hidden_by_user_since(since).or(hidden_by_administration_since(since)) } scope :hidden_since, -> (since) { hidden_by_user_since(since).or(hidden_by_administration_since(since)) }
scope :with_type_de_champ, -> (stable_id) { scope :with_type_de_champ, -> (stable_id) { joins(:champs).where(champs: { stream: 'main', stable_id: }) }
joins('INNER JOIN champs ON champs.dossier_id = dossiers.id INNER JOIN types_de_champ ON types_de_champ.id = champs.type_de_champ_id')
.where(types_de_champ: { stable_id: })
}
scope :all_state, -> { not_archived.state_not_brouillon } scope :all_state, -> { not_archived.state_not_brouillon }
scope :en_construction, -> { not_archived.state_en_construction } scope :en_construction, -> { not_archived.state_en_construction }
@ -271,20 +268,18 @@ class Dossier < ApplicationRecord
scope :with_followers, -> { left_outer_joins(:follows).where.not(follows: { id: nil }) } scope :with_followers, -> { left_outer_joins(:follows).where.not(follows: { id: nil }) }
scope :with_champs, -> { scope :with_champs, -> {
includes(champs_public: [ includes(champs_public: [
:type_de_champ,
:geo_areas, :geo_areas,
piece_justificative_file_attachments: :blob, piece_justificative_file_attachments: :blob,
champs: [:type_de_champ, piece_justificative_file_attachments: :blob] champs: [piece_justificative_file_attachments: :blob]
]) ])
} }
scope :brouillons_recently_updated, -> { updated_since(2.days.ago).state_brouillon.order_by_updated_at } scope :brouillons_recently_updated, -> { updated_since(2.days.ago).state_brouillon.order_by_updated_at }
scope :with_annotations, -> { scope :with_annotations, -> {
includes(champs_private: [ includes(champs_private: [
:type_de_champ,
:geo_areas, :geo_areas,
piece_justificative_file_attachments: :blob, piece_justificative_file_attachments: :blob,
champs: [:type_de_champ, piece_justificative_file_attachments: :blob] champs: [piece_justificative_file_attachments: :blob]
]) ])
} }
scope :for_api, -> { scope :for_api, -> {
@ -493,10 +488,10 @@ class Dossier < ApplicationRecord
end end
def build_default_champs_for_new_dossier def build_default_champs_for_new_dossier
revision.build_champs_public.each do |champ| revision.build_champs_public(self).each do |champ|
champs_public << champ champs_public << champ
end end
revision.build_champs_private.each do |champ| revision.build_champs_private(self).each do |champ|
champs_private << champ champs_private << champ
end end
champs_public.filter { _1.repetition? && _1.mandatory? }.each do |champ| champs_public.filter { _1.repetition? && _1.mandatory? }.each do |champ|

View file

@ -15,7 +15,7 @@ class DossierPreloader
def in_batches_with_block(size = DEFAULT_BATCH_SIZE, &block) def in_batches_with_block(size = DEFAULT_BATCH_SIZE, &block)
@dossiers.in_batches(of: size) do |batch| @dossiers.in_batches(of: size) do |batch|
data = Dossier.where(id: batch.ids).includes(:individual, :traitement, :etablissement, user: :france_connect_informations, avis: :expert, commentaires: [:instructeur, :expert], revision: :revision_types_de_champ) data = Dossier.where(id: batch.ids).includes(:individual, :traitement, :etablissement, user: :france_connect_informations, avis: :expert, commentaires: [:instructeur, :expert])
dossiers = data.to_a dossiers = data.to_a
load_dossiers(dossiers) load_dossiers(dossiers)
@ -30,39 +30,32 @@ class DossierPreloader
end end
def self.load_one(dossier, pj_template: false) def self.load_one(dossier, pj_template: false)
DossierPreloader.new([dossier]).all(pj_template: pj_template).first DossierPreloader.new([dossier]).all(pj_template:).first
end end
private private
# returns: { revision_id : { type_de_champ_id : position } } def revisions
@revisions ||= ProcedureRevision.where(id: @dossiers.pluck(:revision_id).uniq)
.includes(types_de_champ: { piece_justificative_template_attachment: :blob })
.index_by(&:id)
end
# returns: { revision_id : { stable_id : position } }
def positions def positions
@positions ||= ProcedureRevisionTypeDeChamp @positions ||= revisions
.where(revision_id: @dossiers.pluck(:revision_id).uniq) .transform_values { |revision| revision.revision_types_de_champ.map { [_1.stable_id, _1.position] }.to_h }
.select(:revision_id, :type_de_champ_id, :position)
.group_by(&:revision_id)
.transform_values do |coordinates|
coordinates.index_by(&:type_de_champ_id).transform_values(&:position)
end
end end
def load_dossiers(dossiers, pj_template: false) def load_dossiers(dossiers, pj_template: false)
to_include = @includes_for_champ.dup to_include = @includes_for_champ.dup
to_include << [piece_justificative_file_attachments: :blob] to_include << [piece_justificative_file_attachments: :blob]
if pj_template
to_include << { type_de_champ: { piece_justificative_template_attachment: :blob } }
else
to_include << :type_de_champ
end
all_champs = Champ all_champs = Champ
.includes(to_include) .includes(to_include)
.where(dossier_id: dossiers) .where(dossier_id: dossiers)
.to_a .to_a
load_etablissements(all_champs)
children_champs, root_champs = all_champs.partition(&:child?) children_champs, root_champs = all_champs.partition(&:child?)
champs_by_dossier = root_champs.group_by(&:dossier_id) champs_by_dossier = root_champs.group_by(&:dossier_id)
champs_by_dossier_by_parent = children_champs champs_by_dossier_by_parent = children_champs
@ -74,6 +67,8 @@ class DossierPreloader
dossiers.each do |dossier| dossiers.each do |dossier|
load_dossier(dossier, champs_by_dossier[dossier.id] || [], champs_by_dossier_by_parent[dossier.id] || {}) load_dossier(dossier, champs_by_dossier[dossier.id] || [], champs_by_dossier_by_parent[dossier.id] || {})
end end
load_etablissements(all_champs)
end end
def load_etablissements(champs) def load_etablissements(champs)
@ -90,6 +85,11 @@ class DossierPreloader
end end
def load_dossier(dossier, champs, children_by_parent = {}) def load_dossier(dossier, champs, children_by_parent = {})
revision = revisions[dossier.revision_id]
if revision.present?
dossier.association(:revision).target = revision
end
champs_public, champs_private = champs.partition(&:public?) champs_public, champs_private = champs.partition(&:public?)
dossier.association(:champs).target = [] dossier.association(:champs).target = []
@ -121,8 +121,8 @@ class DossierPreloader
dossier.association(:champs).target += champs dossier.association(:champs).target += champs
parent.association(name).target = champs parent.association(name).target = champs
.filter { positions[dossier.revision_id][_1.type_de_champ_id].present? } .filter { positions[dossier.revision_id][_1.stable_id].present? }
.sort_by { [_1.row_id, positions[dossier.revision_id][_1.type_de_champ_id]] } .sort_by { [_1.row_id, positions[dossier.revision_id][_1.stable_id]] }
# Load children champs # Load children champs
champs.filter(&:block?).each do |parent_champ| champs.filter(&:block?).each do |parent_champ|

View file

@ -41,7 +41,6 @@ class Logic::ChampValue < Logic::Term
return nil if !targeted_champ.visible? return nil if !targeted_champ.visible?
return nil if targeted_champ.blank? & !targeted_champ.drop_down_other? return nil if targeted_champ.blank? & !targeted_champ.drop_down_other?
# on dépense 22ms ici, à cause du map, mais on doit pouvoir passer par un champ type
case targeted_champ.type case targeted_champ.type
when "Champs::YesNoChamp", when "Champs::YesNoChamp",
"Champs::CheckboxChamp" "Champs::CheckboxChamp"

View file

@ -35,14 +35,14 @@ class ProcedureRevision < ApplicationRecord
serialize :ineligibilite_rules, LogicSerializer serialize :ineligibilite_rules, LogicSerializer
def build_champs_public def build_champs_public(dossier)
# reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc # reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc
types_de_champ_public.reload.map(&:build_champ) types_de_champ_public.reload.map { _1.build_champ(dossier:) }
end end
def build_champs_private def build_champs_private(dossier)
# reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc # reload: it can be out of sync in test if some tdcs are added wihtout using add_tdc
types_de_champ_private.reload.map(&:build_champ) types_de_champ_private.reload.map { _1.build_champ(dossier:) }
end end
def add_type_de_champ(params) def add_type_de_champ(params)

View file

@ -179,16 +179,6 @@ class TypeDeChamp < ApplicationRecord
.where(type_champ: [TypeDeChamp.type_champs.fetch(:text), TypeDeChamp.type_champs.fetch(:textarea)]) .where(type_champ: [TypeDeChamp.type_champs.fetch(:text), TypeDeChamp.type_champs.fetch(:textarea)])
} }
has_many :champ, inverse_of: :type_de_champ, dependent: :destroy do
def build(params = {})
super(params.merge(proxy_association.owner.params_for_champ))
end
def create(params = {})
super(params.merge(proxy_association.owner.params_for_champ))
end
end
has_one_attached :piece_justificative_template has_one_attached :piece_justificative_template
validates :piece_justificative_template, size: { less_than: FILE_MAX_SIZE }, on: :update validates :piece_justificative_template, size: { less_than: FILE_MAX_SIZE }, on: :update
validates :piece_justificative_template, content_type: AUTHORIZED_CONTENT_TYPES, on: :update validates :piece_justificative_template, content_type: AUTHORIZED_CONTENT_TYPES, on: :update
@ -257,7 +247,7 @@ class TypeDeChamp < ApplicationRecord
end end
def build_champ(params = {}) def build_champ(params = {})
champ.build(params) self.class.type_champ_to_champ_class_name(type_champ).constantize.new(params_for_champ.merge(params))
end end
def check_mandatory def check_mandatory
@ -740,7 +730,6 @@ class TypeDeChamp < ApplicationRecord
return true if type_champ_to_champ_class_name(type_champ) != champ.type return true if type_champ_to_champ_class_name(type_champ) != champ.type
# special case for linked drop down champ it's blank implementation is not what you think # special case for linked drop down champ it's blank implementation is not what you think
return champ.value.blank? if type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list) return champ.value.blank? if type_champ == TypeDeChamp.type_champs.fetch(:linked_drop_down_list)
champ.blank? champ.blank?
end end
end end

View file

@ -1,19 +0,0 @@
namespace :after_party do
desc 'Deployment task: fix_champs_revisions'
task fix_champs_revisions: :environment do
puts "Running deploy task 'fix_champs_revisions'"
progress = ProgressReport.new(Dossier.count)
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier, progress:)
fixer.run
fixer.logs.each do |log|
puts JSON.dump(log)
end
# Update task as completed. If you remove the line below, the task will
# run with every deploy (or every time you call after_party:run).
AfterParty::TaskRecord
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
end
end

View file

@ -1,5 +1,8 @@
RSpec.describe Attachment::EditComponent, type: :component do RSpec.describe Attachment::EditComponent, type: :component do
let(:champ) { create(:champ_titre_identite, dossier: create(:dossier)) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :titre_identite }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:attached_file) { champ.piece_justificative_file } let(:attached_file) { champ.piece_justificative_file }
let(:attachment) { attached_file.attachments.first } let(:attachment) { attached_file.attachments.first }
let(:filename) { attachment.filename.to_s } let(:filename) { attachment.filename.to_s }
@ -98,8 +101,6 @@ RSpec.describe Attachment::EditComponent, type: :component do
end end
context 'when watermark is pending' do context 'when watermark is pending' do
let(:champ) { create(:champ_titre_identite) }
it 'displays the filename, but doesnt allow to download the file' do it 'displays the filename, but doesnt allow to download the file' do
expect(attachment.watermark_pending?).to be_truthy expect(attachment.watermark_pending?).to be_truthy
expect(subject).to have_text(filename) expect(subject).to have_text(filename)

View file

@ -1,5 +1,9 @@
RSpec.describe Attachment::MultipleComponent, type: :component do RSpec.describe Attachment::MultipleComponent, type: :component do
let(:champ) { create(:champ_titre_identite) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :titre_identite }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:attached_file) { champ.piece_justificative_file } let(:attached_file) { champ.piece_justificative_file }
let(:kwargs) { {} } let(:kwargs) { {} }
@ -14,14 +18,11 @@ RSpec.describe Attachment::MultipleComponent, type: :component do
subject { render_inline(component).to_html } subject { render_inline(component).to_html }
context 'when there is no attachment yet' do context 'when there is no attachment yet' do
let(:champ) { create(:champ_titre_identite, skip_default_attachment: true) } let(:dossier) { create(:dossier, procedure:) }
it 'renders a form field for uploading a file' do it 'renders a form field for uploading a file and max attachment size' do
expect(subject).to have_no_selector('.hidden input[type=file]') expect(subject).to have_no_selector('.hidden input[type=file]')
expect(subject).to have_selector('input[type=file]:not(.hidden)') expect(subject).to have_selector('input[type=file]:not(.hidden)')
end
it 'renders max size' do
expect(subject).to have_content(/Taille maximale :\s+20 Mo/) expect(subject).to have_content(/Taille maximale :\s+20 Mo/)
end end
end end

View file

@ -3,15 +3,16 @@
require "rails_helper" require "rails_helper"
RSpec.describe Attachment::PendingPollComponent, type: :component do RSpec.describe Attachment::PendingPollComponent, type: :component do
let(:champ) { create(:champ_titre_identite) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:attachment) { champ.piece_justificative_file.attachments.first } let(:types_de_champ_public) { [{ type: :titre_identite }] }
let(:component) { let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
described_class.new(poll_url: "poll-here", attachment:) let(:champ) { dossier.champs.first }
}
subject { let(:attachment) { champ.piece_justificative_file.attachments.first }
render_inline(component).to_html
} let(:component) { described_class.new(poll_url: "poll-here", attachment:) }
subject { render_inline(component).to_html }
context "when watermark is pending" do context "when watermark is pending" do
it "renders turbo poll attributes" do it "renders turbo poll attributes" do
@ -48,7 +49,8 @@ RSpec.describe Attachment::PendingPollComponent, type: :component do
end end
context "when antivirus is in progress on pj" do context "when antivirus is in progress on pj" do
let(:champ) { create(:champ_piece_justificative) } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
before do before do
attachment.blob.virus_scan_result = ActiveStorage::VirusScanner::PENDING attachment.blob.virus_scan_result = ActiveStorage::VirusScanner::PENDING
end end

View file

@ -1,16 +1,14 @@
RSpec.describe Attachment::ShowComponent, type: :component do RSpec.describe Attachment::ShowComponent, type: :component do
let(:champ) { create(:champ_piece_justificative) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:virus_scan_result) { nil } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:attachment) { let(:champ) { dossier.champs.first }
champ.piece_justificative_file.attachments.first
}
let(:attachment) { champ.piece_justificative_file.attachments.first }
let(:filename) { attachment.filename.to_s } let(:filename) { attachment.filename.to_s }
let(:component) do let(:virus_scan_result) { nil }
described_class.new(attachment:) let(:component) { described_class.new(attachment:) }
end
subject { render_inline(component).to_html } subject { render_inline(component).to_html }

View file

@ -1,25 +1,29 @@
describe EditableChamp::DatetimeComponent, type: :component do describe EditableChamp::DatetimeComponent, type: :component do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :datetime, stable_id: 99 }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:component) { let(:component) {
described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:)
} }
describe '#formatted_value_for_datetime_locale' do describe '#formatted_value_for_datetime_locale' do
# before { champ.validate(:prefill) }
subject { component.formatted_value_for_datetime_locale } subject { component.formatted_value_for_datetime_locale }
context 'when the value is nil' do context 'when the value is nil' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: nil) } let(:champ) { Champs::DatetimeChamp.new(value: nil, dossier:, stable_id: 99) }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'when the value is not a valid datetime' do context 'when the value is not a valid datetime' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: 'invalid') } let(:champ) { Champs::DatetimeChamp.new(value: 'invalid', dossier:, stable_id: 99) }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'when the value is a valid datetime' do context 'when the value is a valid datetime' do
let(:champ) { create(:champ_datetime, dossier: create(:dossier), value: '2020-01-01T00:00:00+01:00') } let(:champ) { Champs::DatetimeChamp.new(value: '2020-01-01T00:00:00+01:00', dossier:, stable_id: 99) }
it { is_expected.to eq('2020-01-01T00:00') } it { is_expected.to eq('2020-01-01T00:00') }
end end

View file

@ -1,71 +1,60 @@
describe EditableChamp::EditableChampComponent, type: :component do describe EditableChamp::EditableChampComponent, type: :component do
let(:component) { described_class.new(form: nil, champ: champ) } let(:procedure) { create(:procedure, types_de_champ_public:, types_de_champ_private:) }
let(:types_de_champ_public) { [] }
let(:types_de_champ_private) { [] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:component) { described_class.new(form: nil, champ:) }
describe "editable_champ_controller" do describe "editable_champ_controller" do
let(:dossier) { create(:dossier) }
let(:champ) { create(:champ, dossier: dossier) }
let(:controllers) { [] } let(:controllers) { [] }
let(:data) { controllers.join(' ') } let(:data) { controllers.join(' ') }
subject { component.send(:stimulus_controller) } subject { component.send(:stimulus_controller) }
context 'when an editable champ' do context 'when an editable public champ' do
let(:controllers) { ['autosave'] } let(:controllers) { ['autosave'] }
let(:types_de_champ_public) { [{ type: :text }] }
it { expect(subject).to eq(data) } it { expect(subject).to eq(data) }
end end
context 'when a repetition champ' do context 'when a repetition champ' do
let(:champ) { create(:champ_repetition, dossier: dossier) } let(:types_de_champ_public) { [{ type: :repetition, children: [{ type: :text }] }] }
it { expect(subject).to eq(nil) } it { expect(subject).to eq(nil) }
end end
context 'when a carte champ' do context 'when a carte champ' do
let(:champ) { create(:champ_carte, dossier: dossier) } let(:types_de_champ_public) { [{ type: :carte }] }
it { expect(subject).to eq(nil) } it { expect(subject).to eq(nil) }
end end
context 'when a private champ' do context 'when a private champ' do
let(:champ) { create(:champ, dossier: dossier, private: true) } let(:types_de_champ_private) { [{ type: :text }] }
it { expect(subject).to eq('autosave') } it { expect(subject).to eq('autosave') }
end end
context 'when a dossier is en_construction' do context 'when a dossier is en_construction' do
let(:controllers) { ['autosave'] } let(:controllers) { ['autosave'] }
let(:dossier) { create(:dossier, :en_construction) } let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
it { expect(subject).to eq(data) }
context 'when a public dropdown champ' do context 'when a public dropdown champ' do
let(:controllers) { ['autosave'] } let(:controllers) { ['autosave'] }
let(:champ) { create(:champ_drop_down_list, dossier: dossier) } let(:types_de_champ_public) { [{ type: :drop_down_list }] }
it { expect(subject).to eq(data) } it { expect(subject).to eq(data) }
end end
context 'when a private dropdown champ' do context 'when a private dropdown champ' do
let(:controllers) { ['autosave'] } let(:controllers) { ['autosave'] }
let(:champ) { create(:champ_drop_down_list, dossier: dossier, private: true) } let(:types_de_champ_private) { [{ type: :drop_down_list }] }
it { expect(subject).to eq(data) } it { expect(subject).to eq(data) }
end end
end end
context 'when a public dropdown champ' do
let(:controllers) { ['autosave'] }
let(:champ) { create(:champ_drop_down_list, dossier: dossier) }
it { expect(subject).to eq(data) }
end
context 'when a private dropdown champ' do
let(:controllers) { ['autosave'] }
let(:champ) { create(:champ_drop_down_list, dossier: dossier, private: true) }
it { expect(subject).to eq(data) }
end
end end
end end

View file

@ -1,22 +1,24 @@
describe EditableChamp::ExplicationComponent, type: :component do describe EditableChamp::ExplicationComponent, type: :component do
let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:component) { let(:component) {
described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:)
} }
let(:champ) { create(:champ_explication) }
describe 'no description' do describe 'no description' do
let(:types_de_champ_public) { [{ type: :explication }] }
subject { render_inline(component).to_html } subject { render_inline(component).to_html }
it { is_expected.not_to have_button("Lire plus") } it { is_expected.not_to have_button("Lire plus") }
end end
describe 'collapsed text is collapsed' do describe 'collapsed text is collapsed' do
subject { render_inline(component).to_html } let(:types_de_champ_public) { [{ type: :explication, collapsible_explanation_enabled: "1", collapsible_explanation_text: "hide me" }] }
before do subject { render_inline(component).to_html }
champ.type_de_champ.update!(collapsible_explanation_enabled: "1", collapsible_explanation_text: "hide me")
end
it { is_expected.to have_button("Lire plus") } it { is_expected.to have_button("Lire plus") }
it { is_expected.to have_selector(".fr-collapse", text: "hide me") } it { is_expected.to have_selector(".fr-collapse", text: "hide me") }

View file

@ -1,5 +1,9 @@
describe EditableChamp::PieceJustificativeComponent, type: :component do describe EditableChamp::PieceJustificativeComponent, type: :component do
let(:champ) { create(:champ_piece_justificative, dossier: create(:dossier)) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:component) { let(:component) {
described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:) described_class.new(form: instance_double(ActionView::Helpers::FormBuilder, object_name: "dossier[champs_public_attributes]"), champ:)
} }
@ -9,7 +13,6 @@ describe EditableChamp::PieceJustificativeComponent, type: :component do
} }
context 'when there is a template' do context 'when there is a template' do
let(:template) { champ.type_de_champ.piece_justificative_template }
let(:profil) { :user } let(:profil) { :user }
before do before do

View file

@ -2,6 +2,7 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
include ActionView::Context include ActionView::Context
include ActionView::Helpers::FormHelper include ActionView::Helpers::FormHelper
include ActionView::Helpers::FormOptionsHelper include ActionView::Helpers::FormOptionsHelper
let(:procedure) { create(:procedure, types_de_champ_public:) }
let(:component) do let(:component) do
cmp = nil cmp = nil
@ -14,8 +15,8 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
describe 'header_section_options_for_select' do describe 'header_section_options_for_select' do
context 'without upper tdc' do context 'without upper tdc' do
let(:tdc) { header.type_de_champ } let(:types_de_champ_public) { [{ type: :header_section, level: 1 }] }
let(:header) { build(:champ_header_section) } let(:tdc) { procedure.draft_revision.types_de_champ_public.first }
let(:upper_tdcs) { [] } let(:upper_tdcs) { [] }
it 'allows up to level 1 header section' do it 'allows up to level 1 header section' do
@ -24,9 +25,14 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
end end
context 'with upper tdc of level 1' do context 'with upper tdc of level 1' do
let(:tdc) { header.type_de_champ } let(:types_de_champ_public) do
let(:header) { build(:champ_header_section_level_1) } [
let(:upper_tdcs) { [build(:champ_header_section_level_1).type_de_champ] } { type: :header_section, level: 1 },
{ type: :header_section, level: 2 }
]
end
let(:tdc) { procedure.draft_revision.types_de_champ_public.last }
let(:upper_tdcs) { [procedure.draft_revision.types_de_champ_public.first] }
it 'allows up to level 2 header section' do it 'allows up to level 2 header section' do
expect(subject).to have_selector("option", count: 2) expect(subject).to have_selector("option", count: 2)
@ -34,34 +40,24 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
end end
context 'with upper tdc of level 2' do context 'with upper tdc of level 2' do
let(:tdc) { header.type_de_champ } let(:types_de_champ_public) do
let(:header) { build(:champ_header_section_level_1) } [
let(:upper_tdcs) { [build(:champ_header_section_level_1), build(:champ_header_section_level_2)].map(&:type_de_champ) } { type: :header_section, level: 1 },
{ type: :header_section, level: 2 },
{ type: :header_section, level: 3 }
]
end
let(:tdc) { procedure.draft_revision.types_de_champ_public.third }
let(:upper_tdcs) { [procedure.draft_revision.types_de_champ_public.first, procedure.draft_revision.types_de_champ_public.second] }
it 'allows up to level 3 header section' do it 'allows up to level 3 header section' do
expect(subject).to have_selector("option", count: 3) expect(subject).to have_selector("option", count: 3)
end end
end end
context 'with upper tdc of level 3' do
let(:tdc) { header.type_de_champ }
let(:header) { build(:champ_header_section_level_1) }
let(:upper_tdcs) do
[
build(:champ_header_section_level_1),
build(:champ_header_section_level_2),
build(:champ_header_section_level_3)
].map(&:type_de_champ)
end
it 'reaches limit of at most 3 section level' do
expect(subject).to have_selector("option", count: 3)
end
end
context 'with error' do context 'with error' do
let(:tdc) { header.type_de_champ } let(:types_de_champ_public) { [{ type: :header_section, level: 2 }] }
let(:header) { build(:champ_header_section_level_2) } let(:tdc) { procedure.draft_revision.types_de_champ_public.first }
let(:upper_tdcs) { [] } let(:upper_tdcs) { [] }
it 'includes disabled levels' do it 'includes disabled levels' do
@ -72,8 +68,8 @@ RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
end end
describe 'errors' do describe 'errors' do
let(:tdc) { header.type_de_champ } let(:types_de_champ_public) { [{ type: :header_section, level: 2 }] }
let(:header) { build(:champ_header_section_level_2) } let(:tdc) { procedure.draft_revision.types_de_champ_public.first }
let(:upper_tdcs) { [] } let(:upper_tdcs) { [] }
it 'returns errors' do it 'returns errors' do

View file

@ -208,6 +208,6 @@ RSpec.describe API::Public::V1::DossiersController, type: :controller do
private private
def find_champ_by_stable_id(dossier, stable_id) def find_champ_by_stable_id(dossier, stable_id)
dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) dossier.champs.find_by(stable_id:)
end end
end end

View file

@ -3,10 +3,11 @@ describe API::V2::GraphqlController do
let(:generated_token) { APIToken.generate(admin) } let(:generated_token) { APIToken.generate(admin) }
let(:api_token) { generated_token.first } let(:api_token) { generated_token.first }
let(:token) { generated_token.second } let(:token) { generated_token.second }
let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin]) } let(:types_de_champ_public) { [] }
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } let(:procedure) { create(:procedure, :published, :for_individual, :with_service, administrateurs: [admin], types_de_champ_public:) }
let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure: procedure, en_construction_at: 1.day.ago) } let(:dossier) { create(:dossier, :en_construction, :with_individual, :with_populated_champs, procedure:) }
let(:dossier2) { create(:dossier, :en_construction, :with_individual, :archived, procedure: procedure, en_construction_at: 3.days.ago) } let(:dossier1) { create(:dossier, :en_construction, :with_individual, procedure:, en_construction_at: 1.day.ago) }
let(:dossier2) { create(:dossier, :en_construction, :with_individual, :archived, procedure:, en_construction_at: 3.days.ago) }
let(:dossiers) { [dossier] } let(:dossiers) { [dossier] }
let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) } let(:instructeur) { create(:instructeur, followed_dossiers: dossiers) }
@ -806,7 +807,8 @@ describe API::V2::GraphqlController do
end end
describe "champ piece_justificative" do describe "champ piece_justificative" do
let(:champ) { create(:champ_piece_justificative, dossier: dossier) } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:champ) { dossier.champs.first }
let(:byte_size) { 2712286911 } let(:byte_size) { 2712286911 }
context "with deprecated file field" do context "with deprecated file field" do

View file

@ -1,8 +1,9 @@
describe AttachmentsController, type: :controller do describe AttachmentsController, type: :controller do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:attachment) { champ.piece_justificative_file.attachments.first } let(:attachment) { champ.piece_justificative_file.attachments.first }
let(:dossier) { create(:dossier, user: user) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:champ) { create(:champ_piece_justificative, dossier_id: dossier.id) } let(:dossier) { create(:dossier, :with_populated_champs, user:, procedure:) }
let(:champ) { dossier.champs.first }
let(:signed_id) { attachment.blob.signed_id } let(:signed_id) { attachment.blob.signed_id }
describe '#show' do describe '#show' do
@ -46,8 +47,6 @@ describe AttachmentsController, type: :controller do
render_views render_views
let(:attachment) { champ.piece_justificative_file.attachments.first } let(:attachment) { champ.piece_justificative_file.attachments.first }
let(:dossier) { create(:dossier, user: user) }
let(:champ) { create(:champ_piece_justificative, dossier_id: dossier.id) }
let(:signed_id) { attachment.blob.signed_id } let(:signed_id) { attachment.blob.signed_id }
subject do subject do

View file

@ -8,7 +8,8 @@ describe Experts::AvisController, type: :controller do
let(:another_instructeur) { create(:instructeur) } let(:another_instructeur) { create(:instructeur) }
let(:claimant) { create(:expert) } let(:claimant) { create(:expert) }
let(:expert) { create(:expert) } let(:expert) { create(:expert) }
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur, another_instructeur, instructeur_with_instant_avis_notification]) } let(:types_de_champ_public) { [] }
let(:procedure) { create(:procedure, :published, instructeurs: [instructeur, another_instructeur, instructeur_with_instant_avis_notification], types_de_champ_public:) }
let(:procedure_id) { procedure.id } let(:procedure_id) { procedure.id }
let(:another_procedure) { create(:procedure, :published, instructeurs: [instructeur]) } let(:another_procedure) { create(:procedure, :published, instructeurs: [instructeur]) }
let(:dossier) { create(:dossier, :en_construction, procedure:) } let(:dossier) { create(:dossier, :en_construction, procedure:) }
@ -464,7 +465,8 @@ describe Experts::AvisController, type: :controller do
end end
context 'with linked dossiers' do context 'with linked dossiers' do
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } let(:types_de_champ_public) { [{ type: :dossier_link }] }
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
context 'when the expert doesnt share linked dossiers' do context 'when the expert doesnt share linked dossiers' do
let(:invite_linked_dossiers) { false } let(:invite_linked_dossiers) { false }

View file

@ -4,7 +4,8 @@ describe Instructeurs::DossiersController, type: :controller do
let(:instructeur) { create(:instructeur) } let(:instructeur) { create(:instructeur) }
let(:administration) { create(:administration) } let(:administration) { create(:administration) }
let(:instructeurs) { [instructeur] } let(:instructeurs) { [instructeur] }
let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: instructeurs) } let(:types_de_champ_public) { [] }
let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: instructeurs, types_de_champ_public:) }
let(:procedure_accuse_lecture) { create(:procedure, :published, :for_individual, :accuse_lecture, :new_administrateur, instructeurs: instructeurs) } let(:procedure_accuse_lecture) { create(:procedure, :published, :for_individual, :accuse_lecture, :new_administrateur, instructeurs: instructeurs) }
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
let(:dossier_accuse_lecture) { create(:dossier, :en_construction, :with_individual, procedure: procedure_accuse_lecture) } let(:dossier_accuse_lecture) { create(:dossier, :en_construction, :with_individual, procedure: procedure_accuse_lecture) }
@ -854,7 +855,8 @@ describe Instructeurs::DossiersController, type: :controller do
context 'with linked dossiers' do context 'with linked dossiers' do
let(:asked_confidentiel) { false } let(:asked_confidentiel) { false }
let(:previous_avis_confidentiel) { false } let(:previous_avis_confidentiel) { false }
let(:dossier) { create(:dossier, :en_construction, :with_dossier_link, procedure: procedure) } let(:types_de_champ_public) { [{ type: :dossier_link }] }
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
before { subject } before { subject }
context 'when the expert doesnt share linked dossiers' do context 'when the expert doesnt share linked dossiers' do
let(:invite_linked_dossiers) { false } let(:invite_linked_dossiers) { false }
@ -873,7 +875,7 @@ describe Instructeurs::DossiersController, type: :controller do
context 'and the expert can access the linked dossiers' do context 'and the expert can access the linked dossiers' do
let(:saved_avis) { Avis.last(2).first } let(:saved_avis) { Avis.last(2).first }
let(:linked_avis) { Avis.last } let(:linked_avis) { Avis.last }
let(:linked_dossier) { Dossier.find_by(id: dossier.reload.champs_public.filter(&:dossier_link?).filter_map(&:value)) } let(:linked_dossier) { Dossier.find_by(id: dossier.champs.first.value) }
let(:invite_linked_dossiers) do let(:invite_linked_dossiers) do
instructeur.assign_to_procedure(linked_dossier.procedure) instructeur.assign_to_procedure(linked_dossier.procedure)
true true

View file

@ -159,7 +159,7 @@ describe Users::CommencerController, type: :controller do
expect(Dossier.count).to eq(1) expect(Dossier.count).to eq(1)
expect(session[:prefill_token]).to eq(Dossier.last.prefill_token) expect(session[:prefill_token]).to eq(Dossier.last.prefill_token)
expect(session[:prefill_params_digest]).to eq(PrefillChamps.digest({ "champ_#{type_de_champ_text.to_typed_id}" => "blabla" })) expect(session[:prefill_params_digest]).to eq(PrefillChamps.digest({ "champ_#{type_de_champ_text.to_typed_id}" => "blabla" }))
expect(Dossier.last.champs.where(type_de_champ: type_de_champ_text).first.value).to eq("blabla") expect(Dossier.last.champs.where(stable_id: type_de_champ_text.stable_id).first.value).to eq("blabla")
expect(Dossier.last.individual.nom).to eq("Dupont") expect(Dossier.last.individual.nom).to eq("Dupont")
end end
end end
@ -190,8 +190,8 @@ describe Users::CommencerController, type: :controller do
subject { get :commencer, params: { path: path, prefill_token: "token", "champ_#{type_de_champ_text.to_typed_id}" => "blabla" } } subject { get :commencer, params: { path: path, prefill_token: "token", "champ_#{type_de_champ_text.to_typed_id}" => "blabla" } }
context "when the associated dossier exists" do context "when the associated dossier exists" do
let!(:dossier) { create(:dossier, :prefilled, prefill_token: "token") } let(:procedure) { create(:procedure, types_de_champ_public: [{}]) }
let!(:champ_text) { create(:champ_text, dossier: dossier, type_de_champ: type_de_champ_text) } let!(:dossier) { create(:dossier, :prefilled, procedure:, prefill_token: "token") }
it "does not create a new dossier" do it "does not create a new dossier" do
subject subject

View file

@ -1,174 +1,110 @@
FactoryBot.define do FactoryBot.define do
factory :champ do factory :champ_do_not_use, class: 'Champ' do
stream { 'main' } stream { 'main' }
add_attribute(:private) { false } add_attribute(:private) { false }
dossier { association :dossier } factory :champ_do_not_use_text, class: 'Champs::TextChamp' do
type_de_champ { association :type_de_champ, procedure: dossier.procedure }
after(:build) do |champ, _evaluator|
champ.stable_id = champ.type_de_champ.stable_id
end
trait :private do
add_attribute(:private) { true }
end
trait :with_piece_justificative_file do
after(:build) do |champ, _evaluator|
champ.piece_justificative_file.attach(
io: StringIO.new("toto"),
filename: "toto.txt",
content_type: "text/plain",
# we don't want to run virus scanner on this file
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
)
end
end
factory :champ_text, class: 'Champs::TextChamp' do
type_de_champ { association :type_de_champ_text, procedure: dossier.procedure }
value { 'text' } value { 'text' }
end end
factory :champ_textarea, class: 'Champs::TextareaChamp' do factory :champ_do_not_use_textarea, class: 'Champs::TextareaChamp' do
type_de_champ { association :type_de_champ_textarea, procedure: dossier.procedure }
value { 'textarea' } value { 'textarea' }
end end
factory :champ_date, class: 'Champs::DateChamp' do factory :champ_do_not_use_date, class: 'Champs::DateChamp' do
type_de_champ { association :type_de_champ_date, procedure: dossier.procedure }
value { '2019-07-10' } value { '2019-07-10' }
end end
factory :champ_datetime, class: 'Champs::DatetimeChamp' do factory :champ_do_not_use_datetime, class: 'Champs::DatetimeChamp' do
type_de_champ { association :type_de_champ_datetime, procedure: dossier.procedure }
value { '15/09/1962 15:35' } value { '15/09/1962 15:35' }
end end
factory :champ_number, class: 'Champs::NumberChamp' do factory :champ_do_not_use_number, class: 'Champs::NumberChamp' do
type_de_champ { association :type_de_champ_number, procedure: dossier.procedure }
value { '42' } value { '42' }
end end
factory :champ_decimal_number, class: 'Champs::DecimalNumberChamp' do factory :champ_do_not_use_decimal_number, class: 'Champs::DecimalNumberChamp' do
type_de_champ { association :type_de_champ_decimal_number, procedure: dossier.procedure }
value { '42.1' } value { '42.1' }
end end
factory :champ_integer_number, class: 'Champs::IntegerNumberChamp' do factory :champ_do_not_use_integer_number, class: 'Champs::IntegerNumberChamp' do
type_de_champ { association :type_de_champ_integer_number, procedure: dossier.procedure }
value { '42' } value { '42' }
end end
factory :champ_checkbox, class: 'Champs::CheckboxChamp' do factory :champ_do_not_use_checkbox, class: 'Champs::CheckboxChamp' do
type_de_champ { association :type_de_champ_checkbox, procedure: dossier.procedure }
value { 'true' } value { 'true' }
end end
factory :champ_civilite, class: 'Champs::CiviliteChamp' do factory :champ_do_not_use_civilite, class: 'Champs::CiviliteChamp' do
type_de_champ { association :type_de_champ_civilite, procedure: dossier.procedure }
value { 'M.' } value { 'M.' }
end end
factory :champ_email, class: 'Champs::EmailChamp' do factory :champ_do_not_use_email, class: 'Champs::EmailChamp' do
type_de_champ { association :type_de_champ_email, procedure: dossier.procedure }
value { 'yoda@beta.gouv.fr' } value { 'yoda@beta.gouv.fr' }
end end
factory :champ_phone, class: 'Champs::PhoneChamp' do factory :champ_do_not_use_phone, class: 'Champs::PhoneChamp' do
type_de_champ { association :type_de_champ_phone, procedure: dossier.procedure }
value { '0666666666' } value { '0666666666' }
end end
factory :champ_address, class: 'Champs::AddressChamp' do factory :champ_do_not_use_address, class: 'Champs::AddressChamp' do
type_de_champ { association :type_de_champ_address, procedure: dossier.procedure }
value { '2 rue des Démarches' } value { '2 rue des Démarches' }
end end
factory :champ_yes_no, class: 'Champs::YesNoChamp' do factory :champ_do_not_use_yes_no, class: 'Champs::YesNoChamp' do
type_de_champ { association :type_de_champ_yes_no, procedure: dossier.procedure }
value { 'true' } value { 'true' }
end end
factory :champ_drop_down_list, class: 'Champs::DropDownListChamp' do factory :champ_do_not_use_drop_down_list, class: 'Champs::DropDownListChamp' do
transient do transient do
other { false } other { false }
end end
type_de_champ { association :type_de_champ_drop_down_list, procedure: dossier.procedure, drop_down_other: other }
value { 'val1' } value { 'val1' }
end end
factory :champ_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do factory :champ_do_not_use_multiple_drop_down_list, class: 'Champs::MultipleDropDownListChamp' do
type_de_champ { association :type_de_champ_multiple_drop_down_list, procedure: dossier.procedure }
value { '["val1", "val2"]' } value { '["val1", "val2"]' }
end end
factory :champ_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do factory :champ_do_not_use_linked_drop_down_list, class: 'Champs::LinkedDropDownListChamp' do
type_de_champ { association :type_de_champ_linked_drop_down_list, procedure: dossier.procedure }
value { '["categorie 1", "choix 1"]' } value { '["categorie 1", "choix 1"]' }
end end
factory :champ_pays, class: 'Champs::PaysChamp' do factory :champ_do_not_use_pays, class: 'Champs::PaysChamp' do
type_de_champ { association :type_de_champ_pays, procedure: dossier.procedure }
value { 'France' } value { 'France' }
end end
factory :champ_regions, class: 'Champs::RegionChamp' do factory :champ_do_not_use_regions, class: 'Champs::RegionChamp' do
type_de_champ { association :type_de_champ_regions, procedure: dossier.procedure }
value { 'Guadeloupe' } value { 'Guadeloupe' }
end end
factory :champ_departements, class: 'Champs::DepartementChamp' do factory :champ_do_not_use_departements, class: 'Champs::DepartementChamp' do
type_de_champ { association :type_de_champ_departements, procedure: dossier.procedure }
value { '01' } value { '01' }
end end
factory :champ_communes, class: 'Champs::CommuneChamp' do factory :champ_do_not_use_communes, class: 'Champs::CommuneChamp' do
type_de_champ { association :type_de_champ_communes, procedure: dossier.procedure }
external_id { '60172' } external_id { '60172' }
code_postal { '60580' } code_postal { '60580' }
end end
factory :champ_epci, class: 'Champs::EpciChamp' do factory :champ_do_not_use_epci, class: 'Champs::EpciChamp' do
type_de_champ { association :type_de_champ_epci, procedure: dossier.procedure }
value { 'CC Retz en Valois' } value { 'CC Retz en Valois' }
external_id { '200071991' } external_id { '200071991' }
end end
factory :champ_header_section, class: 'Champs::HeaderSectionChamp' do factory :champ_do_not_use_header_section, class: 'Champs::HeaderSectionChamp' do
type_de_champ { association :type_de_champ_header_section, procedure: dossier.procedure }
value { 'une section' }
end
factory :champ_header_section_level_1, class: 'Champs::HeaderSectionChamp' do
type_de_champ { association :type_de_champ_header_section_level_1, procedure: dossier.procedure }
value { 'une section' }
end
factory :champ_header_section_level_2, class: 'Champs::HeaderSectionChamp' do
type_de_champ { association :type_de_champ_header_section_level_2, procedure: dossier.procedure }
value { 'une section' }
end
factory :champ_header_section_level_3, class: 'Champs::HeaderSectionChamp' do
type_de_champ { association :type_de_champ_header_section_level_3, procedure: dossier.procedure }
value { 'une section' } value { 'une section' }
end end
factory :champ_explication, class: 'Champs::ExplicationChamp' do factory :champ_do_not_use_explication, class: 'Champs::ExplicationChamp' do
type_de_champ { association :type_de_champ_explication, procedure: dossier.procedure }
value { '' } value { '' }
end end
factory :champ_dossier_link, class: 'Champs::DossierLinkChamp' do factory :champ_do_not_use_dossier_link, class: 'Champs::DossierLinkChamp' do
type_de_champ { association :type_de_champ_dossier_link, procedure: dossier.procedure } value { create(:dossier, :en_construction).id }
value { create(:dossier).id }
end end
factory :champ_without_piece_justificative, class: 'Champs::PieceJustificativeChamp' do
type_de_champ { association :type_de_champ_piece_justificative, procedure: dossier.procedure }
end
factory :champ_piece_justificative, class: 'Champs::PieceJustificativeChamp' do
type_de_champ { association :type_de_champ_piece_justificative, procedure: dossier.procedure }
factory :champ_do_not_use_piece_justificative, class: 'Champs::PieceJustificativeChamp' do
transient do transient do
size { 4 } size { 4 }
end end
@ -184,8 +120,7 @@ FactoryBot.define do
end end
end end
factory :champ_titre_identite, class: 'Champs::TitreIdentiteChamp' do factory :champ_do_not_use_titre_identite, class: 'Champs::TitreIdentiteChamp' do
type_de_champ { association :type_de_champ_titre_identite, procedure: dossier.procedure }
transient do transient do
skip_default_attachment { false } skip_default_attachment { false }
end end
@ -203,109 +138,67 @@ FactoryBot.define do
end end
end end
factory :champ_carte, class: 'Champs::CarteChamp' do factory :champ_do_not_use_carte, class: 'Champs::CarteChamp' do
type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure } geo_areas { build_list(:geo_area, 2) }
end end
factory :champ_iban, class: 'Champs::IbanChamp' do factory :champ_do_not_use_iban, class: 'Champs::IbanChamp' do
type_de_champ { association :type_de_champ_iban, procedure: dossier.procedure }
end end
factory :champ_annuaire_education, class: 'Champs::AnnuaireEducationChamp' do factory :champ_do_not_use_annuaire_education, class: 'Champs::AnnuaireEducationChamp' do
type_de_champ { association :type_de_champ_annuaire_education, procedure: dossier.procedure }
end end
factory :champ_cnaf, class: 'Champs::CnafChamp' do factory :champ_do_not_use_cnaf, class: 'Champs::CnafChamp' do
type_de_champ { association :type_de_champ_cnaf, procedure: dossier.procedure }
end end
factory :champ_dgfip, class: 'Champs::DgfipChamp' do factory :champ_do_not_use_dgfip, class: 'Champs::DgfipChamp' do
type_de_champ { association :type_de_champ_dgfip, procedure: dossier.procedure }
end end
factory :champ_pole_emploi, class: 'Champs::PoleEmploiChamp' do factory :champ_do_not_use_pole_emploi, class: 'Champs::PoleEmploiChamp' do
type_de_champ { association :type_de_champ_pole_emploi, procedure: dossier.procedure }
end end
factory :champ_mesri, class: 'Champs::MesriChamp' do factory :champ_do_not_use_mesri, class: 'Champs::MesriChamp' do
type_de_champ { association :type_de_champ_mesri, procedure: dossier.procedure }
end end
factory :champ_siret, class: 'Champs::SiretChamp' do factory :champ_do_not_use_siret, class: 'Champs::SiretChamp' do
type_de_champ { association :type_de_champ_siret, procedure: dossier.procedure }
association :etablissement, factory: [:etablissement] association :etablissement, factory: [:etablissement]
value { '44011762001530' } value { '44011762001530' }
end end
factory :champ_rna, class: 'Champs::RNAChamp' do factory :champ_do_not_use_rna, class: 'Champs::RNAChamp' do
type_de_champ { association :type_de_champ_rna, procedure: dossier.procedure }
association :etablissement, factory: [:etablissement]
value { 'W173847273' } value { 'W173847273' }
end end
factory :champ_engagement_juridique, class: 'Champs::EngagementJuridiqueChamp' do factory :champ_do_not_use_engagement_juridique, class: 'Champs::EngagementJuridiqueChamp' do
type_de_champ { association :type_de_champ_engagement_juridique, procedure: dossier.procedure }
end end
factory :champ_cojo, class: 'Champs::COJOChamp' do factory :champ_do_not_use_cojo, class: 'Champs::COJOChamp' do
type_de_champ { association :type_de_champ_cojo, procedure: dossier.procedure }
end end
factory :champ_rnf, class: 'Champs::RNFChamp' do factory :champ_do_not_use_rnf, class: 'Champs::RNFChamp' do
type_de_champ { association :type_de_champ_rnf, procedure: dossier.procedure }
end end
factory :champ_expression_reguliere, class: 'Champs::ExpressionReguliereChamp' do factory :champ_do_not_use_expression_reguliere, class: 'Champs::ExpressionReguliereChamp' do
type_de_champ { association :type_de_champ_expression_reguliere, procedure: dossier.procedure }
end end
factory :champ_repetition, class: 'Champs::RepetitionChamp' do factory :champ_do_not_use_repetition, class: 'Champs::RepetitionChamp' do
type_de_champ { association :type_de_champ_repetition, procedure: dossier.procedure }
transient do transient do
rows { 2 } rows { 2 }
end end
after(:build) do |champ_repetition, evaluator| after(:build) do |champ_repetition, evaluator|
revision = champ_repetition.type_de_champ.procedure&.active_revision || build(:procedure_revision) revision = champ_repetition.type_de_champ.procedure.active_revision
parent = revision.revision_types_de_champ.find { |rtdc| rtdc.type_de_champ == champ_repetition.type_de_champ } parent = revision.revision_types_de_champ.find { _1.type_de_champ == champ_repetition.type_de_champ }
types_de_champ = revision.revision_types_de_champ.filter { |rtdc| rtdc.parent == parent }.map(&:type_de_champ) types_de_champ = revision.revision_types_de_champ.filter { _1.parent == parent }.map(&:type_de_champ)
evaluator.rows.times do evaluator.rows.times do
row_id = ULID.generate row_id = ULID.generate
champ_repetition.champs << types_de_champ.map do |type_de_champ| champ_repetition.champs << types_de_champ.map do |type_de_champ|
build(:"champ_#{type_de_champ.type_champ}", dossier: champ_repetition.dossier, row_id:, type_de_champ: type_de_champ, parent: champ_repetition, private: champ_repetition.private?) attrs = { dossier: champ_repetition.dossier, parent: champ_repetition, private: champ_repetition.private?, stable_id: type_de_champ.stable_id, row_id: }
build(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs)
end end
end end
end 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 { association :type_de_champ_repetition, procedure: dossier.procedure }
after(:build) do |champ_repetition, _evaluator|
type_de_champ_pj0 = build(:type_de_champ_piece_justificative,
position: 0,
parent: champ_repetition.type_de_champ,
libelle: 'Justificatif de domicile')
type_de_champ_pj1 = build(:type_de_champ_piece_justificative,
position: 1,
parent: champ_repetition.type_de_champ,
libelle: 'Carte d\'identité')
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 end
end end

View file

@ -119,37 +119,6 @@ FactoryBot.define do
hidden_by_reason { DeletedDossier.reasons.fetch(:instructeur_request) } hidden_by_reason { DeletedDossier.reasons.fetch(:instructeur_request) }
end end
trait :with_dossier_link do
after(:create) do |dossier, _evaluator|
# create linked dossier
linked_dossier = create(:dossier, :en_construction)
# find first type de champ dossier_link
type_de_champ = dossier.types_de_champ.find do |t|
t.type_champ == TypeDeChamp.type_champs.fetch(:dossier_link)
end
# if type de champ does not exist create it
if !type_de_champ
type_de_champ = create(:type_de_champ_dossier_link, procedure: dossier.procedure)
end
# find champ with the type de champ
champ = dossier.reload.champs_public.find do |c|
c.type_de_champ == type_de_champ
end
# if champ does not exist create it
if !champ
champ = create(:champ_dossier_link, dossier: dossier, type_de_champ: type_de_champ)
end
# set champ value with linked dossier
champ.value = linked_dossier.id
champ.save!
end
end
trait :with_commentaires do trait :with_commentaires do
commentaires { [build(:commentaire), build(:commentaire)] } commentaires { [build(:commentaire), build(:commentaire)] }
end end
@ -285,13 +254,13 @@ FactoryBot.define do
after(:create) do |dossier, _evaluator| after(:create) do |dossier, _evaluator|
dossier.champs_to_destroy.where(private: false).destroy_all dossier.champs_to_destroy.where(private: false).destroy_all
dossier.types_de_champ.each do |type_de_champ| dossier.types_de_champ.each do |type_de_champ|
if type_de_champ.simple_drop_down_list? value = if type_de_champ.simple_drop_down_list?
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first) type_de_champ.drop_down_list_enabled_non_empty_options.first
elsif type_de_champ.multiple_drop_down_list? elsif type_de_champ.multiple_drop_down_list?
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json) type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json
else
create(:"champ_#{type_de_champ.type_champ}", dossier:, type_de_champ:)
end end
attrs = { stable_id: type_de_champ.stable_id, dossier:, value: }.compact
create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs)
end end
dossier.reload dossier.reload
end end
@ -301,13 +270,13 @@ FactoryBot.define do
after(:create) do |dossier, _evaluator| after(:create) do |dossier, _evaluator|
dossier.champs_to_destroy.where(private: true).destroy_all dossier.champs_to_destroy.where(private: true).destroy_all
dossier.types_de_champ_private.each do |type_de_champ| dossier.types_de_champ_private.each do |type_de_champ|
if type_de_champ.simple_drop_down_list? value = if type_de_champ.simple_drop_down_list?
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first) type_de_champ.drop_down_list_enabled_non_empty_options.first
elsif type_de_champ.multiple_drop_down_list? elsif type_de_champ.multiple_drop_down_list?
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:, value: type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json) type_de_champ.drop_down_list_enabled_non_empty_options.first(2).to_json
else
create(:"champ_#{type_de_champ.type_champ}", private: true, dossier:, type_de_champ:)
end end
attrs = { stable_id: type_de_champ.stable_id, dossier:, private: true, value: }.compact
create(:"champ_do_not_use_#{type_de_champ.type_champ}", **attrs)
end end
dossier.reload dossier.reload
end end

View file

@ -1,6 +1,5 @@
FactoryBot.define do FactoryBot.define do
factory :geo_area do factory :geo_area do
association :champ
properties { {} } properties { {} }
geometry { {} } geometry { {} }

View file

@ -1,7 +1,9 @@
RSpec.describe GalleryHelper, type: :helper do RSpec.describe GalleryHelper, type: :helper do
let(:procedure) { create(:procedure_with_dossiers) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } let(:types_de_champ_public) { [{ type: :piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile' }] }
let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ_pj) { dossier.champs.first }
let(:blob_info) do let(:blob_info) do
{ {
filename: file.original_filename, filename: file.original_filename,

View file

@ -3,7 +3,11 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe ChampFetchExternalDataJob, type: :job do RSpec.describe ChampFetchExternalDataJob, type: :job do
let(:champ) { build(:champ, external_id: champ_external_id, data:) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :communes }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
let(:external_id) { "an ID" } let(:external_id) { "an ID" }
let(:champ_external_id) { "an ID" } let(:champ_external_id) { "an ID" }
let(:data) { nil } let(:data) { nil }
@ -15,6 +19,7 @@ RSpec.describe ChampFetchExternalDataJob, type: :job do
include Dry::Monads[:result] include Dry::Monads[:result]
before do before do
champ.update_columns(external_id: champ_external_id, data:)
allow(champ).to receive(:fetch_external_data).and_return(fetched_data) allow(champ).to receive(:fetch_external_data).and_return(fetched_data)
allow(champ).to receive(:update_with_external_data!) allow(champ).to receive(:update_with_external_data!)
allow(champ).to receive(:log_fetch_external_data_exception) allow(champ).to receive(:log_fetch_external_data_exception)

View file

@ -15,9 +15,14 @@ RSpec.describe Cron::BackfillSiretDegradedModeJob, type: :job do
end end
context 'fix etablisEtablissementAdapter.newsement with champs with adresse nil' do context 'fix etablisEtablissementAdapter.newsement with champs with adresse nil' do
let(:champ_siret) { create(:champ_siret, etablissement: etablissement) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :siret }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ_siret) { dossier.champs.first }
before do before do
champ_siret champ_siret
champ_siret.update_column(:etablissement_id, etablissement.id)
end end
it 'works' do it 'works' do
allow_any_instance_of(APIEntreprise::EtablissementAdapter).to receive(:to_params).and_return({ adresse: new_adresse }) allow_any_instance_of(APIEntreprise::EtablissementAdapter).to receive(:to_params).and_return({ adresse: new_adresse })

View file

@ -1,11 +1,15 @@
RSpec.describe DossierIndexSearchTermsJob, type: :job do RSpec.describe DossierIndexSearchTermsJob, type: :job do
let(:dossier) { create(:dossier) } let(:procedure) { create(:procedure, :published, types_de_champ_public:, types_de_champ_private:) }
let(:types_de_champ_public) { [{ type: :text }] }
let(:types_de_champ_private) { [{ type: :text }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ_siret) { dossier.champs.first }
subject(:perform_job) { described_class.perform_now(dossier.reload) } subject(:perform_job) { described_class.perform_now(dossier.reload) }
before do before do
create(:champ_text, dossier:, value: "un nouveau champ") dossier.champs_public.first.update_column(:value, "un nouveau champ")
create(:champ_text, dossier:, value: "private champ", private: true) dossier.champs_private.first.update_column(:value, "private champ")
end end
it "update search terms columns" do it "update search terms columns" do

View file

@ -1,11 +1,17 @@
describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do
let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :datetime, mandatory: }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:datetime_champ) { dossier.champs.first }
let(:mandatory) { true }
before do before do
datetime_champ.update_column(:value, value)
datetime_champ.save(validate: false) datetime_champ.save(validate: false)
end end
context "when the value is a valid ISO8601 date" do context "when the value is a valid ISO8601 date" do
let!(:value) { Time.zone.parse('10/01/2023 13:30').iso8601 } let!(:value) { Time.zone.parse('10/01/2023 13:30').iso8601 }
let!(:datetime_champ) { build(:champ_datetime, value: value) }
subject { described_class.perform_now([datetime_champ.id]) } subject { described_class.perform_now([datetime_champ.id]) }
@ -17,7 +23,6 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do
context "when the value is a date convertible to IS8061" do context "when the value is a date convertible to IS8061" do
let!(:value) { "2023-01-10" } let!(:value) { "2023-01-10" }
let!(:datetime_champ) { build(:champ_datetime, value: value) }
subject { described_class.perform_now([datetime_champ.id]) } subject { described_class.perform_now([datetime_champ.id]) }
@ -28,11 +33,8 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do
end end
context "when the value is a date not convertible to IS8061" do context "when the value is a date not convertible to IS8061" do
before do let!(:value) { "blabla" }
datetime_champ.type_de_champ.update!(mandatory: false) let!(:mandatory) { false }
end
let!(:datetime_champ) { build(:champ_datetime, value: "blabla") }
subject { described_class.perform_now([datetime_champ.id]) } subject { described_class.perform_now([datetime_champ.id]) }
@ -43,7 +45,7 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do
end end
context "when the value is a date not convertible to IS8061 and the champ is required" do context "when the value is a date not convertible to IS8061 and the champ is required" do
let!(:datetime_champ) { build(:champ_datetime, value: "blabla") } let!(:value) { "blabla" }
subject { described_class.perform_now([datetime_champ.id]) } subject { described_class.perform_now([datetime_champ.id]) }
@ -57,7 +59,7 @@ describe Migrations::BatchUpdateDatetimeValuesJob, type: :job do
end end
context "when the value is nil" do context "when the value is nil" do
let!(:datetime_champ) { build(:champ_datetime, value: nil) } let!(:value) { nil }
subject { described_class.perform_now([datetime_champ.id]) } subject { described_class.perform_now([datetime_champ.id]) }

View file

@ -1,8 +1,14 @@
describe Migrations::BatchUpdatePaysValuesJob, type: :job do describe Migrations::BatchUpdatePaysValuesJob, type: :job do
let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :pays, mandatory: }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:pays_champ) { dossier.champs.first }
let(:mandatory) { true }
before { pays_champ.update_columns(attributes) }
subject { described_class.perform_now([pays_champ.id]) } subject { described_class.perform_now([pays_champ.id]) }
context "the value is correct" do context "the value is correct" do
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'France', external_id: 'FR') } } let(:attributes) { { value: 'France', external_id: 'FR' } }
it 'does not change it' do it 'does not change it' do
subject subject
@ -12,11 +18,8 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
end end
context "the value is incorrect" do context "the value is incorrect" do
before do let(:attributes) { { value: 'Incorrect' } }
pays_champ.type_de_champ.update!(mandatory: false) let(:mandatory) { false }
end
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Incorrect') } }
it 'updates value to nil' do it 'updates value to nil' do
subject subject
@ -26,7 +29,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
end end
context "the value is easily cleanable" do context "the value is easily cleanable" do
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'Vietnam') } } let(:attributes) { { value: 'Vietnam' } }
it 'cleans the value' do it 'cleans the value' do
subject subject
@ -36,7 +39,7 @@ describe Migrations::BatchUpdatePaysValuesJob, type: :job do
end end
context "the value is hard to clean" do context "the value is hard to clean" do
let(:pays_champ) { create(:champ_pays).tap { _1.update_columns(value: 'CHRISTMAS (ILE)') } } let(:attributes) { { value: 'CHRISTMAS (ILE)' } }
it 'cleans the value' do it 'cleans the value' do
subject subject

View file

@ -1,6 +1,10 @@
describe Migrations::NormalizeCommunesJob, type: :job do describe Migrations::NormalizeCommunesJob, type: :job do
context 'when value is "", external_id is "", and code_departement is "undefined"' do context 'when value is "", external_id is "", and code_departement is "undefined"' do
let(:champ) { create(:champ_communes) } let(:procedure) { create(:procedure, :published, types_de_champ_public:) }
let(:types_de_champ_public) { [{ type: :communes }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
before { champ.update_columns(external_id: "", value: "", value_json: { code_departement: 'undefined', departement: 'undefined' }) } before { champ.update_columns(external_id: "", value: "", value_json: { code_departement: 'undefined', departement: 'undefined' }) }
subject { described_class.perform_now([champ.id]) } subject { described_class.perform_now([champ.id]) }
it 'empty the champs' do it 'empty the champs' do

View file

@ -1,68 +0,0 @@
describe Recovery::AlignChampWithDossierRevision do
let(:procedure) { create(:procedure, types_de_champ_public: [{ stable_id: bad_stable_id }, {}]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:bad_dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:bad_stable_id) { 999 }
let(:bad_champ) { bad_dossier.champs.find { bad_stable_id == _1.stable_id } }
context 'when type_de_champ exists in dossier revision' do
before do
procedure.publish!
procedure.draft_revision
.find_and_ensure_exclusive_use(bad_stable_id)
.update(libelle: "New libelle")
previous_revision = procedure.published_revision
previous_type_de_champ = previous_revision.types_de_champ.find { bad_stable_id == _1.stable_id }
procedure.publish_revision!
procedure.reload
bad_dossier
bad_champ.update(type_de_champ: previous_type_de_champ)
end
it 'bad dossier shoud be bad' do
expect(procedure.revisions.size).to eq(3)
expect(bad_dossier.revision).to eq(procedure.published_revision)
expect(bad_dossier.champs.size).to eq(2)
expect(bad_dossier.champs_public.size).to eq(2)
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
fixer.run
expect(fixer.logs.size).to eq(1)
expect(fixer.logs.first.fetch(:status)).to eq(:updated)
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
expect(bad_dossier.champs.size).to eq(2)
expect(bad_dossier.champs_public.size).to eq(2)
end
end
context 'when type_de_champ does not exist in dossier revision' do
before do
procedure.publish!
bad_dossier
procedure.draft_revision.remove_type_de_champ(bad_stable_id)
procedure.publish_revision!
bad_dossier.update(revision: procedure.published_revision)
end
it 'bad dossier shoud be bad' do
expect(procedure.revisions.size).to eq(3)
expect(bad_dossier.revision).to eq(procedure.published_revision)
expect(bad_dossier.champs.size).to eq(2)
expect(bad_dossier.champs_public.size).to eq(2)
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
fixer.run(destroy_extra_champs: true)
expect(fixer.logs.size).to eq(1)
expect(fixer.logs.first.fetch(:status)).to eq(:not_found)
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error
expect(bad_dossier.champs.size).to eq(1)
expect(bad_dossier.champs_public.size).to eq(1)
end
end
end

View file

@ -1,7 +1,7 @@
describe Champ do describe Champ do
describe '#private?' do describe '#private?' do
let(:type_de_champ) { build(:type_de_champ, :private) } let(:type_de_champ) { build(:type_de_champ, :private) }
let(:champ) { type_de_champ.champ.build } let(:champ) { type_de_champ.build_champ }
it { expect(champ.private?).to be_truthy } it { expect(champ.private?).to be_truthy }
it { expect(champ.public?).to be_falsey } it { expect(champ.public?).to be_falsey }

View file

@ -1,56 +0,0 @@
shared_examples 'champ_spec' do
describe 'mandatory_blank?' do
let(:type_de_champ) { build(:type_de_champ, mandatory: mandatory) }
let(:champ) { build(:champ, type_de_champ: type_de_champ, value: value) }
let(:value) { '' }
let(:mandatory) { true }
context 'when mandatory and blank' do
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when carte mandatory and blank' do
let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) }
let(:champ) { build(:champ_carte, type_de_champ: type_de_champ, value: value) }
let(:value) { nil }
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when multiple_drop_down_list mandatory and blank' do
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) }
let(:champ) { build(:champ_multiple_drop_down_list, type_de_champ: type_de_champ, value: value) }
let(:value) { '[]' }
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when repetition blank' do
let(:type_de_champ) { build(:type_de_champ_repetition) }
let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ, rows: 0) }
it { expect(champ.blank?).to be(true) }
end
context 'when repetition not blank' do
let(:type_de_champ) { build(:type_de_champ_repetition, :with_types_de_champ, procedure: build(:procedure)) }
let(:champ) { build(:champ_repetition, type_de_champ: type_de_champ) }
it { expect(champ.blank?).to be(false) }
end
context 'when not blank' do
let(:value) { 'yop' }
it { expect(champ.mandatory_blank?).to be(false) }
end
context 'when not mandatory' do
let(:mandatory) { false }
it { expect(champ.mandatory_blank?).to be(false) }
end
context 'when not mandatory or blank' do
let(:value) { 'u' }
let(:mandatory) { false }
it { expect(champ.mandatory_blank?).to be(false) }
end
end
end

View file

@ -1,9 +1,62 @@
describe Champ do describe Champ do
include ActiveJob::TestHelper include ActiveJob::TestHelper
require 'models/champ_shared_example.rb' describe 'mandatory_blank?' do
let(:type_de_champ) { build(:type_de_champ, mandatory: mandatory) }
let(:champ) { Champ.new(value: value) }
let(:value) { '' }
let(:mandatory) { true }
before { allow(champ).to receive(:type_de_champ).and_return(type_de_champ) }
it_should_behave_like "champ_spec" context 'when mandatory and blank' do
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when carte mandatory and blank' do
let(:type_de_champ) { build(:type_de_champ_carte, mandatory: mandatory) }
let(:champ) { Champs::CarteChamp.new(value: value) }
let(:value) { nil }
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when multiple_drop_down_list mandatory and blank' do
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, mandatory: mandatory) }
let(:champ) { Champs::MultipleDropDownListChamp.new(value: value) }
let(:value) { '[]' }
it { expect(champ.mandatory_blank?).to be(true) }
end
context 'when repetition blank' do
let(:type_de_champ) { build(:type_de_champ_repetition) }
let(:champ) { Champs::RepetitionChamp.new }
it { expect(champ.blank?).to be(true) }
end
context 'when repetition not blank' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :repetition, children: [{ type: :text }] }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.find(&:repetition?) }
it { expect(champ.blank?).to be(false) }
end
context 'when not blank' do
let(:value) { 'yop' }
it { expect(champ.mandatory_blank?).to be(false) }
end
context 'when not mandatory' do
let(:mandatory) { false }
it { expect(champ.mandatory_blank?).to be(false) }
end
context 'when not mandatory or blank' do
let(:value) { 'u' }
let(:mandatory) { false }
it { expect(champ.mandatory_blank?).to be(false) }
end
end
describe "associations" do describe "associations" do
it { is_expected.to belong_to(:dossier) } it { is_expected.to belong_to(:dossier) }
@ -18,14 +71,14 @@ describe Champ do
describe "normalization" do describe "normalization" do
it "should remove null bytes before save" do it "should remove null bytes before save" do
champ = create(:champ, value: "foo\u0000bar") champ = Champ.new(value: "foo\u0000bar")
champ.normalize
expect(champ.value).to eq "foobar" expect(champ.value).to eq "foobar"
end end
end end
describe '#public?' do describe '#public?' do
let(:type_de_champ) { build(:type_de_champ) } let(:champ) { Champ.new }
let(:champ) { type_de_champ.champ.build }
it { expect(champ.public?).to be_truthy } it { expect(champ.public?).to be_truthy }
it { expect(champ.private?).to be_falsey } it { expect(champ.private?).to be_falsey }
@ -87,10 +140,8 @@ describe Champ do
end end
describe '#format_datetime' do describe '#format_datetime' do
let(:champ) { build(:champ_datetime, value: value) } let(:champ) { Champs::DatetimeChamp.new(value: value) }
before { champ.run_callbacks(:validation) }
before { champ.save! }
context 'when the value is sent by a modern browser' do context 'when the value is sent by a modern browser' do
let(:value) { '2017-12-31 10:23' } let(:value) { '2017-12-31 10:23' }
@ -105,9 +156,8 @@ describe Champ do
end end
describe '#multiple_select_to_string' do describe '#multiple_select_to_string' do
let(:champ) { build(:champ_multiple_drop_down_list, value: value) } let(:champ) { Champs::MultipleDropDownListChamp.new(value: value) }
# before { champ.save! }
before { champ.save! }
# when using the old form, and the ChampsService Class # when using the old form, and the ChampsService Class
# TODO: to remove # TODO: to remove
@ -142,7 +192,8 @@ describe Champ do
end end
describe 'for_export' do describe 'for_export' do
let(:champ) { create(:champ_text, value: value) } let(:champ) { Champs::TextChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) }
context 'when type_de_champ is text' do context 'when type_de_champ is text' do
let(:value) { '123' } let(:value) { '123' }
@ -151,14 +202,17 @@ describe Champ do
end end
context 'when type_de_champ is textarea' do context 'when type_de_champ is textarea' do
let(:champ) { create(:champ_textarea, value: value) } let(:champ) { Champs::TextareaChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_textarea)) }
let(:value) { '<b>gras<b>' } let(:value) { '<b>gras<b>' }
it { expect(champ.for_export).to eq('gras') } it { expect(champ.for_export).to eq('gras') }
end end
context 'when type_de_champ is yes_no' do context 'when type_de_champ is yes_no' do
let(:champ) { create(:champ_yes_no, value: value) } let(:champ) { Champs::YesNoChamp.new(value: value) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) }
context 'if yes' do context 'if yes' do
let(:value) { 'true' } let(:value) { 'true' }
@ -180,18 +234,21 @@ describe Champ do
end end
context 'when type_de_champ is multiple_drop_down_list' do context 'when type_de_champ is multiple_drop_down_list' do
let(:champ) { create(:champ_multiple_drop_down_list, value:) } let(:champ) { Champs::MultipleDropDownListChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_multiple_drop_down_list)) }
let(:value) { '["Crétinier", "Mousserie"]' } let(:value) { '["Crétinier", "Mousserie"]' }
it { expect(champ.for_export).to eq('Crétinier, Mousserie') } it { expect(champ.for_export).to eq('Crétinier, Mousserie') }
end end
context 'when type_de_champ and champ.type mismatch' do context 'when type_de_champ and champ.type mismatch' do
let(:champ_yes_no) { create(:champ_yes_no, value: 'true') } let(:value) { :noop }
let(:champ_text) { create(:champ_text, value: 'Hello') } let(:champ_yes_no) { Champs::YesNoChamp.new(value: 'true') }
let(:champ_text) { Champs::TextChamp.new(value: 'hello') }
it { expect(TypeDeChamp.champ_value_for_export(champ_text.type_champ, champ_yes_no)).to eq(nil) } it { expect(TypeDeChamp.champ_value_for_export('text', champ_yes_no)).to eq(nil) }
it { expect(TypeDeChamp.champ_value_for_export(champ_yes_no.type_champ, champ_text)).to eq('Non') } it { expect(TypeDeChamp.champ_value_for_export('yes_no', champ_text)).to eq('Non') }
end end
end end
@ -199,7 +256,7 @@ describe Champ do
subject { champ.search_terms } subject { champ.search_terms }
context 'for adresse champ' do context 'for adresse champ' do
let(:champ) { create(:champ_address, value:) } let(:champ) { Champs::AddressChamp.new(value:) }
let(:value) { "10 rue du Pinson qui Piaille" } let(:value) { "10 rue du Pinson qui Piaille" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
@ -207,8 +264,8 @@ describe Champ do
context 'for checkbox champ' do context 'for checkbox champ' do
let(:libelle) { champ.libelle } let(:libelle) { champ.libelle }
let(:champ) { create(:champ_checkbox, value:) } let(:champ) { Champs::CheckboxChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_checkbox)) }
context 'when the box is checked' do context 'when the box is checked' do
let(:value) { 'true' } let(:value) { 'true' }
@ -223,74 +280,79 @@ describe Champ do
end end
context 'for civilite champ' do context 'for civilite champ' do
let(:champ) { create(:champ_civilite, value:) } let(:champ) { Champs::CiviliteChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_civilite)) }
let(:value) { "M." } let(:value) { "M." }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for date champ' do context 'for date champ' do
let(:champ) { create(:champ_date, value:) } let(:champ) { Champs::DateChamp.new(value:) }
let(:value) { "2018-07-30" } let(:value) { "2018-07-30" }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'for date time champ' do context 'for date time champ' do
let(:champ) { create(:champ_datetime, value:) } let(:champ) { Champs::DatetimeChamp.new(value:) }
let(:value) { "2018-04-29 09:00" } let(:value) { "2018-04-29 09:00" }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'for département champ' do context 'for département champ' do
let(:champ) { create(:champ_departements, value:) } let(:champ) { Champs::DepartementChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) }
let(:value) { "69" } let(:value) { "69" }
it { is_expected.to eq(['69 Rhône']) } it { is_expected.to eq(['69 Rhône']) }
end end
context 'for dossier link champ' do context 'for dossier link champ' do
let(:champ) { create(:champ_dossier_link, value:) } let(:champ) { Champs::DossierLinkChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_dossier_link)) }
let(:value) { "9103132886" } let(:value) { "9103132886" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for drop down list champ' do context 'for drop down list champ' do
let(:champ) { create(:champ_dossier_link, value:) } let(:champ) { Champs::DropDownListChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list)) }
let(:value) { "HLM" } let(:value) { "HLM" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for email champ' do context 'for email champ' do
let(:champ) { build(:champ_email, value:) } let(:champ) { Champs::EmailChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_email)) }
let(:value) { "machin@example.com" } let(:value) { "machin@example.com" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for explication champ' do context 'for explication champ' do
let(:champ) { build(:champ_explication) } let(:champ) { Champs::ExplicationChamp.new }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'for header section champ' do context 'for header section champ' do
let(:champ) { build(:champ_header_section) } let(:champ) { Champs::HeaderSectionChamp.new }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'for linked drop down list champ' do context 'for linked drop down list champ' do
let(:champ) { create(:champ_linked_drop_down_list, primary_value: "hello", secondary_value: "world") } let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: "hello", secondary_value: "world") }
it { is_expected.to eq(["hello", "world"]) } it { is_expected.to eq(["hello", "world"]) }
end end
context 'for multiple drop down list champ' do context 'for multiple drop down list champ' do
let(:champ) { build(:champ_multiple_drop_down_list, value:) } let(:champ) { Champs::MultipleDropDownListChamp.new(value:) }
context 'when there are multiple values selected' do context 'when there are multiple values selected' do
let(:value) { JSON.generate(['goodbye', 'cruel', 'world']) } let(:value) { JSON.generate(['goodbye', 'cruel', 'world']) }
@ -306,35 +368,41 @@ describe Champ do
end end
context 'for number champ' do context 'for number champ' do
let(:champ) { build(:champ_number, value:) } let(:champ) { Champs::NumberChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_number)) }
let(:value) { "1234" } let(:value) { "1234" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for pays champ' do context 'for pays champ' do
let(:champ) { build(:champ_pays, value:) } let(:champ) { Champs::PaysChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_pays)) }
let(:value) { "FR" } let(:value) { "FR" }
it { is_expected.to eq(['France']) } it { is_expected.to eq(['France']) }
end end
context 'for phone champ' do context 'for phone champ' do
let(:champ) { build(:champ_phone, value:) } let(:champ) { Champs::PhoneChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_phone)) }
let(:value) { "06 06 06 06 06" } let(:value) { "06 06 06 06 06" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for pièce justificative champ' do context 'for pièce justificative champ' do
let(:champ) { build(:champ_piece_justificative, value:) } let(:champ) { Champs::PieceJustificativeChamp.new(value:) }
let(:value) { nil } let(:value) { nil }
it { is_expected.to be_nil } it { is_expected.to be_nil }
end end
context 'for region champ' do context 'for region champ' do
let(:champ) { build(:champ_regions, value:) } let(:champ) { Champs::RegionChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_regions)) }
let(:value) { "11" } let(:value) { "11" }
it { is_expected.to eq(['Île-de-France']) } it { is_expected.to eq(['Île-de-France']) }
@ -375,13 +443,13 @@ describe Champ do
association_date_publication: "1962-05-31" association_date_publication: "1962-05-31"
) )
end end
let(:champ) { create(:champ_siret, value: etablissement.siret, etablissement:) } let(:champ) { Champs::SiretChamp.new(value: etablissement.siret, etablissement:) }
it { is_expected.to eq([etablissement.entreprise_siren, etablissement.entreprise_numero_tva_intracommunautaire, etablissement.entreprise_forme_juridique, etablissement.entreprise_forme_juridique_code, etablissement.entreprise_nom_commercial, etablissement.entreprise_raison_sociale, etablissement.entreprise_siret_siege_social, etablissement.entreprise_nom, etablissement.entreprise_prenom, etablissement.association_rna, etablissement.association_titre, etablissement.association_objet, etablissement.siret, etablissement.enseigne, etablissement.naf, etablissement.libelle_naf, etablissement.adresse, etablissement.code_postal, etablissement.localite, etablissement.code_insee_localite]) } it { is_expected.to eq([etablissement.entreprise_siren, etablissement.entreprise_numero_tva_intracommunautaire, etablissement.entreprise_forme_juridique, etablissement.entreprise_forme_juridique_code, etablissement.entreprise_nom_commercial, etablissement.entreprise_raison_sociale, etablissement.entreprise_siret_siege_social, etablissement.entreprise_nom, etablissement.entreprise_prenom, etablissement.association_rna, etablissement.association_titre, etablissement.association_objet, etablissement.siret, etablissement.enseigne, etablissement.naf, etablissement.libelle_naf, etablissement.adresse, etablissement.code_postal, etablissement.localite, etablissement.code_insee_localite]) }
end end
context 'when there is no etablissement' do context 'when there is no etablissement' do
let(:champ) { create(:champ_siret, value:, etablissement: nil) } let(:champ) { Champs::SiretChamp.new(value:, etablissement: nil) }
let(:value) { "35130347400024" } let(:value) { "35130347400024" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
@ -389,21 +457,25 @@ describe Champ do
end end
context 'for text champ' do context 'for text champ' do
let(:champ) { build(:champ_text, value:) } let(:champ) { Champs::TextChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_text)) }
let(:value) { "Blah" } let(:value) { "Blah" }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for text area champ' do context 'for text area champ' do
let(:champ) { build(:champ_textarea, value:) } let(:champ) { Champs::TextareaChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_textarea)) }
let(:value) { "Bla\nBlah de bla." } let(:value) { "Bla\nBlah de bla." }
it { is_expected.to eq([value]) } it { is_expected.to eq([value]) }
end end
context 'for yes/no champ' do context 'for yes/no champ' do
let(:champ) { build(:champ_yes_no, value:) } let(:champ) { Champs::YesNoChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) }
let(:libelle) { champ.libelle } let(:libelle) { champ.libelle }
context 'when the box is checked' do context 'when the box is checked' do
@ -422,7 +494,9 @@ describe Champ do
describe '#enqueue_virus_scan' do describe '#enqueue_virus_scan' do
context 'when type_champ is type_de_champ_piece_justificative' do context 'when type_champ is type_de_champ_piece_justificative' do
let(:champ) { build(:champ_piece_justificative) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { dossier.champs.first }
context 'and there is a blob' do context 'and there is a blob' do
before do before do
@ -450,8 +524,9 @@ describe Champ do
describe '#enqueue_watermark_job' do describe '#enqueue_watermark_job' do
context 'when type_champ is type_de_champ_titre_identite' do context 'when type_champ is type_de_champ_titre_identite' do
let(:type_de_champ) { create(:type_de_champ_titre_identite) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :titre_identite }]) }
let(:champ) { build(:champ_titre_identite, type_de_champ: type_de_champ, skip_default_attachment: true) } let(:dossier) { create(:dossier, procedure:) }
let(:champ) { dossier.champs.first }
before do before do
allow(ClamavService).to receive(:safe_file?).and_return(true) allow(ClamavService).to receive(:safe_file?).and_return(true)
@ -476,40 +551,21 @@ describe Champ do
end end
end end
describe 'repetition' do
let(:procedure) { create(:procedure, :published, types_de_champ_private: [{}], types_de_champ_public: [{}, { type: :repetition, mandatory: true, children: [{}, { type: :integer_number }] }]) }
let(:tdc_repetition) { procedure.active_revision.types_de_champ_public.find(&:repetition?) }
let(:tdc_text) { procedure.active_revision.children_of(tdc_repetition).first }
let(:dossier) { create(:dossier, procedure: procedure) }
let(:champ) { dossier.champs_public.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_id: ULID.generate) }
context 'when creating the model directly' do
let(:champ_text_row_1) { create(:champ_text, type_de_champ: tdc_text, row_id: ULID.generate, 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
end
describe '#log_fetch_external_data_exception' do describe '#log_fetch_external_data_exception' do
let(:champ) { create(:champ_siret) } let(:champ) { Champs::SiretChamp.new }
context "add execption to the log" do context "add execption to the log" do
before do it do
champ.log_fetch_external_data_exception(StandardError.new('My special exception!')) expect(champ).to receive(:update_column).with(:fetch_external_data_exceptions, ['PAN'])
champ.log_fetch_external_data_exception(double(inspect: 'PAN'))
end end
it { expect(champ.fetch_external_data_exceptions).to eq(['#<StandardError: My special exception!>']) }
end end
end end
describe "fetch_external_data" do describe "fetch_external_data" do
let(:champ) { create(:champ_rnf, data: 'some data') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :rnf }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { dossier.champs.first.tap { _1.update_column(:data, 'some data') } }
context "cleanup_if_empty" do context "cleanup_if_empty" do
it "remove data if external_id changes" do it "remove data if external_id changes" do
@ -534,47 +590,50 @@ describe Champ do
end end
describe "#input_name" do describe "#input_name" do
let(:champ) { create(:champ_text) } let(:champ) { Champs::TextChamp.new }
it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" } it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" }
context "when private" do context "when private" do
let(:champ) { create(:champ_text, private: true) } let(:champ) { Champs::TextChamp.new(private: true) }
it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" }
end end
context "when has parent" do context "when has parent" do
let(:champ) { create(:champ_text, parent: create(:champ_text)) } let(:champ) { Champs::TextChamp.new(parent: Champs::TextChamp.new) }
it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" } it { expect(champ.input_name).to eq "dossier[champs_public_attributes][#{champ.public_id}]" }
end end
context "when has private parent" do context "when has private parent" do
let(:champ) { create(:champ_text, private: true, parent: create(:champ_text, private: true)) } let(:champ) { Champs::TextChamp.new(private: true, parent: Champs::TextChamp.new(private: true)) }
it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" } it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.public_id}]" }
end end
end end
describe '#update_with_external_data!' do
let(:champ) { create(:champ_siret) }
let(:data) { "data" }
subject { champ.update_with_external_data!(data: data) }
it { expect { subject }.to change { champ.reload.data }.to(data) }
end
describe 'dom_id' do describe 'dom_id' do
let(:champ) { build(:champ_text, row_id: '1234') } let(:champ) { Champs::TextChamp.new(row_id: '1234') }
before do
allow(champ).to receive(:type_de_champ).and_return(create(:type_de_champ_text))
end
it { expect(champ.public_id).to eq("#{champ.stable_id}-#{champ.row_id}") } it do
it { expect(ActionView::RecordIdentifier.dom_id(champ)).to eq("champ_#{champ.public_id}") } expect(champ.public_id).to eq("#{champ.stable_id}-#{champ.row_id}")
it { expect(ActionView::RecordIdentifier.dom_id(champ.type_de_champ)).to eq("type_de_champ_#{champ.type_de_champ.id}") } expect(ActionView::RecordIdentifier.dom_id(champ)).to eq("champ_#{champ.public_id}")
it { expect(ActionView::RecordIdentifier.dom_class(champ)).to eq("champ") } expect(ActionView::RecordIdentifier.dom_id(champ.type_de_champ)).to eq("type_de_champ_#{champ.type_de_champ.id}")
expect(ActionView::RecordIdentifier.dom_class(champ)).to eq("champ")
end
end end
describe 'clone' do describe 'clone' do
let(:procedure) { create(:procedure, types_de_champ_private:, types_de_champ_public:) }
let(:types_de_champ_private) { [] }
let(:types_de_champ_public) { [] }
let(:champ) { dossier.champs.first }
subject { champ.clone(fork) } subject { champ.clone(fork) }
context 'when champ public' do context 'when champ public' do
let(:champ) { create(:champ_piece_justificative, private: false) } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
context 'when fork' do context 'when fork' do
let(:fork) { true } let(:fork) { true }
@ -592,7 +651,8 @@ describe Champ do
end end
context 'champ private' do context 'champ private' do
let(:champ) { create(:champ_piece_justificative, private: true) } let(:dossier) { create(:dossier, :with_populated_annotations, procedure:) }
let(:types_de_champ_private) { [{ type: :piece_justificative }] }
context 'when fork' do context 'when fork' do
let(:fork) { true } let(:fork) { true }

View file

@ -1,5 +1,11 @@
describe Champs::AddressChamp do describe Champs::AddressChamp do
let(:champ) { build(:champ_address, value:, data:) } let(:champ) do
described_class.new.tap do |champ|
champ.value = value
champ.data = data
champ.validate
end
end
let(:value) { '' } let(:value) { '' }
let(:data) { nil } let(:data) { nil }

View file

@ -4,7 +4,9 @@ require 'rails_helper'
RSpec.describe Champs::AnnuaireEducationChamp do RSpec.describe Champs::AnnuaireEducationChamp do
describe '#update_with_external_data!' do describe '#update_with_external_data!' do
let(:champ) { create(:champ_annuaire_education, data: "any data") } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :annuaire_education }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first.tap { _1.update_column(:data, 'any data') } }
subject { champ.update_with_external_data!(data: data) } subject { champ.update_with_external_data!(data: data) }
shared_examples "a data updater (without updating the value)" do |data| shared_examples "a data updater (without updating the value)" do |data|

View file

@ -1,5 +1,6 @@
describe Champs::CarteChamp do describe Champs::CarteChamp do
let(:champ) { build(:champ_carte, geo_areas:) } let(:champ) { Champs::CarteChamp.new(geo_areas:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_carte)) }
let(:value) { '' } let(:value) { '' }
let(:coordinates) { [[[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.3859214782714844, 48.87442541960633]]] } let(:coordinates) { [[[2.3859214782714844, 48.87442541960633], [2.3850631713867183, 48.87273183590832], [2.3809432983398438, 48.87081237174292], [2.3859214782714844, 48.87442541960633]]] }
let(:geo_json) do let(:geo_json) do

View file

@ -1,12 +1,11 @@
describe Champs::CheckboxChamp do describe Champs::CheckboxChamp do
it_behaves_like "a boolean champ" do let(:boolean_champ) { described_class.new(value: value) }
let(:boolean_champ) { build(:champ_checkbox, value: value) } before { allow(boolean_champ).to receive(:type_de_champ).and_return(build(:type_de_champ_checkbox)) }
end it_behaves_like "a boolean champ"
# TODO remove when normalize_checkbox_values is over # TODO remove when normalize_checkbox_values is over
describe '#true?' do describe '#true?' do
let(:checkbox_champ) { build(:champ_checkbox, value: value) } subject { boolean_champ.true? }
subject { checkbox_champ.true? }
context "when the checkbox value is 'on'" do context "when the checkbox value is 'on'" do
let(:value) { 'on' } let(:value) { 'on' }

View file

@ -1,6 +1,6 @@
describe Champs::CnafChamp, type: :model do describe Champs::CnafChamp, type: :model do
let(:champ) { build(:champ_cnaf) } let(:champ) { described_class.new(dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_cnaf)) }
describe 'numero_allocataire and code_postal' do describe 'numero_allocataire and code_postal' do
before do before do
champ.numero_allocataire = '1234567' champ.numero_allocataire = '1234567'
@ -37,7 +37,7 @@ describe Champs::CnafChamp, type: :model do
describe '#validate' do describe '#validate' do
let(:numero_allocataire) { '1234567' } let(:numero_allocataire) { '1234567' }
let(:code_postal) { '12345' } let(:code_postal) { '12345' }
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_cnaf)) } let(:champ) { described_class.new(dossier: build(:dossier)) }
let(:validation_context) { :champs_public_value } let(:validation_context) { :champs_public_value }
subject { champ.valid?(validation_context) } subject { champ.valid?(validation_context) }

View file

@ -1,7 +1,5 @@
describe Champs::COJOChamp, type: :model do describe Champs::COJOChamp, type: :model do
let(:champ) { build(:champ_cojo, accreditation_number:, accreditation_birthdate:) }
let(:external_id) { nil } let(:external_id) { nil }
let(:stub) { stub_request(:post, url).with(body: { accreditationNumber: accreditation_number.to_i, birthdate: accreditation_birthdate }).to_return(body:, status:) }
let(:url) { COJOService.new.send(:url) } let(:url) { COJOService.new.send(:url) }
let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_cojo', "accreditation_#{response_type}.json").read } let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_cojo', "accreditation_#{response_type}.json").read }
let(:status) { 200 } let(:status) { 200 }
@ -9,8 +7,17 @@ describe Champs::COJOChamp, type: :model do
let(:accreditation_number) { '123456' } let(:accreditation_number) { '123456' }
let(:accreditation_birthdate) { '21/12/1959' } let(:accreditation_birthdate) { '21/12/1959' }
before { stub_request(:post, url).with(body: { accreditationNumber: accreditation_number.to_i, birthdate: accreditation_birthdate }).to_return(body:, status:) }
describe 'fetch_external_data' do describe 'fetch_external_data' do
subject { stub; champ.fetch_external_data } let(:champ) do
described_class.new do |champ|
champ.accreditation_number = accreditation_number
champ.accreditation_birthdate = accreditation_birthdate
end
end
subject { champ.fetch_external_data }
context 'success (yes)' do context 'success (yes)' do
it { expect(subject.value!).to eq({ accreditation_success: true, accreditation_first_name: 'Florence', accreditation_last_name: 'Griffith-Joyner' }) } it { expect(subject.value!).to eq({ accreditation_success: true, accreditation_first_name: 'Florence', accreditation_last_name: 'Griffith-Joyner' }) }
@ -49,9 +56,14 @@ describe Champs::COJOChamp, type: :model do
end end
describe 'fill champ' do describe 'fill champ' do
let(:champ) { create(:champ_cojo, accreditation_number:, accreditation_birthdate:) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :cojo }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
subject { stub; champ.touch; perform_enqueued_jobs; champ.reload } let(:champ) { dossier.champs.first }
before do
champ.update(accreditation_number:, accreditation_birthdate:, data: nil)
perform_enqueued_jobs;
end
subject { champ.reload }
it 'success (yes)' do it 'success (yes)' do
expect(subject.blank?).to be_falsey expect(subject.blank?).to be_falsey

View file

@ -1,8 +1,17 @@
describe Champs::CommuneChamp do describe Champs::CommuneChamp do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes, stable_id: 99 }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:code_insee) { '63102' } let(:code_insee) { '63102' }
let(:code_postal) { '63290' } let(:code_postal) { '63290' }
let(:code_departement) { '63' } let(:code_departement) { '63' }
let(:champ) { create(:champ_communes, code_postal:, external_id: code_insee) } let(:champ) do
described_class.new(stable_id: 99, dossier:).tap do |champ|
champ.code_postal = code_postal
champ.external_id = code_insee
champ.run_callbacks(:save)
end
end
describe 'value' do describe 'value' do
it 'find commune' do it 'find commune' do
@ -18,7 +27,12 @@ describe Champs::CommuneChamp do
end end
context 'with code' do context 'with code' do
let(:champ) { create(:champ_communes, code: '63102-63290') } let(:champ) do
described_class.new(stable_id: 99, dossier:).tap do |champ|
champ.code = '63102-63290'
champ.run_callbacks(:save)
end
end
it 'find commune' do it 'find commune' do
expect(champ.to_s).to eq('Châteldon (63290)') expect(champ.to_s).to eq('Châteldon (63290)')

View file

@ -1,47 +1,49 @@
describe Champs::DateChamp do describe Champs::DateChamp do
let(:date_champ) { create(:champ_date) } let(:type_de_champ) { create(:type_de_champ_date) }
let(:date_champ) { described_class.new }
before { allow(date_champ).to receive(:type_de_champ).and_return(type_de_champ) }
describe '#convert_to_iso8601' do describe '#convert_to_iso8601' do
it 'preserves nil' do it 'preserves nil' do
champ = champ_with_value(nil) champ = champ_with_value(nil)
champ.save champ.validate
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if empty string' do it 'converts to nil if empty string' do
champ = champ_with_value("") champ = champ_with_value("")
champ.save champ.validate
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if not ISO8601' do it 'converts to nil if not ISO8601' do
champ = champ_with_value("12-21-2023") champ = champ_with_value("12-21-2023")
champ.save champ.validate
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if not date' do it 'converts to nil if not date' do
champ = champ_with_value("value") champ = champ_with_value("value")
champ.save champ.validate
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it "converts %d/%m/%Y format to ISO" do it "converts %d/%m/%Y format to ISO" do
champ = champ_with_value("31/12/2017") champ = champ_with_value("31/12/2017")
champ.save champ.validate
expect(champ.reload.value).to eq("2017-12-31") expect(champ.value).to eq("2017-12-31")
end end
it 'preserves if ISO8601' do it 'preserves if ISO8601' do
champ = champ_with_value("2023-12-21") champ = champ_with_value("2023-12-21")
champ.save champ.validate
expect(champ.reload.value).to eq("2023-12-21") expect(champ.value).to eq("2023-12-21")
end end
it 'converts to nil if false iso' do it 'converts to nil if false iso' do
champ = champ_with_value("2023-27-02") champ = champ_with_value("2023-27-02")
champ.save champ.validate
expect(champ.reload.value).to eq(nil) expect(champ.value).to eq(nil)
end end
end end

View file

@ -1,47 +1,47 @@
describe Champs::DatetimeChamp do describe Champs::DatetimeChamp do
let(:datetime_champ) { build(:champ_datetime) } let(:datetime_champ) { described_class.new }
describe '#convert_to_iso8601' do describe '#convert_to_iso8601' do
it 'preserves nil' do it 'preserves nil' do
champ = champ_with_value(nil) champ = champ_with_value(nil)
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if empty string' do it 'converts to nil if empty string' do
champ = champ_with_value("") champ = champ_with_value("")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if not ISO8601' do it 'converts to nil if not ISO8601' do
champ = champ_with_value("12-21-2023 03:20") champ = champ_with_value("12-21-2023 03:20")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'converts to nil if not datetime' do it 'converts to nil if not datetime' do
champ = champ_with_value("value") champ = champ_with_value("value")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to be_nil expect(champ.value).to be_nil
end end
it 'preserves if ISO8601' do it 'preserves if ISO8601' do
champ = champ_with_value("2023-12-21T03:20") champ = champ_with_value("2023-12-21T03:20")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601)
end end
it 'converts to ISO8601 if form format' do it 'converts to ISO8601 if form format' do
champ = champ_with_value("{3=>21, 2=>12, 1=>2023, 4=>3, 5=>20}") champ = champ_with_value("{3=>21, 2=>12, 1=>2023, 4=>3, 5=>20}")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601)
end end
it 'converts to ISO8601 if old browser form format' do it 'converts to ISO8601 if old browser form format' do
champ = champ_with_value("21/12/2023 03:20") champ = champ_with_value("21/12/2023 03:20")
champ.save champ.run_callbacks(:validation)
expect(champ.reload.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601) expect(champ.value).to eq(Time.zone.parse("2023-12-21T03:20:00").iso8601)
end end
end end

View file

@ -1,8 +1,13 @@
describe Champs::DecimalNumberChamp do describe Champs::DecimalNumberChamp do
let(:champ) { build(:champ_decimal_number, value:) }
subject { champ.validate(:champs_public_value) }
describe 'validation' do describe 'validation' do
let(:champ) { Champs::DecimalNumberChamp.new(value:, dossier: build(:dossier)) }
before do
allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number))
allow(champ).to receive(:visible?).and_return(true)
champ.run_callbacks(:validation)
end
subject { champ.validate(:champs_public_value) }
context 'when the value is integer number' do context 'when the value is integer number' do
let(:value) { 2 } let(:value) { 2 }
@ -25,7 +30,7 @@ describe Champs::DecimalNumberChamp do
end end
context 'when value contain space' do context 'when value contain space' do
let(:champ) { create(:champ_decimal_number, :private, value:) } before { champ.run_callbacks(:validation) }
let(:value) { ' 2.6666 ' } let(:value) { ' 2.6666 ' }
it { expect(champ.value).to eq('2.6666') } it { expect(champ.value).to eq('2.6666') }
end end
@ -52,14 +57,15 @@ describe Champs::DecimalNumberChamp do
end end
context 'when the champ is private, value is invalid, but validation is public' do context 'when the champ is private, value is invalid, but validation is public' do
let(:champ) { build(:champ_decimal_number, :private, value:) } let(:champ) { Champs::DecimalNumberChamp.new(value:, private: true, dossier: build(:dossier)) }
let(:value) { '2.6666' } let(:value) { '2.6666' }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
end end
describe 'for_export' do describe 'for_export' do
let(:champ) { create(:champ_decimal_number, value:) } let(:champ) { Champs::DecimalNumberChamp.new(value:) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_decimal_number)) }
subject { champ.for_export } subject { champ.for_export }
context 'with nil' do context 'with nil' do
let(:value) { 0 } let(:value) { 0 }

View file

@ -1,7 +1,8 @@
describe Champs::DepartementChamp, type: :model do describe Champs::DepartementChamp, type: :model do
describe 'validations' do describe 'validations' do
describe 'external link' do describe 'external link' do
let(:champ) { build(:champ_departements, external_id: external_id) } let(:champ) { described_class.new(external_id: external_id, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
context 'when nil' do context 'when nil' do
@ -30,7 +31,9 @@ describe Champs::DepartementChamp, type: :model do
end end
describe 'value' do describe 'value' do
let(:champ) { create(:champ_departements) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :departements }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { dossier.champs.first }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
before { champ.update_columns(value: value) } before { champ.update_columns(value: value) }
@ -61,7 +64,8 @@ describe Champs::DepartementChamp, type: :model do
end end
describe 'value' do describe 'value' do
let(:champ) { build(:champ_departements, value: nil) } let(:champ) { described_class.new(value: nil, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_departements)) }
it 'with code having 2 chars' do it 'with code having 2 chars' do
champ.value = '01' champ.value = '01'

View file

@ -1,5 +1,5 @@
describe Champs::DgfipChamp, type: :model do describe Champs::DgfipChamp, type: :model do
let(:champ) { build(:champ_dgfip) } let(:champ) { described_class.new }
describe 'numero_fiscal and reference_avis' do describe 'numero_fiscal and reference_avis' do
before do before do
@ -37,7 +37,8 @@ describe Champs::DgfipChamp, type: :model do
describe '#validate' do describe '#validate' do
let(:numero_fiscal) { '1122299999092' } let(:numero_fiscal) { '1122299999092' }
let(:reference_avis) { 'FC22299999092' } let(:reference_avis) { 'FC22299999092' }
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_dgfip)) } let(:champ) { described_class.new(dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_dgfip)) }
let(:validation_context) { :champs_public_value } let(:validation_context) { :champs_public_value }
subject { champ.valid?(validation_context) } subject { champ.valid?(validation_context) }

View file

@ -1,7 +1,7 @@
describe Champs::DossierLinkChamp, type: :model do describe Champs::DossierLinkChamp, type: :model do
describe 'prefilling validations' do describe 'prefilling validations' do
describe 'value' do describe 'value' do
subject { build(:champ_dossier_link, value: value).valid?(:prefill) } subject { described_class.new(value:, dossier: build(:dossier)).valid?(:prefill) }
context 'when nil' do context 'when nil' do
let(:value) { nil } let(:value) { nil }

View file

@ -1,7 +1,8 @@
describe Champs::DropDownListChamp do describe Champs::DropDownListChamp do
describe 'validations' do describe 'validations' do
describe 'inclusion' do describe 'inclusion' do
let(:champ) { build(:champ_drop_down_list, other: other, value: value) } let(:champ) { described_class.new(other:, value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list, drop_down_other: other)) }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
context 'when the other value is accepted' do context 'when the other value is accepted' do
@ -51,7 +52,8 @@ describe Champs::DropDownListChamp do
end end
describe '#drop_down_other?' do describe '#drop_down_other?' do
let(:drop_down) { create(:champ_drop_down_list) } let(:drop_down) { described_class.new(dossier: build(:dossier)) }
before { allow(drop_down).to receive(:type_de_champ).and_return(build(:type_de_champ_drop_down_list)) }
context 'when drop_down_other is nil' do context 'when drop_down_other is nil' do
it do it do

View file

@ -1,7 +1,7 @@
describe Champs::EmailChamp do describe Champs::EmailChamp do
describe 'validation' do describe 'validation' do
let(:champ) { build(:champ_email, value: value) } let(:champ) { described_class.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_email)) }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
context 'when nil' do context 'when nil' do

View file

@ -3,8 +3,8 @@ describe Champs::EpciChamp, type: :model do
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
describe 'code_departement' do describe 'code_departement' do
let(:champ) { build(:champ_epci, code_departement: code_departement) } let(:champ) { Champs::EpciChamp.new(code_departement: code_departement, dossier: build(:dossier)) }
before { allow(champ).to receive(:visible?).and_return(true) }
context 'when nil' do context 'when nil' do
let(:code_departement) { nil } let(:code_departement) { nil }
@ -31,9 +31,13 @@ describe Champs::EpciChamp, type: :model do
end end
describe 'external_id' do describe 'external_id' do
let(:champ) { build(:champ_epci, code_departement: code_departement, external_id: nil) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :epci }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
before do before do
champ.code_departement = code_departement
champ.external_id = nil
champ.save!(validate: false) champ.save!(validate: false)
champ.update_columns(external_id: external_id) champ.update_columns(external_id: external_id)
end end
@ -75,13 +79,16 @@ describe Champs::EpciChamp, type: :model do
end end
describe 'value' do describe 'value' do
subject { champ.validate(:champs_public_value) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :epci }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { build(:champ_epci, code_departement: code_departement, external_id: nil, value: nil) } let(:champ) { dossier.champs.first }
before do before do
champ.value = nil
champ.code_departement = code_departement
champ.external_id = nil
champ.save!(validate: false) champ.save!(validate: false)
champ.update_columns(external_id: external_id, value: value) champ.update_columns(external_id:, value:)
end end
context 'when code_departement is nil' do context 'when code_departement is nil' do
@ -144,10 +151,11 @@ describe Champs::EpciChamp, type: :model do
end end
describe 'value' do describe 'value' do
let(:champ) { build(:champ_epci, external_id: nil, value: nil) } let(:champ) { described_class.new }
let(:epci) { APIGeoService.epcis('01').first } let(:epci) { APIGeoService.epcis('01').first }
it 'with departement and code' do it 'with departement and code' do
allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_epci))
champ.code_departement = '01' champ.code_departement = '01'
champ.value = epci[:code] champ.value = epci[:code]
expect(champ.blank?).to be_falsey expect(champ.blank?).to be_falsey

View file

@ -1,16 +1,21 @@
describe Champs::IbanChamp do describe Champs::IbanChamp do
describe '#valid?' do describe '#valid?' do
let(:champ) { Champs::IbanChamp.new(dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_iban)) }
def with_value(value)
champ.tap { _1.value = value }
end
it do it do
expect(build(:champ_iban, value: nil).valid?(:champs_public_value)).to be_truthy expect(with_value(nil).valid?(:champs_public_value)).to be_truthy
expect(build(:champ_iban, value: "FR35 KDSQFDJQSMFDQMFDQ").valid?(:champs_public_value)).to be_falsey expect(with_value("FR35 KDSQFDJQSMFDQMFDQ").valid?(:champs_public_value)).to be_falsey
expect(build(:champ_iban, value: "FR7630006000011234567890189").valid?(:champs_public_value)).to be_truthy expect(with_value("FR7630006000011234567890189").valid?(:champs_public_value)).to be_truthy
expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy expect(with_value("FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy
expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189DSF").valid?(:champs_public_value)).to be_falsey expect(with_value("FR76 3000 6000 0112 3456 7890 189DSF").valid?(:champs_public_value)).to be_falsey
expect(build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy expect(with_value("FR76 3000 6000 0112 3456 7890 189").valid?(:champs_public_value)).to be_truthy
end end
it 'format value after validation' do it 'format value after validation' do
champ = build(:champ_iban, value: "FR76 3000 6000 0112 3456 7890 189") with_value("FR76 3000 6000 0112 3456 7890 189")
champ.valid?(:champs_public_value) champ.valid?(:champs_public_value)
expect(champ.value).to eq("FR76 3000 6000 0112 3456 7890 189") expect(champ.value).to eq("FR76 3000 6000 0112 3456 7890 189")
end end

View file

@ -1,5 +1,6 @@
describe Champs::IntegerNumberChamp do describe Champs::IntegerNumberChamp do
let(:champ) { build(:champ_integer_number, value:) } let(:champ) { Champs::IntegerNumberChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:visible?).and_return(true) }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
describe '#valid?' do describe '#valid?' do

View file

@ -1,21 +1,19 @@
describe Champs::LinkedDropDownListChamp do describe Champs::LinkedDropDownListChamp do
describe '#unpack_value' do describe '#unpack_value' do
let(:champ) { build(:champ_linked_drop_down_list, value: '["tata", "tutu"]') } let(:champ) { Champs::LinkedDropDownListChamp.new(value: '["tata", "tutu"]') }
it { expect(champ.primary_value).to eq('tata') } it { expect(champ.primary_value).to eq('tata') }
it { expect(champ.secondary_value).to eq('tutu') } it { expect(champ.secondary_value).to eq('tutu') }
end end
describe '#pack_value' do describe '#pack_value' do
let(:champ) { build(:champ_linked_drop_down_list, primary_value: 'tata', secondary_value: 'tutu') } let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: 'tata', secondary_value: 'tutu') }
before { champ.save }
it { expect(champ.value).to eq('["tata","tutu"]') } it { expect(champ.value).to eq('["tata","tutu"]') }
end end
describe '#primary_value=' do describe '#primary_value=' do
let!(:champ) { build(:champ_linked_drop_down_list, primary_value: 'tata', secondary_value: 'tutu') } let(:champ) { Champs::LinkedDropDownListChamp.new(primary_value: 'tata', secondary_value: 'tutu') }
before { champ.primary_value = '' } before { champ.primary_value = '' }
@ -23,7 +21,8 @@ describe Champs::LinkedDropDownListChamp do
end end
describe '#to_s' do describe '#to_s' do
let(:champ) { build(:champ_linked_drop_down_list, value: [primary_value, secondary_value].to_json) } let(:champ) { Champs::LinkedDropDownListChamp.new(value: [primary_value, secondary_value].to_json) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) }
let(:primary_value) { nil } let(:primary_value) { nil }
let(:secondary_value) { nil } let(:secondary_value) { nil }
@ -48,11 +47,12 @@ describe Champs::LinkedDropDownListChamp do
end end
describe 'for_export' do describe 'for_export' do
let(:champ) { build(:champ_linked_drop_down_list, value:) } let(:champ) { Champs::LinkedDropDownListChamp.new(value:) }
let(:value) { [primary_value, secondary_value].to_json } let(:value) { [primary_value, secondary_value].to_json }
let(:primary_value) { nil } let(:primary_value) { nil }
let(:secondary_value) { nil } let(:secondary_value) { nil }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_linked_drop_down_list)) }
subject { champ.for_export } subject { champ.for_export }
context 'with no value' do context 'with no value' do
@ -78,7 +78,8 @@ describe Champs::LinkedDropDownListChamp do
describe '#mandatory_and_blank' do describe '#mandatory_and_blank' do
let(:value) { "--Primary--\nSecondary" } let(:value) { "--Primary--\nSecondary" }
subject { described_class.new(type_de_champ: type_de_champ) } subject { described_class.new }
before { allow(subject).to receive(:type_de_champ).and_return(type_de_champ) }
context 'when the champ is not mandatory' do context 'when the champ is not mandatory' do
let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, mandatory: false, drop_down_list_value: value) } let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, mandatory: false, drop_down_list_value: value) }

View file

@ -32,7 +32,9 @@ describe Champs::MesriChamp, type: :model do
end end
describe '#validate' do describe '#validate' do
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_mesri)) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :mesri, stable_id: 99 }]) }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { described_class.new(dossier:, stable_id: 99) }
let(:validation_context) { :create } let(:validation_context) { :create }
subject { champ.valid?(validation_context) } subject { champ.valid?(validation_context) }

View file

@ -1,7 +1,8 @@
describe Champs::MultipleDropDownListChamp do describe Champs::MultipleDropDownListChamp do
let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, drop_down_list_value: "val1\r\nval2\r\nval3\r\n[brackets] val4") } let(:type_de_champ) { build(:type_de_champ_multiple_drop_down_list, drop_down_list_value: "val1\r\nval2\r\nval3\r\n[brackets] val4") }
let(:value) { nil } let(:value) { nil }
let(:champ) { build(:champ_multiple_drop_down_list, type_de_champ:, value:) } let(:champ) { Champs::MultipleDropDownListChamp.new(value:, dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(type_de_champ) }
describe 'validations' do describe 'validations' do
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }

View file

@ -1,5 +1,6 @@
describe Champs::PaysChamp, type: :model do describe Champs::PaysChamp, type: :model do
let(:champ) { build(:champ_pays, value: nil) } let(:champ) { described_class.new(value: nil) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_pays)) }
describe 'value' do describe 'value' do
it 'with code' do it 'with code' do

View file

@ -1,6 +1,6 @@
describe Champs::PhoneChamp do describe Champs::PhoneChamp do
let(:champ) { build(:champ_phone) } let(:champ) { Champs::PhoneChamp.new(dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_phone)) }
describe '#validate' do describe '#validate' do
it do it do
expect(champ_with_value(nil).validate(:champs_public_value)).to be_truthy expect(champ_with_value(nil).validate(:champs_public_value)).to be_truthy

View file

@ -3,60 +3,52 @@ require 'active_storage_validations/matchers'
describe Champs::PieceJustificativeChamp do describe Champs::PieceJustificativeChamp do
include ActiveStorageValidations::Matchers include ActiveStorageValidations::Matchers
describe "skip_validation is not set anymore" do
subject { champ_pj.type_de_champ.skip_pj_validation }
context 'before_save' do
let(:champ_pj) { build (:champ_piece_justificative) }
it { is_expected.to be_falsy }
end
context 'after_save' do
let(:champ_pj) { create (:champ_piece_justificative) }
it { is_expected.to be_falsy }
end
end
describe "validations" do describe "validations" do
let(:champ_pj) { create(:champ_piece_justificative) } let(:champ) { Champs::PieceJustificativeChamp.new }
subject { champ_pj } subject { champ }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_piece_justificative)) }
context "by default" do context "by default" do
it { is_expected.to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) } it { is_expected.to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) }
it { is_expected.to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') } it { is_expected.to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') }
it { expect(champ_pj.type_de_champ.skip_pj_validation).to be_falsy } it { expect(champ.type_de_champ.skip_pj_validation).to be_falsy }
end end
context "when validation is disabled" do context "when validation is disabled" do
before { champ_pj.type_de_champ.update(skip_pj_validation: true) } before { champ.type_de_champ.update(skip_pj_validation: true) }
it { is_expected.not_to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) } it { is_expected.not_to validate_size_of(:piece_justificative_file).less_than(Champs::PieceJustificativeChamp::FILE_MAX_SIZE) }
end end
context "when content-type validation is disabled" do context "when content-type validation is disabled" do
before { champ_pj.type_de_champ.update(skip_content_type_pj_validation: true) } before { champ.type_de_champ.update(skip_content_type_pj_validation: true) }
it { is_expected.not_to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') } it { is_expected.not_to validate_content_type_of(:piece_justificative_file).rejecting('application/x-ms-dos-executable') }
end end
end end
describe "#for_export" do describe "#for_export" do
let(:champ_pj) { create(:champ_piece_justificative) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
subject { champ_pj.for_export } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
subject { champ.for_export }
it { is_expected.to eq('toto.txt') } it { is_expected.to eq('toto.txt') }
context 'without attached file' do context 'without attached file' do
before { champ_pj.piece_justificative_file.purge } before { champ.piece_justificative_file.purge }
it { is_expected.to eq(nil) } it { is_expected.to eq(nil) }
end end
end end
describe '#for_api' do describe '#for_api' do
let(:champ_pj) { create(:champ_piece_justificative) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative }]) }
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ) { dossier.champs.first }
before { champ_pj.piece_justificative_file.first.blob.update(virus_scan_result:) } before { champ.piece_justificative_file.first.blob.update(virus_scan_result:) }
subject { champ_pj.for_api } subject { champ.for_api }
context 'when file is safe' do context 'when file is safe' do
let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE } let(:virus_scan_result) { ActiveStorage::VirusScanner::SAFE }

View file

@ -1,5 +1,6 @@
describe Champs::PoleEmploiChamp, type: :model do describe Champs::PoleEmploiChamp, type: :model do
let(:champ) { build(:champ_pole_emploi) } let(:champ) { described_class.new(dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(:type_de_champ_pole_emploi) }
describe 'identifiant' do describe 'identifiant' do
before do before do
@ -32,7 +33,6 @@ describe Champs::PoleEmploiChamp, type: :model do
end end
describe '#validate' do describe '#validate' do
let(:champ) { described_class.new(dossier: create(:dossier), type_de_champ: create(:type_de_champ_pole_emploi)) }
let(:validation_context) { :create } let(:validation_context) { :create }
subject { champ.valid?(validation_context) } subject { champ.valid?(validation_context) }

View file

@ -1,7 +1,17 @@
describe Champs::RegionChamp, type: :model do describe Champs::RegionChamp, type: :model do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :regions, stable_id: 99 }]) }
let(:dossier) { create(:dossier, procedure:) }
describe 'validations' do describe 'validations' do
describe 'external link' do describe 'external link' do
let(:champ) { build(:champ_regions, value: nil, external_id: external_id) } let(:champ) do
described_class
.new(stable_id: 99, dossier:)
.tap do |champ|
champ.value = nil
champ.external_id = external_id
end
end
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
context 'when nil' do context 'when nil' do
let(:external_id) { nil } let(:external_id) { nil }
@ -29,21 +39,26 @@ describe Champs::RegionChamp, type: :model do
end end
describe 'value' do describe 'value' do
let(:champ) { create(:champ_regions, value: nil) } let(:champ) do
described_class
.new(stable_id: 99, dossier:)
.tap do |champ|
champ.value = value
end
end
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
before { champ.update_columns(value: value) }
context 'when nil' do context 'when nil' do
let(:value) { nil } let(:value) { nil }
it { is_expected.to be_truthy } it { is_expected.to be_truthy }
end end
# not real use case, the value= method override value when blank? aka "" to nil
context 'when blank' do context 'when blank' do
let(:value) { '' } let(:value) { '' }
it { is_expected.to be_falsey } xit { is_expected.to be_falsey }
end end
context 'when included in the region names' do context 'when included in the region names' do
@ -61,7 +76,9 @@ describe Champs::RegionChamp, type: :model do
end end
describe 'value' do describe 'value' do
let(:champ) { build(:champ_regions, value: nil) } let(:champ) do
described_class.new(stable_id: 99, dossier:)
end
it 'with code' do it 'with code' do
champ.value = '01' champ.value = '01'

View file

@ -1,12 +1,15 @@
describe Champs::RNAChamp do describe Champs::RNAChamp do
let(:champ) { create(:champ_rna, value: "W182736273") } let(:champ) { Champs::RNAChamp.new(value: "W182736273", dossier: build(:dossier)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rna)) }
def with_value(value)
champ.tap { _1.value = value }
end
describe '#valid?' do describe '#valid?' do
it { expect(build(:champ_rna, value: nil).valid?(:champs_public_value)).to be_truthy } it { expect(with_value(nil).validate(:champs_public_value)).to be_truthy }
it { expect(build(:champ_rna, value: "2736251627").valid?(:champs_public_value)).to be_falsey } it { expect(with_value("2736251627").validate(:champs_public_value)).to be_falsey }
it { expect(build(:champ_rna, value: "A172736283").valid?(:champs_public_value)).to be_falsey } it { expect(with_value("A172736283").validate(:champs_public_value)).to be_falsey }
it { expect(build(:champ_rna, value: "W1827362718").valid?(:champs_public_value)).to be_falsey } it { expect(with_value("W1827362718").validate(:champs_public_value)).to be_falsey }
it { expect(build(:champ_rna, value: "W182736273").valid?(:champs_public_value)).to be_truthy } it { expect(with_value("W182736273").validate(:champs_public_value)).to be_truthy }
end end
describe "#export" do describe "#export" do

View file

@ -1,14 +1,15 @@
describe Champs::RNFChamp, type: :model do describe Champs::RNFChamp, type: :model do
let(:champ) { build(:champ_rnf, external_id:) } let(:champ) { described_class.new(external_id:) }
let(:stub) { stub_request(:get, "#{url}/#{external_id}").to_return(body:, status:) }
let(:url) { RNFService.new.send(:url) }
let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_rnf', "#{response_type}.json").read }
let(:external_id) { '075-FDD-00003-01' } let(:external_id) { '075-FDD-00003-01' }
let(:status) { 200 } let(:body) { Rails.root.join('spec', 'fixtures', 'files', 'api_rnf', "#{response_type}.json").read }
let(:response_type) { 'valid' } let(:response_type) { 'valid' }
describe 'fetch_external_data' do describe 'fetch_external_data' do
subject { stub; champ.fetch_external_data } let(:url) { RNFService.new.send(:url) }
let(:status) { 200 }
before { stub_request(:get, "#{url}/#{external_id}").to_return(body:, status:) }
subject { champ.fetch_external_data }
context 'success' do context 'success' do
it do it do
@ -84,7 +85,8 @@ describe Champs::RNFChamp, type: :model do
end end
describe 'for_export' do describe 'for_export' do
let(:champ) { build(:champ_rnf, external_id:, data: JSON.parse(body)) } let(:champ) { described_class.new(external_id:, data: JSON.parse(body)) }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_rnf)) }
it do it do
expect(champ.for_export(:value)).to eq '075-FDD-00003-01' expect(champ.for_export(:value)).to eq '075-FDD-00003-01'
expect(champ.for_export(:nom)).to eq 'Fondation SFR' expect(champ.for_export(:nom)).to eq 'Fondation SFR'

View file

@ -1,13 +1,16 @@
describe Champs::TitreIdentiteChamp do describe Champs::TitreIdentiteChamp do
describe "#for_export" do describe "#for_export" do
let(:champ_titre_identite) { create(:champ_titre_identite) } let(:champ) { described_class.new }
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_titre_identite)) }
subject { champ_titre_identite.for_export } subject { champ.for_export }
it { is_expected.to eq('présent') } context 'without attached file' do
let(:piece_justificative_file) { double(attached?: true) }
before { allow(champ).to receive(:piece_justificative_file).and_return(piece_justificative_file) }
it { is_expected.to eq('présent') }
end
context 'without attached file' do context 'without attached file' do
before { champ_titre_identite.piece_justificative_file.purge }
it { is_expected.to eq('absent') } it { is_expected.to eq('absent') }
end end
end end

View file

@ -1,5 +1,6 @@
describe Champs::YesNoChamp do describe Champs::YesNoChamp do
it_behaves_like "a boolean champ" do it_behaves_like "a boolean champ" do
let(:boolean_champ) { build(:champ_yes_no, value: value) } let(:boolean_champ) { described_class.new(value: value) }
before { allow(boolean_champ).to receive(:type_de_champ).and_return(build(:type_de_champ_yes_no)) }
end end
end end

View file

@ -1,11 +1,10 @@
describe ChampConditionalConcern do describe ChampConditionalConcern do
include Logic include Logic
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :decimal_number, stable_id: 99 }, { type: :decimal_number, condition: }]) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :decimal_number, stable_id: 99 }, { type: :decimal_number, stable_id: 999, condition: }]) }
let(:dossier) { create(:dossier, revision: procedure.active_revision) } let(:dossier) { create(:dossier, :with_populated_champs, revision: procedure.active_revision) }
let(:types_de_champ) { procedure.active_revision.types_de_champ_public } let(:champ) { dossier.champs.find { _1.stable_id == 99 }.tap { _1.update_column(:value, '1.1234') } }
let(:champ) { create(:champ_decimal_number, dossier:, type_de_champ: types_de_champ.first, value: '1.1234') } let(:last_champ) { dossier.champs.find { _1.stable_id == 999 }.tap { _1.update_column(:value, '1.1234') } }
let(:last_champ) { create(:champ_decimal_number, dossier:, type_de_champ: types_de_champ.last, value: '1.1234') }
let(:condition) { nil } let(:condition) { nil }
describe '#dependent_conditions?' do describe '#dependent_conditions?' do

View file

@ -17,7 +17,7 @@ RSpec.describe DossierCloneConcern do
describe '#clone' do describe '#clone' do
let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) } let(:dossier) { create(:dossier, :en_construction, :with_populated_champs, procedure:) }
let(:types_de_champ_public) { [{}] } let(:types_de_champ_public) { [{}] }
let(:types_de_champ_private) { [{}] } let(:types_de_champ_private) { [] }
let(:fork) { false } let(:fork) { false }
subject(:new_dossier) { dossier.clone(fork:) } subject(:new_dossier) { dossier.clone(fork:) }
@ -131,67 +131,65 @@ RSpec.describe DossierCloneConcern do
end end
context 'for Champs::Repetition with rows, original_champ.repetition and rows are duped' do context 'for Champs::Repetition with rows, original_champ.repetition and rows are duped' do
let(:dossier) { create(:dossier) } let(:types_de_champ_public) { [{ type: :repetition, children: [{}, {}] }] }
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, :with_types_de_champ, procedure: dossier.procedure) } let(:champ_repetition) { dossier.champs.first }
let(:champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) } let(:cloned_champ_repetition) { new_dossier.champs.first }
before { dossier.champs_public << champ_repetition }
it do it do
expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.count).to eq(4) expect(cloned_champ_repetition.champs.count).to eq(4)
expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.ids).not_to eq(champ_repetition.champs.ids) expect(cloned_champ_repetition.champs.ids).not_to eq(champ_repetition.champs.ids)
end end
end end
context 'for Champs::CarteChamp with geo areas, original_champ.geo_areas are duped' do context 'for Champs::CarteChamp with geo areas, original_champ.geo_areas are duped' do
let(:dossier) { create(:dossier) } let(:types_de_champ_public) { [{ type: :carte }] }
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } let(:champ_carte) { dossier.champs.first }
let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } let(:cloned_champ_carte) { new_dossier.champs.first }
let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) }
before { dossier.champs_public << champ_carte }
it do it do
expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.count).to eq(1) expect(cloned_champ_carte.geo_areas.count).to eq(2)
expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.ids).not_to eq(champ_carte.geo_areas.ids) expect(cloned_champ_carte.geo_areas.ids).not_to eq(champ_carte.geo_areas.ids)
end end
end end
context 'for Champs::SiretChamp, original_champ.etablissement is duped' do context 'for Champs::SiretChamp, original_champ.etablissement is duped' do
let(:dossier) { create(:dossier) } let(:types_de_champ_public) { [{ type: :siret }] }
let(:type_de_champs_siret) { create(:type_de_champ_siret, procedure: dossier.procedure) } let(:champ_siret) { dossier.champs.first }
let(:etablissement) { create(:etablissement) } let(:cloned_champ_siret) { new_dossier.champs.first }
let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champs_siret, etablissement: create(:etablissement)) }
before { dossier.champs_public << champ_siret }
it do it do
expect(Champs::SiretChamp.where(dossier: dossier).first.etablissement).not_to be_nil expect(champ_siret.etablissement).not_to be_nil
expect(Champs::SiretChamp.where(dossier: new_dossier).first.etablissement.id).not_to eq(champ_siret.etablissement.id) expect(cloned_champ_siret.etablissement.id).not_to eq(champ_siret.etablissement.id)
end
end end
end
context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do
let(:types_de_champ_public) { [{ type: :piece_justificative }] } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:champ_piece_justificative) { dossier.champs_public.first } let(:champ_piece_justificative) { dossier.champs.first }
let(:cloned_champ_piece_justificative) { new_dossier.champs.first }
it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) } it { expect(cloned_champ_piece_justificative.piece_justificative_file.first.blob).to eq(champ_piece_justificative.piece_justificative_file.first.blob) }
end end
context 'for Champs::AddressChamp, original_champ.data is duped' do context 'for Champs::AddressChamp, original_champ.data is duped' do
let(:dossier) { create(:dossier) } let(:types_de_champ_public) { [{ type: :address }] }
let(:type_de_champs_adress) { create(:type_de_champ_address, procedure: dossier.procedure) } let(:champ_address) { dossier.champs.first }
let(:etablissement) { create(:etablissement) } let(:cloned_champ_address) { new_dossier.champs.first }
let(:champ_address) { create(:champ_address, type_de_champ: type_de_champs_adress, external_id: 'Address', data: { city_code: '75019' }) }
before { dossier.champs_public << champ_address } before { champ_address.update(external_id: 'Address', data: { city_code: '75019' }) }
it do it do
expect(Champs::AddressChamp.where(dossier: dossier).first.data).not_to be_nil expect(champ_address.data).not_to be_nil
expect(Champs::AddressChamp.where(dossier: dossier).first.external_id).not_to be_nil expect(champ_address.external_id).not_to be_nil
expect(Champs::AddressChamp.where(dossier: new_dossier).first.external_id).to eq(champ_address.external_id) expect(cloned_champ_address.external_id).to eq(champ_address.external_id)
expect(Champs::AddressChamp.where(dossier: new_dossier).first.data).to eq(champ_address.data) expect(cloned_champ_address.data).to eq(champ_address.data)
end end
end end
end end
context 'private are renewd' do context 'private are renewd' do
let(:types_de_champ_private) { [{}] }
it 'reset champs private values' do it 'reset champs private values' do
expect(new_dossier.champs_private.count).to eq(dossier.champs_private.count) expect(new_dossier.champs_private.count).to eq(dossier.champs_private.count)
expect(new_dossier.champs_private.ids).not_to eq(dossier.champs_private.ids) expect(new_dossier.champs_private.ids).not_to eq(dossier.champs_private.ids)
@ -217,13 +215,13 @@ RSpec.describe DossierCloneConcern do
context "piece justificative champ" do context "piece justificative champ" do
let(:types_de_champ_public) { [{ type: :piece_justificative }] } let(:types_de_champ_public) { [{ type: :piece_justificative }] }
let(:champ_pj) { dossier.champs_public.first } let(:champ_pj) { dossier.champs.first }
let(:cloned_champ_pj) { new_dossier.champs.first }
it { it {
champ_pj_fork = Champs::PieceJustificativeChamp.where(dossier: new_dossier).first expect(cloned_champ_pj.piece_justificative_file.first.blob).to eq(champ_pj.piece_justificative_file.first.blob)
expect(champ_pj_fork.piece_justificative_file.first.blob).to eq(champ_pj.piece_justificative_file.first.blob) expect(cloned_champ_pj.created_at).to eq(champ_pj.created_at)
expect(champ_pj_fork.created_at).to eq(champ_pj.created_at) expect(cloned_champ_pj.updated_at).to eq(champ_pj.updated_at)
expect(champ_pj_fork.updated_at).to eq(champ_pj.updated_at)
} }
end end
@ -258,7 +256,8 @@ RSpec.describe DossierCloneConcern do
before do before do
champ = dossier.champs.find { _1.stable_id == 992 } champ = dossier.champs.find { _1.stable_id == 992 }
geo_area = build(:geo_area, champ:, geometry: { "i'm" => "invalid" }) geo_area = champ.geo_areas.first
geo_area.geometry = { "i'm" => "invalid" }
geo_area.save!(validate: false) geo_area.save!(validate: false)
end end

View file

@ -127,7 +127,7 @@ RSpec.describe DossierPrefillableConcern do
private private
def find_champ_by_stable_id(dossier, stable_id) def find_champ_by_stable_id(dossier, stable_id)
dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) dossier.champs.find_by(stable_id:)
end end
end end
end end

View file

@ -87,7 +87,7 @@ describe DossierRebaseConcern do
context 'with a value' do context 'with a value' do
before do before do
dossier.champs.find_by(type_de_champ: type_de_champ).update(value: 'a value') dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'a value')
end end
it 'should be true' do it 'should be true' do
@ -364,7 +364,7 @@ describe DossierRebaseConcern do
expect(dossier.champs_public.size).to eq(6) expect(dossier.champs_public.size).to eq(6)
expect(dossier.champs.count(&:public?)).to eq(12) expect(dossier.champs.count(&:public?)).to eq(12)
expect(rebased_text_champ.value).to eq(text_champ.value) expect(rebased_text_champ.value).to eq(text_champ.value)
expect(rebased_text_champ.type_de_champ_id).not_to eq(text_champ.type_de_champ_id) expect(rebased_text_champ.type_de_champ).not_to eq(text_champ.type_de_champ)
expect(rebased_datetime_champ.type_champ).to eq(TypeDeChamp.type_champs.fetch(:date)) expect(rebased_datetime_champ.type_champ).to eq(TypeDeChamp.type_champs.fetch(:date))
expect(rebased_datetime_champ.value).to be_nil expect(rebased_datetime_champ.value).to be_nil
expect(rebased_repetition_champ.rows.size).to eq(2) expect(rebased_repetition_champ.rows.size).to eq(2)
@ -562,7 +562,7 @@ describe DossierRebaseConcern do
context 'and the cadastre are removed' do context 'and the cadastre are removed' do
before do before do
dossier.champs_public.first.update(value: 'v1', geo_areas: [create(:geo_area, :cadastre)]) dossier.champs_public.first.update(value: 'v1', geo_areas: [build(:geo_area, :cadastre)])
stable_id = procedure.draft_revision.types_de_champ.find_by(libelle: 'l1') stable_id = procedure.draft_revision.types_de_champ.find_by(libelle: 'l1')
tdc_to_update = procedure.draft_revision.find_and_ensure_exclusive_use(stable_id) tdc_to_update = procedure.draft_revision.find_and_ensure_exclusive_use(stable_id)
@ -623,7 +623,7 @@ describe DossierRebaseConcern do
def first_champ = dossier.champs_public.first def first_champ = dossier.champs_public.first
before do before do
first_champ.update(value: 'v1', external_id: '123', geo_areas: [create(:geo_area)]) first_champ.update(value: 'v1', external_id: '123', geo_areas: [build(:geo_area)])
first_champ.update(data: { a: 1 }) first_champ.update(data: { a: 1 })
first_champ.piece_justificative_file.attach( first_champ.piece_justificative_file.attach(

View file

@ -1,6 +1,12 @@
RSpec.describe RNAChampAssociationFetchableConcern do RSpec.describe RNAChampAssociationFetchableConcern do
describe '.fetch_association!' do describe '.fetch_association!' do
let!(:champ) { create(:champ_rna, data: "not nil data", value: 'W173847273') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :rna }]) }
let(:dossier) do
create(:dossier, :with_populated_champs, procedure:).tap do
_1.champs.first.update(data: "not nil data", value: 'W173847273')
end
end
let!(:champ) { dossier.champs.first }
before do before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v4\/djepva\/api-association\/associations\/open_data\/#{rna}/) stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v4\/djepva\/api-association\/associations\/open_data\/#{rna}/)

View file

@ -3,7 +3,9 @@ RSpec.describe SiretChampEtablissementFetchableConcern do
let(:api_etablissement_status) { 200 } let(:api_etablissement_status) { 200 }
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') } let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
let(:token_expired) { false } let(:token_expired) { false }
let!(:champ) { create(:champ_siret) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :siret }]) }
let(:dossier) { create(:dossier, procedure:) }
let!(:champ) { dossier.champs.first.tap { _1.update!(etablissement: create(:etablissement)) } }
before do before do
stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v3\/insee\/sirene\/etablissements\/#{siret}/) stub_request(:get, /https:\/\/entreprise.api.gouv.fr\/v3\/insee\/sirene\/etablissements\/#{siret}/)

View file

@ -257,7 +257,7 @@ describe TagsSubstitutionConcern, type: :model do
context 'and the champ has a primary value' do context 'and the champ has a primary value' do
before do before do
dossier.champs_public.find_by(type_de_champ: type_de_champ).update(primary_value: 'primo') dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(primary_value: 'primo')
dossier.reload dossier.reload
end end
@ -265,7 +265,7 @@ describe TagsSubstitutionConcern, type: :model do
context 'and the champ has a secondary value' do context 'and the champ has a secondary value' do
before do before do
dossier.champs_public.find_by(type_de_champ: type_de_champ).update(secondary_value: 'secundo') dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(secondary_value: 'secundo')
dossier.reload dossier.reload
end end

View file

@ -10,28 +10,40 @@ describe TreeableConcern do
subject { ChampsToTree.new(types_de_champ:).root } subject { ChampsToTree.new(types_de_champ:).root }
describe "to_tree" do describe "to_tree" do
let(:header_1) { build(:champ_header_section_level_1).type_de_champ } let(:procedure) { create(:procedure, types_de_champ_public:) }
let(:header_1_2) { build(:champ_header_section_level_2).type_de_champ } let(:types_de_champ_public) { [] }
let(:header_2) { build(:champ_header_section_level_1).type_de_champ } let(:types_de_champ) { procedure.active_revision.types_de_champ_public }
let(:champ_text) { build(:champ_text).type_de_champ }
let(:champ_textarea) { build(:champ_textarea).type_de_champ } let(:header_1) { { type: :header_section, level: 1, stable_id: 99 } }
let(:champ_explication) { build(:champ_explication).type_de_champ } let(:header_1_2) { { type: :header_section, level: 2, stable_id: 199 } }
let(:champ_communes) { build(:champ_communes).type_de_champ } let(:header_2) { { type: :header_section, level: 1, stable_id: 299 } }
let(:champ_text) { { stable_id: 399 } }
let(:champ_textarea) { { type: :textarea, stable_id: 499 } }
let(:champ_explication) { { type: :explication, stable_id: 599 } }
let(:champ_communes) { { type: :communes, stable_id: 699 } }
let(:header_1_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 99 } }
let(:header_1_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 199 } }
let(:header_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 299 } }
let(:champ_text_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 399 } }
let(:champ_textarea_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 499 } }
let(:champ_explication_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 599 } }
let(:champ_communes_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 699 } }
context 'without section' do context 'without section' do
let(:types_de_champ) do let(:types_de_champ_public) do
[ [
champ_text, champ_textarea champ_text, champ_textarea
] ]
end end
it 'inlines champs at root level' do it 'inlines champs at root level' do
expect(subject.size).to eq(types_de_champ.size) expect(subject.size).to eq(types_de_champ.size)
expect(subject).to eq(types_de_champ) expect(subject).to eq([champ_text_tdc, champ_textarea_tdc])
end end
end end
context 'with header_section and champs' do context 'with header_section and champs' do
let(:types_de_champ) do let(:types_de_champ_public) do
[ [
header_1, header_1,
champ_explication, champ_explication,
@ -44,14 +56,16 @@ describe TreeableConcern do
it 'wraps champs within preview header section' do it 'wraps champs within preview header section' do
expect(subject.size).to eq(2) expect(subject.size).to eq(2)
expect(subject).to eq([ expect(subject).to eq([
[header_1, champ_explication, champ_text], [header_1_tdc, champ_explication_tdc, champ_text_tdc],
[header_2, champ_textarea] [header_2_tdc, champ_textarea_tdc]
]) ])
end end
end end
context 'leading champs, and in between sections only' do context 'leading champs, and in between sections only' do
let(:types_de_champ) do let(:champ_textarea_bis) { { type: :textarea, stable_id: 799 } }
let(:champ_textarea_bis_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } }
let(:types_de_champ_public) do
[ [
champ_text, champ_text,
champ_textarea, champ_textarea,
@ -59,22 +73,22 @@ describe TreeableConcern do
champ_explication, champ_explication,
champ_communes, champ_communes,
header_2, header_2,
champ_textarea champ_textarea_bis
] ]
end end
it 'chunk by uniq champs' do it 'chunk by uniq champs' do
expect(subject.size).to eq(4) expect(subject.size).to eq(4)
expect(subject).to eq([ expect(subject).to eq([
champ_text, champ_text_tdc,
champ_textarea, champ_textarea_tdc,
[header_1, champ_explication, champ_communes], [header_1_tdc, champ_explication_tdc, champ_communes_tdc],
[header_2, champ_textarea] [header_2_tdc, champ_textarea_bis_tdc]
]) ])
end end
end end
context 'with one sub sections' do context 'with one sub sections' do
let(:types_de_champ) do let(:types_de_champ_public) do
[ [
header_1, header_1,
champ_explication, champ_explication,
@ -87,18 +101,22 @@ describe TreeableConcern do
it 'chunk by uniq champs' do it 'chunk by uniq champs' do
expect(subject.size).to eq(2) expect(subject.size).to eq(2)
expect(subject).to eq([ expect(subject).to eq([
[header_1, champ_explication, [header_1_2, champ_communes]], [header_1_tdc, champ_explication_tdc, [header_1_2_tdc, champ_communes_tdc]],
[header_2, champ_textarea] [header_2_tdc, champ_textarea_tdc]
]) ])
end end
end end
context 'with consecutive subsection' do context 'with consecutive subsection' do
let(:header_1) { build(:champ_header_section_level_1).type_de_champ } let(:header_1_2_1) { { type: :header_section, level: 2, stable_id: 799 } }
let(:header_1_2_1) { build(:champ_header_section_level_2).type_de_champ } let(:header_1_2_2) { { type: :header_section, level: 2, stable_id: 899 } }
let(:header_1_2_2) { build(:champ_header_section_level_2).type_de_champ } let(:header_1_2_3) { { type: :header_section, level: 2, stable_id: 999 } }
let(:header_1_2_3) { build(:champ_header_section_level_2).type_de_champ }
let(:types_de_champ) do let(:header_1_2_1_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } }
let(:header_1_2_2_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 899 } }
let(:header_1_2_3_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 999 } }
let(:types_de_champ_public) do
[ [
header_1, header_1,
header_1_2_1, header_1_2_1,
@ -113,19 +131,20 @@ describe TreeableConcern do
expect(subject.size).to eq(1) expect(subject.size).to eq(1)
expect(subject).to eq([ expect(subject).to eq([
[ [
header_1, header_1_tdc,
[header_1_2_1, champ_text], [header_1_2_1_tdc, champ_text_tdc],
[header_1_2_2, champ_textarea], [header_1_2_2_tdc, champ_textarea_tdc],
[header_1_2_3, champ_communes] [header_1_2_3_tdc, champ_communes_tdc]
] ]
]) ])
end end
end end
context 'with one sub sections and one subsub section' do context 'with one sub sections and one subsub section' do
let(:header_1_2_3) { build(:champ_header_section_level_3).type_de_champ } let(:header_1_2_3) { { type: :header_section, level: 3, stable_id: 799 } }
let(:header_1_2_3_tdc) { procedure.active_revision.types_de_champ_public.find { _1.stable_id == 799 } }
let(:types_de_champ) do let(:types_de_champ_public) do
[ [
header_1, header_1,
champ_explication, champ_explication,
@ -142,19 +161,19 @@ describe TreeableConcern do
expect(subject.size).to eq(2) expect(subject.size).to eq(2)
expect(subject).to eq([ expect(subject).to eq([
[ [
header_1, header_1_tdc,
champ_explication, champ_explication_tdc,
[ [
header_1_2, header_1_2_tdc,
champ_communes, champ_communes_tdc,
[ [
header_1_2_3, champ_text header_1_2_3_tdc, champ_text_tdc
] ]
] ]
], ],
[ [
header_2, header_2_tdc,
champ_textarea champ_textarea_tdc
] ]
]) ])
end end

View file

@ -1575,12 +1575,12 @@ describe Dossier, type: :model do
end end
context "when a SIRET champ has etablissement in degraded mode" do context "when a SIRET champ has etablissement in degraded mode" do
let(:dossier_incomplete) { create(:dossier, :en_instruction) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :siret }]) }
let(:dossier_ok) { create(:dossier, :en_instruction) } let(:dossier_incomplete) { create(:dossier, :en_instruction, :with_populated_champs, procedure:) }
let(:dossier_ok) { create(:dossier, :en_instruction, :with_populated_champs, procedure:) }
before do before do
dossier_incomplete.champs_public << create(:champ_siret, dossier: dossier_incomplete, etablissement: Etablissement.new(siret: build(:etablissement).siret)) dossier_incomplete.champs.first.update(etablissement: Etablissement.new(siret: build(:etablissement).siret))
dossier_ok.champs_public << create(:champ_siret, dossier: dossier_ok)
end end
it "can't accepter" do it "can't accepter" do
@ -1837,43 +1837,42 @@ describe Dossier, type: :model do
end end
describe '#geo_data' do describe '#geo_data' do
let(:dossier) { create(:dossier) } let(:procedure) { create(:procedure, types_de_champ_public:, types_de_champ_private:) }
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } let(:dossier) { create(:dossier, :with_populated_champs, :with_populated_annotations, procedure:) }
let(:geo_area) { create(:geo_area) } let(:types_de_champ_public) { [] }
let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } let(:types_de_champ_private) { [] }
context "without data" do context "without data" do
it { expect(dossier.geo_data?).to be_falsey } it { expect(dossier.geo_data?).to be_falsey }
end end
context "with geo data in public champ" do context "with geo data in public champ" do
before do let(:types_de_champ_public) { [{ type: :carte }] }
dossier.champs_public << champ_carte
end
it { expect(dossier.geo_data?).to be_truthy } it { expect(dossier.geo_data?).to be_truthy }
end end
context "with geo data in private champ" do context "with geo data in private champ" do
before do let(:types_de_champ_private) { [{ type: :carte }] }
dossier.champs_private << champ_carte
end
it { expect(dossier.geo_data?).to be_truthy } it { expect(dossier.geo_data?).to be_truthy }
end end
it "should solve N+1 problem" do context "should solve N+1 problem" do
dossier.champs_public << create_list(:champ_carte, 3, type_de_champ: type_de_champ_carte, geo_areas: [create(:geo_area)]) let(:types_de_champ_public) { [{ type: :carte }, { type: :carte }, { type: :carte }] }
dossier.champs_for_revision
count = 0 it do
dossier.champs_for_revision
callback = lambda { |*_args| count += 1 } count = 0
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
dossier.geo_data? callback = lambda { |*_args| count += 1 }
ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
dossier.geo_data?
end
expect(count).to eq(1)
end end
expect(count).to eq(1)
end end
end end
@ -1930,13 +1929,13 @@ describe Dossier, type: :model do
end end
describe "to_feature_collection" do describe "to_feature_collection" do
let(:dossier) { create(:dossier) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :carte }]) }
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) } let(:champ_carte) { dossier.champs.first }
let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) } let(:geo_area) { build(:geo_area, :selection_utilisateur, :polygon) }
before do before do
dossier.champs_public << champ_carte champ_carte.update(geo_areas: [geo_area])
end end
it 'should have all champs carto' do it 'should have all champs carto' do
@ -2120,16 +2119,14 @@ describe Dossier, type: :model do
end end
describe "remove_titres_identite!" do describe "remove_titres_identite!" do
let(:dossier) { create(:dossier, :en_instruction, :followed, :with_individual) } let(:declarative_with_state) { nil }
let(:type_de_champ_titre_identite) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) } let(:procedure) { create(:procedure, declarative_with_state:, types_de_champ_public: [{ type: :titre_identite }, { type: :titre_identite }]) }
let(:champ_titre_identite) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite) } let(:dossier) { create(:dossier, :en_instruction, :followed, :with_populated_champs, procedure:) }
let(:type_de_champ_titre_identite_vide) { create(:type_de_champ_titre_identite, procedure: dossier.procedure) } let(:champ_titre_identite) { dossier.champs.first }
let(:champ_titre_identite_vide) { create(:champ_titre_identite, type_de_champ: type_de_champ_titre_identite_vide) } let(:champ_titre_identite_vide) { dossier.champs.second }
before do before do
champ_titre_identite_vide.piece_justificative_file.purge champ_titre_identite_vide.piece_justificative_file.purge
dossier.champs_public << champ_titre_identite
dossier.champs_public << champ_titre_identite_vide
end end
it "clean up titres identite on accepter" do it "clean up titres identite on accepter" do
@ -2154,7 +2151,8 @@ describe Dossier, type: :model do
end end
context 'en_construction' do context 'en_construction' do
let(:dossier) { create(:dossier, :en_construction, :followed, :with_individual, :with_declarative_accepte) } let(:declarative_with_state) { 'accepte' }
let(:dossier) { create(:dossier, :en_construction, :followed, :with_populated_champs, procedure:) }
it "clean up titres identite on accepter_automatiquement" do it "clean up titres identite on accepter_automatiquement" do
expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy expect(champ_titre_identite.piece_justificative_file.attached?).to be_truthy

View file

@ -1,6 +1,11 @@
describe Champs::EngagementJuridiqueChamp do describe Champs::EngagementJuridiqueChamp do
describe 'validation' do describe 'validation' do
let(:champ) { build(:champ_engagement_juridique, value: value) } let(:champ) do
described_class
.new(dossier: build(:dossier))
.tap { _1.value = value }
end
before { allow(champ).to receive(:type_de_champ).and_return(build(:type_de_champ_engagement_juridique)) }
subject { champ.validate(:champs_public_value) } subject { champ.validate(:champs_public_value) }
context 'with [A-Z]' do context 'with [A-Z]' do

View file

@ -119,6 +119,9 @@ describe Etablissement do
let(:etablissement) { create(:etablissement, dossier: build(:dossier)) } let(:etablissement) { create(:etablissement, dossier: build(:dossier)) }
it "schedule update search terms" do it "schedule update search terms" do
etablissement
etablissement.dossier.debounce_index_search_terms_flag.remove
assert_enqueued_jobs(1, only: DossierIndexSearchTermsJob) do assert_enqueued_jobs(1, only: DossierIndexSearchTermsJob) do
etablissement.update(entreprise_nom: "nom") etablissement.update(entreprise_nom: "nom")
end end

View file

@ -136,46 +136,33 @@ describe ExportTemplate do
end end
context 'for pj' do context 'for pj' do
let(:dossier) { procedure.dossiers.first } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, procedure:) } let(:champ_pj) { dossier.champs.find(&:piece_justificative?) }
let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) }
let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) }
before do
dossier.champs_public << champ_pj
end
it 'returns pj and custom name for pj' do it 'returns pj and custom name for pj' do
expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/superpj_justif-1.png"]) expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/superpj_justif-1.png"])
end end
end end
context 'pj repetable' do context 'pj repetable' do
let(:procedure) do let(:procedure) { create(:procedure, :for_individual, types_de_champ_public:) }
create(:procedure_with_dossiers, :for_individual, types_de_champ_public: [{ type: :repetition, mandatory: true, children: [{ libelle: 'sub type de champ' }] }]) let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
end
let(:type_de_champ_repetition) do
repetition = draft.types_de_champ_public.repetition.first
repetition.update(stable_id: 3333)
repetition
end
let(:draft) { procedure.draft_revision } let(:draft) { procedure.draft_revision }
let(:dossier) { procedure.dossiers.first } let(:types_de_champ_public) do
[
let(:type_de_champ_pj) do {
draft.add_type_de_champ({ type: :repetition,
type_champ: TypeDeChamp.type_champs.fetch(:piece_justificative), stable_id: 3333,
libelle: "pj repet", mandatory: true, children: [
stable_id: 10, { type: :text, libelle: 'sub type de champ' },
parent_stable_id: type_de_champ_repetition.stable_id { type: :piece_justificative, stable_id: 10, libelle: 'pj repet' }
}) ]
}
]
end end
let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } let(:champ_pj) { dossier.champs.find(&:piece_justificative?) }
let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) }
before do
dossier.champs_public << champ_pj
end
it 'rename repetable pj' do it 'rename repetable pj' do
expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/pj_repet_#{dossier.id}-1.png"]) expect(export_template.attachment_and_path(dossier, attachment, champ: champ_pj)).to eq([attachment, "DOSSIER_#{dossier.id}/pj_repet_#{dossier.id}-1.png"])
end end
@ -201,13 +188,14 @@ describe ExportTemplate do
end end
describe '#tiptap_convert_pj' do describe '#tiptap_convert_pj' do
let(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile', procedure:) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :piece_justificative, stable_id: 3, libelle: 'Justificatif de domicile' }]) }
let(:champ_pj) { create(:champ_piece_justificative, type_de_champ: type_de_champ_pj) } let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
let(:champ_pj) { dossier.champs.first }
let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) } let(:attachment) { ActiveStorage::Attachment.new(name: 'pj', record: champ_pj, blob: ActiveStorage::Blob.new(filename: "superpj.png")) }
it 'convert pj' do it 'convert pj' do
attachment attachment
expect(export_template.tiptap_convert_pj(dossier, type_de_champ_pj.stable_id, attachment)).to eq "superpj_justif" expect(export_template.tiptap_convert_pj(dossier, 3, attachment)).to eq "superpj_justif"
end end
end end

View file

@ -20,8 +20,8 @@ describe Logic::BinaryOperator do
end end
describe '#sources' do describe '#sources' do
let(:champ) { create(:champ_integer_number, value: nil) } let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: 1) }
let(:champ2) { create(:champ_integer_number, value: nil) } let(:champ2) { Champs::IntegerNumberChamp.new(value: nil, stable_id: 2) }
it { expect(two_greater_than_one.sources).to eq([]) } it { expect(two_greater_than_one.sources).to eq([]) }
it { expect(greater_than(champ_value(champ.stable_id), constant(2)).sources).to eq([champ.stable_id]) } it { expect(greater_than(champ_value(champ.stable_id), constant(2)).sources).to eq([champ.stable_id]) }
@ -32,7 +32,10 @@ end
describe Logic::GreaterThan do describe Logic::GreaterThan do
include Logic include Logic
let(:champ) { create(:champ_integer_number, value: nil) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :integer_number }]) }
let(:tdc) { procedure.active_revision.types_de_champ.first }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) }
it 'computes' do it 'computes' do
expect(greater_than(constant(1), constant(1)).compute).to be(false) expect(greater_than(constant(1), constant(1)).compute).to be(false)
@ -43,8 +46,6 @@ end
describe Logic::GreaterThanEq do describe Logic::GreaterThanEq do
include Logic include Logic
let(:champ) { create(:champ_integer_number, value: nil) }
it 'computes' do it 'computes' do
expect(greater_than_eq(constant(0), constant(1)).compute).to be(false) expect(greater_than_eq(constant(0), constant(1)).compute).to be(false)
expect(greater_than_eq(constant(1), constant(1)).compute).to be(true) expect(greater_than_eq(constant(1), constant(1)).compute).to be(true)

View file

@ -2,11 +2,18 @@ describe Logic::ChampValue do
include Logic include Logic
describe '#compute' do describe '#compute' do
let(:procedure) { create(:procedure, types_de_champ_public: [{ type: tdc_type, drop_down_other: }]) }
let(:drop_down_other) { nil }
let(:tdc_type) { :text }
let(:tdc) { procedure.active_revision.types_de_champ.first }
let(:dossier) { create(:dossier, procedure:) }
subject { champ_value(champ.stable_id).compute([champ]) } subject { champ_value(champ.stable_id).compute([champ]) }
context 'yes_no tdc' do context 'yes_no tdc' do
let(:tdc_type) { :yes_no }
let(:champ) { Champs::YesNoChamp.new(value: value, stable_id: tdc.stable_id, dossier:) }
let(:value) { 'true' } let(:value) { 'true' }
let(:champ) { create(:champ_yes_no, value: value) }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) }
@ -30,92 +37,117 @@ describe Logic::ChampValue do
end end
context 'integer tdc' do context 'integer tdc' do
let(:champ) { create(:champ_integer_number, value: '42') } let(:tdc_type) { :integer_number }
let(:champ) { Champs::IntegerNumberChamp.new(value:, stable_id: tdc.stable_id, dossier:) }
let(:value) { '42' }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) }
it { is_expected.to eq(42) } it { is_expected.to eq(42) }
context 'with a blank value' do context 'with a blank value' do
let(:champ) { create(:champ_integer_number, value: '') } let(:value) { '' }
it { is_expected.to be nil } it { is_expected.to be nil }
end end
end end
context 'decimal tdc' do context 'decimal tdc' do
let(:champ) { create(:champ_decimal_number, value: '42.01') } let(:tdc_type) { :decimal_number }
let(:champ) { Champs::DecimalNumberChamp.new(value:, stable_id: tdc.stable_id, dossier:) }
let(:value) { '42.01' }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:number) }
it { is_expected.to eq(42.01) } it { is_expected.to eq(42.01) }
end end
context 'dropdown tdc' do context 'dropdown tdc' do
let(:champ) { create(:champ_drop_down_list, value: 'val1') } let(:tdc_type) { :drop_down_list }
let(:champ) { Champs::DropDownListChamp.new(value:, other:, stable_id: tdc.stable_id, dossier:) }
let(:value) { 'val1' }
let(:other) { nil }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:enum) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:enum) }
it { is_expected.to eq('val1') } it { is_expected.to eq('val1') }
it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"]]) } it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"]]) }
context 'with other enabled' do context 'with other enabled' do
let(:champ) { create(:champ_drop_down_list, value: 'val1', other: true) } let(:tdc_type) { :drop_down_list }
let(:drop_down_other) { true }
it { is_expected.to eq('val1') } it { is_expected.to eq('val1') }
it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"], ["Autre", "__other__"]]) } it { expect(champ_value(champ.stable_id).options([champ.type_de_champ])).to match_array([["val1", "val1"], ["val2", "val2"], ["val3", "val3"], ["Autre", "__other__"]]) }
end
context 'with other filled' do context 'with other filled' do
let(:champ) { create(:champ_drop_down_list, value: 'other value', other: true) } let(:other) { true }
it { is_expected.to eq(Champs::DropDownListChamp::OTHER) } it { is_expected.to eq(Champs::DropDownListChamp::OTHER) }
end
end end
end end
context 'checkbox tdc' do context 'checkbox tdc' do
let(:champ) { create(:champ_checkbox, value: 'true') } let(:tdc_type) { :checkbox }
let(:champ) { Champs::CheckboxChamp.new(value:, stable_id: tdc.stable_id, dossier:) }
let(:value) { 'true' }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:boolean) }
it { is_expected.to eq(true) } it { is_expected.to eq(true) }
end end
context 'departement tdc' do context 'departement tdc' do
let(:champ) { create(:champ_departements, value: '02') } let(:tdc_type) { :departements }
let(:champ) { Champs::DepartementChamp.new(value:, stable_id: tdc.stable_id, dossier:) }
let(:value) { '02' }
it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:departement_enum) } it { expect(champ_value(champ.stable_id).type([champ.type_de_champ])).to eq(:departement_enum) }
it { is_expected.to eq({ value: '02', code_region: '32' }) } it { is_expected.to eq({ value: '02', code_region: '32' }) }
end end
context 'region tdc' do context 'region tdc' do
let(:champ) { create(:champ_regions, value: 'La Réunion') } let(:tdc_type) { :regions }
let(:champ) { Champs::RegionChamp.new(value:, stable_id: tdc.stable_id, dossier:) }
let(:value) { 'La Réunion' }
it { is_expected.to eq('04') } it { is_expected.to eq('04') }
end end
context 'commune tdc' do context 'commune tdc' do
let(:champ) { create(:champ_communes, code_postal: '92500', external_id: '92063') } let(:tdc_type) { :communes }
let(:champ) do
Champs::CommuneChamp.new(code_postal:, external_id:, stable_id: tdc.stable_id, dossier:)
.tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute
end
let(:code_postal) { '92500' }
let(:external_id) { '92063' }
it { is_expected.to eq({ code_departement: '92', code_region: '11' }) } it do
is_expected.to eq({ code_departement: '92', code_region: '11' })
end
end end
context 'epci tdc' do context 'epci tdc' do
let(:champ) { build(:champ_epci, code_departement: '43') } let(:tdc_type) { :epci }
let(:champ) do
before do Champs::EpciChamp.new(code_departement:, external_id:, stable_id: tdc.stable_id, dossier:)
champ.save! .tap { |c| c.send(:on_epci_name_changes) } # private method called before save to fill value, which is required for compute
champ.update_columns(external_id: '244301016', value: 'CC des Sucs')
end end
let(:code_departement) { '43' }
let(:external_id) { '244301016' }
it { is_expected.to eq({ code_departement: '43', code_region: '84' }) } it { is_expected.to eq({ code_departement: '43', code_region: '84' }) }
end end
describe 'errors' do describe 'errors' do
let(:champ) { create(:champ) } let(:tdc_type) { :number }
let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) }
it { expect(champ_value(champ.stable_id).errors([champ.type_de_champ])).to be_empty } it { expect(champ_value(champ.stable_id).errors([champ.type_de_champ])).to be_empty }
it { expect(champ_value(champ.stable_id).errors([])).to eq([{ type: :not_available }]) } it { expect(champ_value(champ.stable_id).errors([])).to eq([{ type: :not_available }]) }
end end
describe '#sources' do describe '#sources' do
let(:champ) { create(:champ) } let(:tdc_type) { :number }
let(:champ) { Champs::IntegerNumberChamp.new(value: nil, stable_id: tdc.stable_id, dossier:) }
it { expect(champ_value(champ.stable_id).sources).to eq([champ.stable_id]) } it { expect(champ_value(champ.stable_id).sources).to eq([champ.stable_id]) }
end end

View file

@ -1,7 +1,10 @@
describe Logic::ExcludeOperator do describe Logic::ExcludeOperator do
include Logic include Logic
let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :multiple_drop_down_list }]) }
let(:tdc) { procedure.active_revision.types_de_champ.first }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { Champs::MultipleDropDownListChamp.new(value: '["val1", "val2"]', stable_id: tdc.stable_id, dossier:) }
describe '#compute' do describe '#compute' do
it { expect(ds_exclude(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(false) } it { expect(ds_exclude(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(false) }

View file

@ -1,8 +1,22 @@
describe Logic::InDepartementOperator do describe Logic::InDepartementOperator do
include Logic include Logic
let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }]) }
let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } let(:dossier) { create(:dossier, procedure:) }
let(:tdc_commune) { procedure.active_revision.types_de_champ.first }
let(:champ_commune) do
Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:)
.tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute
end
let(:tdc_epci) { procedure.active_revision.types_de_champ.second }
let(:champ_epci) do
Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:)
.tap do |c|
c.send(:on_epci_name_changes)
end # private method called before save to fill value, which is required for compute
end
describe '#compute' do describe '#compute' do
context 'commune' do context 'commune' do
@ -11,8 +25,7 @@ describe Logic::InDepartementOperator do
context 'epci' do context 'epci' do
it do it do
champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") expect(ds_in_departement(champ_value(champ_epci.stable_id), constant('43')).compute([champ_epci])).to be(true)
expect(ds_in_departement(champ_value(champ_epci.stable_id), constant('02')).compute([champ_epci])).to be(true)
end end
end end
end end

View file

@ -1,9 +1,25 @@
describe Logic::InRegionOperator do describe Logic::InRegionOperator do
include Logic include Logic
let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }, { type: :departements }]) }
let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } let(:dossier) { create(:dossier, procedure:) }
let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') }
let(:tdc_commune) { procedure.active_revision.types_de_champ.first }
let(:champ_commune) do
Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:)
.tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute
end
let(:tdc_epci) { procedure.active_revision.types_de_champ.second }
let(:champ_epci) do
Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:)
.tap do |c|
c.send(:on_epci_name_changes)
end # private method called before save to fill value, which is required for compute
end
let(:tdc_departement) { procedure.active_revision.types_de_champ.third }
let(:champ_departement) { Champs::DepartementChamp.new(value: '01', stable_id: tdc_departement.stable_id, dossier:) }
describe '#compute' do describe '#compute' do
context 'commune' do context 'commune' do
@ -12,8 +28,7 @@ describe Logic::InRegionOperator do
context 'epci' do context 'epci' do
it do it do
champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") expect(ds_in_region(champ_value(champ_epci.stable_id), constant('84')).compute([champ_epci])).to be(true)
expect(ds_in_region(champ_value(champ_epci.stable_id), constant('32')).compute([champ_epci])).to be(true)
end end
end end

View file

@ -1,7 +1,10 @@
describe Logic::IncludeOperator do describe Logic::IncludeOperator do
include Logic include Logic
let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :multiple_drop_down_list }]) }
let(:tdc) { procedure.active_revision.types_de_champ.first }
let(:dossier) { create(:dossier, procedure:) }
let(:champ) { Champs::MultipleDropDownListChamp.new(value: '["val1", "val2"]', stable_id: tdc.stable_id, dossier:) }
describe '#compute' do describe '#compute' do
it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(true) } it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).compute([champ])).to be(true) }

View file

@ -1,8 +1,22 @@
describe Logic::NotInDepartementOperator do describe Logic::NotInDepartementOperator do
include Logic include Logic
let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }]) }
let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } let(:dossier) { create(:dossier, procedure:) }
let(:tdc_commune) { procedure.active_revision.types_de_champ.first }
let(:champ_commune) do
Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:)
.tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute
end
let(:tdc_epci) { procedure.active_revision.types_de_champ.second }
let(:champ_epci) do
Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:)
.tap do |c|
c.send(:on_epci_name_changes)
end # private method called before save to fill value, which is required for compute
end
describe '#compute' do describe '#compute' do
context 'commune' do context 'commune' do
@ -14,8 +28,7 @@ describe Logic::NotInDepartementOperator do
context 'epci' do context 'epci' do
it do it do
champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('43')).compute([champ_epci])).to be(false)
expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('02')).compute([champ_epci])).to be(false)
expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('03')).compute([champ_epci])).to be(true) expect(ds_not_in_departement(champ_value(champ_epci.stable_id), constant('03')).compute([champ_epci])).to be(true)
end end
end end

View file

@ -1,9 +1,29 @@
describe Logic::NotInRegionOperator do describe Logic::NotInRegionOperator do
include Logic include Logic
let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :communes }, { type: :epci }, { type: :departements }]) }
let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") } let(:dossier) { create(:dossier, procedure:) }
let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') }
let(:tdc_commune) { procedure.active_revision.types_de_champ.first }
let(:champ_commune) do
Champs::CommuneChamp.new(code_postal: '92500', external_id: '92063', stable_id: tdc_commune.stable_id, dossier:)
.tap { |c| c.send(:on_codes_change) } # private method called before save to fill value, which is required for compute
end
let(:tdc_epci) { procedure.active_revision.types_de_champ.second }
let(:champ_epci) do
Champs::EpciChamp.new(code_departement: '43', code_region: '32', external_id: '244301016', stable_id: tdc_epci.stable_id, dossier:)
.tap do |c|
c.send(:on_epci_name_changes)
end # private method called before save to fill value, which is required for compute
end
let(:tdc_departement) { procedure.active_revision.types_de_champ.third }
let(:champ_departement) { Champs::DepartementChamp.new(value: '01', stable_id: tdc_departement.stable_id, dossier:) }
# let(:champ_commune) { create(:champ_communes, code_postal: '92500', external_id: '92063') }
# let(:champ_epci) { create(:champ_epci, code_departement: '02', code_region: "32") }
# let(:champ_departement) { create(:champ_departements, value: '01', code_region: '84') }
describe '#compute' do describe '#compute' do
context 'commune' do context 'commune' do
@ -15,8 +35,7 @@ describe Logic::NotInRegionOperator do
context 'epci' do context 'epci' do
it do it do
champ_epci.update_columns(external_id: "200071991", value: "CC Retz en Valois") expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('84')).compute([champ_epci])).to be(false)
expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('32')).compute([champ_epci])).to be(false)
expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('11')).compute([champ_epci])).to be(true) expect(ds_not_in_region(champ_value(champ_epci.stable_id), constant('11')).compute([champ_epci])).to be(true)
end end
end end

View file

@ -135,11 +135,12 @@ RSpec.describe PrefillChamps do
let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first } let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first }
let(:type_de_champ_child_value) { "value" } let(:type_de_champ_child_value) { "value" }
let(:type_de_champ_child_value2) { "value2" } let(:type_de_champ_child_value2) { "value2" }
let(:child_champs) { dossier.champs.where(stable_id: type_de_champ_child.stable_id) }
let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } } let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } }
it "builds an array of hash(id, value) matching the given params" do it "builds an array of hash(id, value) matching the given params" do
expect(prefill_champs_array).to match([{ id: type_de_champ_child.champ.first.id, value: type_de_champ_child_value }, { id: type_de_champ_child.champ.second.id, value: type_de_champ_child_value2 }]) expect(prefill_champs_array).to match([{ id: child_champs.first.id, value: type_de_champ_child_value }, { id: child_champs.second.id, value: type_de_champ_child_value2 }])
end end
end end
@ -177,11 +178,12 @@ RSpec.describe PrefillChamps do
let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first } let(:type_de_champ_child) { procedure.published_revision.children_of(type_de_champ).first }
let(:type_de_champ_child_value) { "value" } let(:type_de_champ_child_value) { "value" }
let(:type_de_champ_child_value2) { "value2" } let(:type_de_champ_child_value2) { "value2" }
let(:child_champs) { dossier.champs.where(stable_id: type_de_champ_child.stable_id) }
let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } } let(:params) { { "champ_#{type_de_champ.to_typed_id_for_query}" => [{ "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value }, { "champ_#{type_de_champ_child.to_typed_id_for_query}" => type_de_champ_child_value2 }] } }
it "builds an array of hash(id, value) matching the given params" do it "builds an array of hash(id, value) matching the given params" do
expect(prefill_champs_array).to match([{ id: type_de_champ_child.champ.first.id, value: type_de_champ_child_value }, { id: type_de_champ_child.champ.second.id, value: type_de_champ_child_value2 }]) expect(prefill_champs_array).to match([{ id: child_champs.first.id, value: type_de_champ_child_value }, { id: child_champs.second.id, value: type_de_champ_child_value2 }])
end end
end end
@ -237,7 +239,7 @@ RSpec.describe PrefillChamps do
private private
def find_champ_by_stable_id(dossier, stable_id) def find_champ_by_stable_id(dossier, stable_id)
dossier.champs.joins(:type_de_champ).find_by(types_de_champ: { stable_id: stable_id }) dossier.champs.find_by(stable_id:)
end end
def attributes(champ, value) def attributes(champ, value)

View file

@ -595,8 +595,8 @@ describe ProcedurePresentation do
context 'with single value' do context 'with single value' do
before do before do
kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'keep me') kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'keep me')
discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'discard me') discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'discard me')
end end
it { is_expected.to contain_exactly(kept_dossier.id) } it { is_expected.to contain_exactly(kept_dossier.id) }
@ -613,9 +613,9 @@ describe ProcedurePresentation do
let(:other_kept_dossier) { create(:dossier, procedure: procedure) } let(:other_kept_dossier) { create(:dossier, procedure: procedure) }
before do before do
kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'keep me') kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'keep me')
discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'discard me') discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'discard me')
other_kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'and me too') other_kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'and me too')
end end
it 'returns every dossier that matches any of the search criteria for a given column' do it 'returns every dossier that matches any of the search criteria for a given column' do
@ -628,8 +628,8 @@ describe ProcedurePresentation do
let(:types_de_champ_public) { [{ type: :yes_no }] } let(:types_de_champ_public) { [{ type: :yes_no }] }
before do before do
kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'true') kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'true')
discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(value: 'false') discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(value: 'false')
end end
it { is_expected.to contain_exactly(kept_dossier.id) } it { is_expected.to contain_exactly(kept_dossier.id) }
@ -640,8 +640,8 @@ describe ProcedurePresentation do
let(:types_de_champ_public) { [{ type: :departements }] } let(:types_de_champ_public) { [{ type: :departements }] }
before do before do
kept_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(external_id: '13') kept_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(external_id: '13')
discarded_dossier.champs_public.find_by(type_de_champ: type_de_champ).update(external_id: '69') discarded_dossier.champs.find_by(stable_id: type_de_champ.stable_id).update(external_id: '69')
end end
it { is_expected.to contain_exactly(kept_dossier.id) } it { is_expected.to contain_exactly(kept_dossier.id) }
@ -656,8 +656,8 @@ describe ProcedurePresentation do
let(:type_de_champ_private) { procedure.active_revision.types_de_champ_private.first } let(:type_de_champ_private) { procedure.active_revision.types_de_champ_private.first }
before do before do
kept_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'keep me') kept_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'keep me')
discarded_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'discard me') discarded_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'discard me')
end end
it { is_expected.to contain_exactly(kept_dossier.id) } it { is_expected.to contain_exactly(kept_dossier.id) }
@ -673,7 +673,7 @@ describe ProcedurePresentation do
let(:other_kept_dossier) { create(:dossier, procedure: procedure) } let(:other_kept_dossier) { create(:dossier, procedure: procedure) }
before do before do
other_kept_dossier.champs_private.find_by(type_de_champ: type_de_champ_private).update(value: 'and me too') other_kept_dossier.champs.find_by(stable_id: type_de_champ_private.stable_id).update(value: 'and me too')
end end
it 'returns every dossier that matches any of the search criteria for a given column' do it 'returns every dossier that matches any of the search criteria for a given column' do

View file

@ -1584,12 +1584,15 @@ describe Procedure do
end end
describe '#average_dossier_weight' do describe '#average_dossier_weight' do
let(:procedure) { create(:procedure, :published) } let(:procedure) { create(:procedure, :published, types_de_champ_public: [{ type: :piece_justificative }]) }
before do before do
create_dossier_with_pj_of_size(4, procedure) create(:dossier, :accepte, :with_populated_champs, procedure:)
create_dossier_with_pj_of_size(5, procedure) create(:dossier, :accepte, :with_populated_champs, procedure:)
create_dossier_with_pj_of_size(6, procedure) create(:dossier, :accepte, :with_populated_champs, procedure:)
ActiveStorage::Blob.first.update!(byte_size: 4)
ActiveStorage::Blob.second.update!(byte_size: 5)
ActiveStorage::Blob.third.update!(byte_size: 6)
end end
it 'estimates average dossier weight' do it 'estimates average dossier weight' do

View file

@ -83,7 +83,7 @@ describe Stat, type: :model do
describe '.cumulative_hash' do describe '.cumulative_hash' do
it 'works count and cumulate counters by month for both dossier and deleted dossiers' do it 'works count and cumulate counters by month for both dossier and deleted dossiers' do
12.downto(1).map do |i| 2.downto(1).map do |i|
create(:dossier, state: :en_construction, depose_at: i.months.ago) create(:dossier, state: :en_construction, depose_at: i.months.ago)
create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago) create(:deleted_dossier, dossier_id: i + 100, state: :en_construction, deleted_at: i.month.ago)
end end
@ -98,18 +98,8 @@ describe Stat, type: :model do
s.reload s.reload
# Use `Hash#to_a` to also test the key ordering # Use `Hash#to_a` to also test the key ordering
expect(s.dossiers_cumulative.to_a).to eq([ expect(s.dossiers_cumulative.to_a).to eq([
[formatted_n_months_ago(12), 2], [formatted_n_months_ago(2), 2],
[formatted_n_months_ago(11), 4], [formatted_n_months_ago(1), 4]
[formatted_n_months_ago(10), 6],
[formatted_n_months_ago(9), 8],
[formatted_n_months_ago(8), 10],
[formatted_n_months_ago(7), 12],
[formatted_n_months_ago(6), 14],
[formatted_n_months_ago(5), 16],
[formatted_n_months_ago(4), 18],
[formatted_n_months_ago(3), 20],
[formatted_n_months_ago(2), 22],
[formatted_n_months_ago(1), 24]
]) ])
end end
end end

View file

@ -10,17 +10,12 @@ describe TypeDeChamp do
it { is_expected.not_to allow_value(nil).for(:type_champ) } it { is_expected.not_to allow_value(nil).for(:type_champ) }
it { is_expected.not_to allow_value('').for(:type_champ) } it { is_expected.not_to allow_value('').for(:type_champ) }
it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:text)).for(:type_champ) } let(:procedure) { create(:procedure, :with_all_champs) }
it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:textarea)).for(:type_champ) } let(:dossier) { create(:dossier, procedure:) }
it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:datetime)).for(:type_champ) }
it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:number)).for(:type_champ) }
it { is_expected.to allow_value(TypeDeChamp.type_champs.fetch(:checkbox)).for(:type_champ) }
it do it do
TypeDeChamp.type_champs.each do |(type_champ, _)| dossier.revision.types_de_champ_public.each do |type_de_champ|
type_de_champ = create(:"type_de_champ_#{type_champ}") champ = dossier.project_champ(type_de_champ, nil)
champ = type_de_champ.champ.create
expect(type_de_champ.dynamic_type.class.name).to match(/^TypesDeChamp::/) expect(type_de_champ.dynamic_type.class.name).to match(/^TypesDeChamp::/)
expect(champ.class.name).to match(/^Champs::/) expect(champ.class.name).to match(/^Champs::/)
end end

View file

@ -1,8 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe TypesDeChamp::PrefillAddressTypeDeChamp do RSpec.describe TypesDeChamp::PrefillAddressTypeDeChamp do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :address }]) }
let(:type_de_champ) { build(:type_de_champ_address, procedure: procedure) } let(:dossier) { create(:dossier, procedure:) }
let(:type_de_champ) { procedure.active_revision.types_de_champ.first }
describe 'ancestors' do describe 'ancestors' do
subject { described_class.new(type_de_champ, procedure.active_revision) } subject { described_class.new(type_de_champ, procedure.active_revision) }
@ -11,7 +12,7 @@ RSpec.describe TypesDeChamp::PrefillAddressTypeDeChamp do
end end
describe '#to_assignable_attributes' do describe '#to_assignable_attributes' do
let(:champ) { create(:champ_address, type_de_champ: type_de_champ) } let(:champ) { dossier.champs.first }
subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) } subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) }
context 'when the value is nil' do context 'when the value is nil' do

View file

@ -1,8 +1,9 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe TypesDeChamp::PrefillAnnuaireEducationTypeDeChamp do RSpec.describe TypesDeChamp::PrefillAnnuaireEducationTypeDeChamp do
let(:procedure) { create(:procedure) } let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :annuaire_education }]) }
let(:type_de_champ) { build(:type_de_champ_annuaire_education, procedure: procedure) } let(:dossier) { create(:dossier, procedure:) }
let(:type_de_champ) { procedure.active_revision.types_de_champ.first }
describe 'ancestors' do describe 'ancestors' do
subject { described_class.new(type_de_champ, procedure.active_revision) } subject { described_class.new(type_de_champ, procedure.active_revision) }
@ -11,7 +12,7 @@ RSpec.describe TypesDeChamp::PrefillAnnuaireEducationTypeDeChamp do
end end
describe '#to_assignable_attributes' do describe '#to_assignable_attributes' do
let(:champ) { create(:champ_annuaire_education, type_de_champ: type_de_champ) } let(:champ) { dossier.champs.first }
subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) } subject { described_class.build(type_de_champ, procedure.active_revision).to_assignable_attributes(champ, value) }
context 'when the value is nil' do context 'when the value is nil' do

Some files were not shown because too many files have changed in this diff Show more