diff --git a/app/javascript/controllers/select_champ_position_template_controller.ts b/app/javascript/controllers/select_champ_position_template_controller.ts index cd0523137dd..ebcbdd23e36 100644 --- a/app/javascript/controllers/select_champ_position_template_controller.ts +++ b/app/javascript/controllers/select_champ_position_template_controller.ts @@ -61,6 +61,7 @@ export class SelectChampPositionTemplateController extends ApplicationController if (stableIdDidChange) { changedSelectTarget.form?.requestSubmit(); } + event.stopImmediatePropagation(); } private getStableIdForSelect(select: HTMLSelectElement): string | null { diff --git a/spec/system/administrateurs/types_de_champ_spec.rb b/spec/system/administrateurs/types_de_champ_spec.rb index e86b0b77516..622e337dc35 100644 --- a/spec/system/administrateurs/types_de_champ_spec.rb +++ b/spec/system/administrateurs/types_de_champ_spec.rb @@ -234,37 +234,111 @@ end end - context 'move and morph champs' do - let(:procedure) { create(:procedure, types_de_champ_public: [{ type: :text, libelle: 'first_tdc' }, { type: :text, libelle: 'middle_tdc' }, { type: :text, libelle: 'last_tdc' }]) } - let!(:initial_first_coordinate) { procedure.draft_revision.revision_types_de_champ[0] } - let!(:initial_second_coordinate) { procedure.draft_revision.revision_types_de_champ[1] } - let!(:initial_third_coordinate) { procedure.draft_revision.revision_types_de_champ[2] } - # TODO: check no select when 1 champs - # TODO: check empty select when 1 champs - # TODO: check select is seeding on focus - # TODO: check select.change move champ and keep order - # TODO: select options are segmented by block - scenario 'root champs' do - initial_order = [initial_first_coordinate, initial_second_coordinate, initial_third_coordinate].map(&:stable_id) - initial_first_coordinate_selector = "##{ActionView::RecordIdentifier.dom_id(initial_first_coordinate, :move_and_morph)}" - # at first, select only contains the current coordinate - expect(page).to have_selector("#{initial_first_coordinate_selector} option", count: 1) - expect(page.find(initial_first_coordinate_selector).all("option").first.value.to_s).to eq(initial_first_coordinate.stable_id.to_s) - - # once clicked, the select is updated other options - page.find(initial_first_coordinate_selector).click - expect(page).to have_selector("#{initial_first_coordinate_selector} option", count: 4) - # also we re-hydrate the selected value - expect(page.find(initial_first_coordinate_selector).find("option[selected]").value.to_s).to eq(initial_first_coordinate.stable_id.to_s) - page.find(initial_first_coordinate_selector).select(initial_third_coordinate.libelle) - wait_until do - procedure.reload.draft_revision.revision_types_de_champ.last.type_de_champ.libelle == initial_first_coordinate.type_de_champ.libelle + context 'move and morph' do + let(:procedure) { create(:procedure, types_de_champ_public: tdcs) } + let!(:initial_first_coordinate) { procedure.draft_revision.revision_types_de_champ_public[0] } + let!(:initial_second_coordinate) { procedure.draft_revision.revision_types_de_champ_public[1] } + let!(:initial_third_coordinate) { procedure.draft_revision.revision_types_de_champ_public[2] } + + context 'with root champs' do + let(:tdcs) do + [ + { type: :text, libelle: 'first_tdc' }, + { type: :text, libelle: 'middle_tdc' }, + { type: :text, libelle: 'last_tdc' } + ] + end + let(:initial_first_coordinate_selector) { "##{ActionView::RecordIdentifier.dom_id(initial_first_coordinate, :move_and_morph)}"} + + scenario 'root select is empty by default' do + # at first, select only contains the current coordinate + expect(page).to have_selector("#{initial_first_coordinate_selector} option", count: 1) + expect(page.find(initial_first_coordinate_selector).all("option").first.value.to_s).to eq(initial_first_coordinate.stable_id.to_s) + end + + scenario 'when select is focused, it seeds its options' do + # once clicked, the select is updated with root champs options only, preselected on coordinates and have nice libelles + page.find(initial_first_coordinate_selector).click + expect(page).to have_selector("#{initial_first_coordinate_selector} option", count: 4) + expect(page.find(initial_first_coordinate_selector).find("option[selected]").value.to_s).to eq(initial_first_coordinate.stable_id.to_s) + expect(page.find(initial_first_coordinate_selector).all("option").map { _1.text }).to match_array(["Selectionner une option", '0 first_tdc', '1 middle_tdc', '2 last_tdc']) + + # renaming a tdc renames it's option + within "##{dom_id(initial_first_coordinate, :type_de_champ_editor)}" do + fill_in 'Libellé du champ', with: 'renamed' + end + wait_until { initial_first_coordinate.reload.libelle == 'renamed' } + page.find(initial_first_coordinate_selector).click + expect(page.find(initial_first_coordinate_selector).all("option").map { _1.text }).to match_array(["Selectionner une option", '0 renamed', '1 middle_tdc', '2 last_tdc']) + end + + scenario 'when select is changed, it move the coordinates' do + page.find(initial_first_coordinate_selector).click # seeds + page.find(initial_first_coordinate_selector).select(initial_third_coordinate.libelle) + wait_until do + procedure.reload.draft_revision.revision_types_de_champ.last.type_de_champ.libelle == initial_first_coordinate.type_de_champ.libelle + end + + # check reorder works on backend + reordered_coordinates = [initial_second_coordinate, initial_third_coordinate, initial_first_coordinate] + expect(procedure.reload.draft_revision.revision_types_de_champ.map(&:stable_id)).to eq(reordered_coordinates.map(&:stable_id)) + + # check reorder rerendered champ component between target->destination + reordered_coordinates.map do |coordinate| + expect(page).to have_selector("##{ActionView::RecordIdentifier.dom_id(coordinate, :type_de_champ_editor)} .position", text: coordinate.position) + end end - expect(procedure.reload.draft_revision.revision_types_de_champ.map(&:stable_id)) - .to eq([initial_second_coordinate, initial_third_coordinate, initial_first_coordinate].map(&:stable_id)) end - scenario 'repetition champs' do + + context 'with repetition champs' do + let(:tdcs) do + [ + { type: :text, libelle: 'root_first_tdc' }, + { + type: :repetition, + libelle: 'root_second_tdc', + children: [ + { type: :text, libelle: 'child_first_tdc' }, + { type: :text, libelle: 'child_second_tdc' } + ] + }, + { type: :text, libelle: 'root_thrid_tdc' } + ] + end + let(:children_coordinates) { procedure.draft_revision.revision_types_de_champ.filter { _1.parent.present? } } + let(:first_child_coordinate_selector) { "##{ActionView::RecordIdentifier.dom_id(children_coordinates.first, :move_and_morph)}" } + + scenario 'first child of repetition select is empty by default' do + expect(page).to have_selector("#{first_child_coordinate_selector} option", count: 1) + expect(page.find(first_child_coordinate_selector).all("option").first.value.to_s).to eq(children_coordinates.first.stable_id.to_s) + end + + scenario 'when first child select is focused, seed with repetition only tdcs' do + page.find(first_child_coordinate_selector).click + expect(page).to have_selector("#{first_child_coordinate_selector} option", count: 3) + + opts = page.find(first_child_coordinate_selector).all("option").map { _1.text } + expect(opts).to match_array(["Selectionner une option"] + children_coordinates.map{ "#{_1.position} #{_1.libelle}" }) + end + + scenario 'when first child select is changed, move champ in repetition' do + page.find(first_child_coordinate_selector).click + expect(children_coordinates.first.position).to eq(0) + page.find(first_child_coordinate_selector).select(children_coordinates.last.libelle) + # check reorder works on backend + wait_until do + children_coordinates.first.reload.position == 1 + end + + reordered_coordinates = children_coordinates.reverse + expect(procedure.reload.draft_revision.revision_types_de_champ.filter{ _1.parent.present? }.sort_by(&:position).map(&:stable_id)).to eq(reordered_coordinates.map(&:stable_id)) + + # check reorder rerendered champ component between target->destination + reordered_coordinates.map do |coordinate| + expect(page).to have_selector("##{ActionView::RecordIdentifier.dom_id(coordinate, :type_de_champ_editor)} .position", text: coordinate.position) + end + end end end end