diff --git a/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb b/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb index 904e05a40..a90b7a0f0 100644 --- a/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb +++ b/app/models/types_de_champ/linked_drop_down_list_type_de_champ.rb @@ -3,6 +3,8 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas delegate :drop_down_list, to: :@type_de_champ + validate :check_presence_of_primary_options + def primary_options primary_options = unpack_options.map(&:first) if primary_options.present? @@ -21,6 +23,12 @@ class TypesDeChamp::LinkedDropDownListTypeDeChamp < TypesDeChamp::TypeDeChampBas private + def check_presence_of_primary_options + if !PRIMARY_PATTERN.match?(drop_down_list.options.second) + errors.add(libelle, "doit commencer par une entrée de menu primaire de la forme --texte--") + end + end + def unpack_options _, *options = drop_down_list.options chunked = options.slice_before(PRIMARY_PATTERN) diff --git a/app/models/types_de_champ/type_de_champ_base.rb b/app/models/types_de_champ/type_de_champ_base.rb index a7053dc38..4f77596c3 100644 --- a/app/models/types_de_champ/type_de_champ_base.rb +++ b/app/models/types_de_champ/type_de_champ_base.rb @@ -1,6 +1,8 @@ class TypesDeChamp::TypeDeChampBase include ActiveModel::Validations + delegate :libelle, to: :@type_de_champ + def initialize(type_de_champ) @type_de_champ = type_de_champ end diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb index c208f5aac..363b79476 100644 --- a/spec/factories/type_de_champ.rb +++ b/spec/factories/type_de_champ.rb @@ -54,7 +54,7 @@ FactoryBot.define do end factory :type_de_champ_linked_drop_down_list do type_champ { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) } - drop_down_list { create(:drop_down_list) } + drop_down_list { create(:drop_down_list, value: "--primary--\nsecondary\n") } end factory :type_de_champ_pays do type_champ { TypeDeChamp.type_champs.fetch(:pays) } diff --git a/spec/models/types_de_champ/linked_drop_down_list_type_de_champ_spec.rb b/spec/models/types_de_champ/linked_drop_down_list_type_de_champ_spec.rb index f9bc0af6a..b7ee29bdf 100644 --- a/spec/models/types_de_champ/linked_drop_down_list_type_de_champ_spec.rb +++ b/spec/models/types_de_champ/linked_drop_down_list_type_de_champ_spec.rb @@ -1,12 +1,78 @@ require 'spec_helper' describe TypesDeChamp::LinkedDropDownListTypeDeChamp do + let(:drop_down_list) { build(:drop_down_list, value: menu_options) } + let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) } + + subject { type_de_champ.dynamic_type } + + describe 'validation' do + context 'It must start with one primary option' do + context 'valid menu' do + let(:menu_options) do + <<~END_OPTIONS + --Primary 1-- + secondary 1.1 + secondary 1.2 + --Primary 2-- + secondary 2.1 + secondary 2.2 + secondary 2.3 + END_OPTIONS + end + + it { is_expected.to be_valid } + end + + context 'degenerate but valid menu' do + let(:menu_options) do + <<~END_OPTIONS + --Primary 1-- + END_OPTIONS + end + + it { is_expected.to be_valid } + end + + context 'invalid menus' do + shared_examples 'missing primary option' do + it { is_expected.to be_invalid } + it do + subject.validate + expect(subject.errors.full_messages).to eq ["#{subject.libelle} doit commencer par une entrée de menu primaire de la forme --texte--"] + end + end + + context 'no primary option' do + let(:menu_options) do + <<~END_OPTIONS + secondary 1.1 + secondary 1.2 + END_OPTIONS + end + + it_should_behave_like 'missing primary option' + end + + context 'starting with secondary options' do + let(:menu_options) do + <<~END_OPTIONS + secondary 1.1 + secondary 1.2 + --Primary 2-- + secondary 2.1 + secondary 2.2 + secondary 2.3 + END_OPTIONS + end + + it_should_behave_like 'missing primary option' + end + end + end + end + describe '#unpack_options' do - let(:drop_down_list) { build(:drop_down_list, value: menu_options) } - let(:type_de_champ) { build(:type_de_champ_linked_drop_down_list, drop_down_list: drop_down_list) } - - subject { type_de_champ.dynamic_type } - context 'with no options' do let(:menu_options) { '' } it { expect(subject.secondary_options).to eq({}) }