amelioration(editeur-de-champs): permet de choisir un niveau de titre (de 1 à 3) pour les champs de type Champs::HeaderSectionChamp. Gère les erreurs dans le cas ou un administrateur supprimerait un HeaderSection qui casserait l'ordre des titre [ex: titre 1,2,3. et l'admin supprime le titre 1 et il reste que 2,3].
This commit is contained in:
parent
38b806a1e0
commit
b9faa26560
27 changed files with 342 additions and 39 deletions
|
@ -1,17 +1,7 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
.conditionnel {
|
||||
|
||||
.condition-error {
|
||||
background: $background-red;
|
||||
margin: ($default-spacer) (-$default-spacer);
|
||||
|
||||
ul {
|
||||
padding: $default-spacer;
|
||||
}
|
||||
}
|
||||
|
||||
form.form > .conditionnel {
|
||||
.condition-table {
|
||||
table-layout: fixed;
|
||||
|
||||
|
|
12
app/assets/stylesheets/errors_summary.scss
Normal file
12
app/assets/stylesheets/errors_summary.scss
Normal file
|
@ -0,0 +1,12 @@
|
|||
@import "colors";
|
||||
@import "constants";
|
||||
|
||||
.errors-summary {
|
||||
background: $background-red;
|
||||
margin: ($default-spacer) (-$default-spacer);
|
||||
|
||||
ul {
|
||||
padding: $default-spacer;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
%h2.header-section{ class: @champ.dossier.auto_numbering_section_headers_for?(@champ) ? "header-section-counter" : nil }
|
||||
= @champ.libelle
|
|
@ -48,6 +48,11 @@
|
|||
.cell.mt-1
|
||||
= form.label :description, "Description du champ (optionnel)", for: dom_id(type_de_champ, :description)
|
||||
= form.text_area :description, class: 'small-margin small width-100', rows: 3, id: dom_id(type_de_champ, :description)
|
||||
- if type_de_champ.header_section?
|
||||
.cell.mt-1
|
||||
= render TypesDeChampEditor::HeaderSectionComponent.new(form: form, tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ))
|
||||
|
||||
|
||||
|
||||
.flex.justify-start.mt-1
|
||||
- if type_de_champ.drop_down_list?
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
.flex.justify-start.section{ id: dom_id(@tdc.stable_self, :conditions) }
|
||||
.flex.justify-start.section{ id: dom_id(@tdc.stable_self, :condition) }
|
||||
= form_tag admin_procedure_condition_path(@procedure_id, @tdc.stable_id), method: :patch, class: 'form width-100' do
|
||||
.conditionnel.mt-2.width-100
|
||||
.flex
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
.condition-error
|
||||
.errors-summary
|
||||
= errors
|
||||
|
|
|
@ -3,16 +3,32 @@ class TypesDeChampEditor::ErrorsSummary < ApplicationComponent
|
|||
@revision = revision
|
||||
end
|
||||
|
||||
def invalid?
|
||||
@revision.invalid?
|
||||
end
|
||||
|
||||
def condition_errors?
|
||||
@revision.errors.include?(:condition)
|
||||
end
|
||||
|
||||
def header_section_errors?
|
||||
@revision.errors.include?(:header_section)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def error_message
|
||||
@revision.errors
|
||||
def errors_for(key)
|
||||
@revision.errors.filter { _1.attribute == key }
|
||||
end
|
||||
|
||||
def error_message_for(key)
|
||||
errors_for(key)
|
||||
.map { |error| error.options[:type_de_champ] }
|
||||
.map { |tdc| tag.li(tdc_anchor(tdc)) }
|
||||
.map { |tdc| tag.li(tdc_anchor(tdc, key)) }
|
||||
.then { |lis| tag.ul(lis.reduce(&:+)) }
|
||||
end
|
||||
|
||||
def tdc_anchor(tdc)
|
||||
tag.a(tdc.libelle, href: champs_admin_procedure_path(@revision.procedure_id, anchor: dom_id(tdc.stable_self, :conditions)), data: { turbo: false })
|
||||
def tdc_anchor(tdc, key)
|
||||
tag.a(tdc.libelle, href: champs_admin_procedure_path(@revision.procedure_id, anchor: dom_id(tdc.stable_self, key)), data: { turbo: false })
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
fr:
|
||||
fix:
|
||||
one: 'Corrigez le champ suivant :'
|
||||
other: 'Corrigez les champs suivants :'
|
||||
fix_conditional:
|
||||
one: 'La logique conditionnelle du champ suivant est invalide, veuillez la corriger :'
|
||||
other: 'La logique conditionnelle des champs suivants sont invalides, veuillez les corriger :'
|
||||
|
||||
fix_header_section:
|
||||
one: 'Le titre de section suivant est invalide, veuillez le corriger :'
|
||||
other: 'Les titres de section suivants sont invalides, veuillez les corriger :'
|
||||
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#errors-summary
|
||||
- if @revision.invalid?
|
||||
- if invalid?
|
||||
.card.warning
|
||||
.card-title La logique conditionnelle est devenue invalide
|
||||
.card-title Le formulaire contient des erreurs
|
||||
|
||||
%p.mb-2= t('.fix', count: @revision.errors.count)
|
||||
= error_message
|
||||
- if condition_errors?
|
||||
%p.mb-2= t('.fix_conditional', count: errors_for(:condition).size)
|
||||
= error_message_for(:condition)
|
||||
|
||||
- if header_section_errors?
|
||||
%p.mb-2= t('.fix_header_section', count: errors_for(:header_section).size)
|
||||
= error_message_for(:header_section)
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
class TypesDeChampEditor::HeaderSectionComponent < ApplicationComponent
|
||||
MAX_LEVEL = 3
|
||||
|
||||
def initialize(form:, tdc:, upper_tdcs:)
|
||||
@form = form
|
||||
@tdc = tdc
|
||||
@upper_tdcs = upper_tdcs
|
||||
end
|
||||
|
||||
def header_section_options_for_select
|
||||
closest_level = @tdc.previous_section_level(@upper_tdcs)
|
||||
next_level = [MAX_LEVEL, closest_level + 1].min
|
||||
|
||||
available_levels = (1..next_level).map(&method(:option_for_level))
|
||||
disabled_levels = errors? ? (next_level + 1..MAX_LEVEL).map(&method(:option_for_level)) : []
|
||||
options_for_select(
|
||||
available_levels + disabled_levels,
|
||||
disabled: disabled_levels.map(&:second),
|
||||
selected: @tdc.header_section_level_value
|
||||
)
|
||||
end
|
||||
|
||||
def errors
|
||||
@tdc.check_nesting(@upper_tdcs)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def option_for_level(level)
|
||||
[translate(".select_option", level: level), level]
|
||||
end
|
||||
|
||||
def errors?
|
||||
!errors.empty?
|
||||
end
|
||||
|
||||
def to_html_list(messages)
|
||||
messages
|
||||
.map { |message| tag.li(message) }
|
||||
.then { |lis| tag.ul(lis.reduce(&:+)) }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
en:
|
||||
select_option: "Header section %{level}"
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
fr:
|
||||
select_option: "Titre de niveau %{level}"
|
|
@ -0,0 +1,5 @@
|
|||
%div{ id: dom_id(@tdc.stable_self, :header_section) }
|
||||
- if errors?
|
||||
.errors-summary= to_html_list(errors)
|
||||
= @form.label :header_section_level, "Niveau du titre", for: dom_id(@tdc, :header_section_level)
|
||||
= @form.select :header_section_level, header_section_options_for_select, {}, id: dom_id(@tdc, :header_section_level)
|
|
@ -128,6 +128,7 @@ module Administrateurs
|
|||
:drop_down_secondary_description,
|
||||
:collapsible_explanation_enabled,
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level
|
||||
editable_options: [
|
||||
:cadastres,
|
||||
:unesco,
|
||||
|
|
|
@ -48,6 +48,8 @@ class Champ < ApplicationRecord
|
|||
:drop_down_secondary_description,
|
||||
:collapsible_explanation_enabled?,
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level,
|
||||
:current_section_level,
|
||||
:exclude_from_export?,
|
||||
:exclude_from_view?,
|
||||
:repetition?,
|
||||
|
|
|
@ -31,6 +31,7 @@ class ProcedureRevision < ApplicationRecord
|
|||
scope :ordered, -> { order(:created_at) }
|
||||
|
||||
validate :conditions_are_valid?
|
||||
validate :header_sections_are_valid?
|
||||
|
||||
delegate :path, to: :procedure, prefix: true
|
||||
|
||||
|
@ -401,4 +402,24 @@ class ProcedureRevision < ApplicationRecord
|
|||
.filter { |_tdc, errors| errors.present? }
|
||||
.each { |tdc, message| errors.add(:condition, message, type_de_champ: tdc) }
|
||||
end
|
||||
|
||||
def header_sections_are_valid?
|
||||
public_tdcs = types_de_champ_public.to_a
|
||||
|
||||
root_tdcs_errors = errors_for_header_sections_order(public_tdcs)
|
||||
repetition_tdcs_errors = public_tdcs
|
||||
.filter_map { _1.repetition? ? children_of(_1) : nil }
|
||||
.map { errors_for_header_sections_order(_1) }
|
||||
|
||||
repetition_tdcs_errors + root_tdcs_errors
|
||||
end
|
||||
|
||||
def errors_for_header_sections_order(tdcs)
|
||||
tdcs
|
||||
.map.with_index
|
||||
.filter_map { |tdc, i| tdc.header_section? ? [tdc, i] : nil }
|
||||
.map { |tdc, i| [tdc, tdc.check_nesting(tdcs.take(i))] }
|
||||
.filter { |_tdc, errors| errors.present? }
|
||||
.each { |tdc, message| errors.add(:header_section, message, type_de_champ: tdc) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -119,7 +119,8 @@ class TypeDeChamp < ApplicationRecord
|
|||
:drop_down_secondary_description,
|
||||
:drop_down_other,
|
||||
:collapsible_explanation_enabled,
|
||||
:collapsible_explanation_text
|
||||
:collapsible_explanation_text,
|
||||
:header_section_level
|
||||
|
||||
has_many :revision_types_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', dependent: :destroy, inverse_of: :type_de_champ
|
||||
has_one :revision_type_de_champ, -> { revision_ordered }, class_name: 'ProcedureRevisionTypeDeChamp', inverse_of: false
|
||||
|
@ -411,6 +412,35 @@ class TypeDeChamp < ApplicationRecord
|
|||
self.drop_down_options = parse_drop_down_list_value(value)
|
||||
end
|
||||
|
||||
def header_section_level_value
|
||||
header_section_level.presence || 1
|
||||
end
|
||||
|
||||
def previous_section_level(upper_tdcs)
|
||||
previous_header_section = upper_tdcs.reverse.find(&:header_section?)
|
||||
|
||||
return 0 if !previous_header_section
|
||||
previous_header_section.header_section_level_value.to_i
|
||||
end
|
||||
|
||||
def check_nesting(upper_tdcs)
|
||||
errs = []
|
||||
previous_level = previous_section_level(upper_tdcs)
|
||||
|
||||
current_level = header_section_level_value.to_i
|
||||
difference = current_level - previous_level
|
||||
if current_level > previous_level && difference != 1
|
||||
errs << I18n.t('activerecord.errors.type_de_champ.attributes.header_section_level.gap_error', level: current_level - previous_level - 1)
|
||||
end
|
||||
errs
|
||||
end
|
||||
|
||||
def current_section_level
|
||||
tdcs = private? ? revision.type_champs_private.to_a : revision.types_de_champ_public.to_a
|
||||
|
||||
previous_section_level(tdcs.take(tdcs.find_index(self)))
|
||||
end
|
||||
|
||||
def self.options_for_select?(type_champs)
|
||||
[
|
||||
TypeDeChamp.type_champs.fetch(:departements),
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
- rendered = render @condition_component
|
||||
|
||||
- if rendered.present?
|
||||
= turbo_stream.replace dom_id(@tdc.stable_self, :conditions) do
|
||||
= turbo_stream.replace dom_id(@tdc.stable_self, :condition) do
|
||||
- rendered
|
||||
- else
|
||||
= turbo_stream.remove dom_id(@tdc.stable_self, :conditions)
|
||||
= turbo_stream.remove dom_id(@tdc.stable_self, :condition)
|
||||
|
|
|
@ -50,3 +50,10 @@ en:
|
|||
pole_emploi: 'Pôle emploi status'
|
||||
mesri: "Data from Ministère de l’Enseignement Supérieur, de la Recherche et de l’Innovation"
|
||||
epci: "EPCI"
|
||||
errors:
|
||||
type_de_champ:
|
||||
attributes:
|
||||
header_section_level:
|
||||
gap_error: "An header section with %{level} is missing."
|
||||
|
||||
|
||||
|
|
|
@ -50,3 +50,8 @@ fr:
|
|||
pole_emploi: 'Situation Pôle emploi'
|
||||
mesri: "Données du Ministère de l’Enseignement Supérieur, de la Recherche et de l’Innovation"
|
||||
epci: "EPCI"
|
||||
errors:
|
||||
type_de_champ:
|
||||
attributes:
|
||||
header_section_level:
|
||||
gap_error: "Un titre de section avec le niveau %{level} est manquant."
|
||||
|
|
83
spec/components/header_section_component_spec.rb
Normal file
83
spec/components/header_section_component_spec.rb
Normal file
|
@ -0,0 +1,83 @@
|
|||
RSpec.describe TypesDeChampEditor::HeaderSectionComponent, type: :component do
|
||||
include ActionView::Context
|
||||
include ActionView::Helpers::FormHelper
|
||||
include ActionView::Helpers::FormOptionsHelper
|
||||
|
||||
let(:component) do
|
||||
cmp = nil
|
||||
form_for(tdc, url: '/') do |form|
|
||||
cmp = described_class.new(form: form, tdc: tdc, upper_tdcs: upper_tdcs)
|
||||
end
|
||||
cmp
|
||||
end
|
||||
subject { render_inline(component).to_html }
|
||||
|
||||
describe 'header_section_options_for_select' do
|
||||
context 'without upper tdc' do
|
||||
let(:tdc) { header.type_de_champ }
|
||||
let(:header) { build(:champ_header_section) }
|
||||
let(:upper_tdcs) { [] }
|
||||
|
||||
it 'allows up to level 1 header section' do
|
||||
expect(subject).to have_selector("option", count: 1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with upper tdc of level 1' do
|
||||
let(:tdc) { header.type_de_champ }
|
||||
let(:header) { build(:champ_header_section_level_1) }
|
||||
let(:upper_tdcs) { [build(:champ_header_section_level_1).type_de_champ] }
|
||||
|
||||
it 'allows up to level 2 header section' do
|
||||
expect(subject).to have_selector("option", count: 2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with upper tdc of level 2' do
|
||||
let(:tdc) { header.type_de_champ }
|
||||
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) }
|
||||
|
||||
it 'allows up to level 3 header section' do
|
||||
expect(subject).to have_selector("option", count: 3)
|
||||
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
|
||||
let(:tdc) { header.type_de_champ }
|
||||
let(:header) { build(:champ_header_section_level_2) }
|
||||
let(:upper_tdcs) { [] }
|
||||
|
||||
it 'includes disabled levels' do
|
||||
expect(subject).to have_selector("option", count: 3)
|
||||
expect(subject).to have_selector("option[disabled]", count: 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'errors' do
|
||||
let(:tdc) { header.type_de_champ }
|
||||
let(:header) { build(:champ_header_section_level_2) }
|
||||
let(:upper_tdcs) { [] }
|
||||
|
||||
it 'returns errors' do
|
||||
expect(subject).to have_selector('.errors-summary')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,7 +8,7 @@ describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do
|
|||
before { render_inline(described_class.new(conditions: conditions, upper_tdcs: upper_tdcs)) }
|
||||
|
||||
context 'when there are no condition' do
|
||||
it { expect(page).to have_no_css('.condition-error') }
|
||||
it { expect(page).to have_no_css('.errors-summary') }
|
||||
end
|
||||
|
||||
context 'when the targeted_champ is not available' do
|
||||
|
@ -16,7 +16,7 @@ describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do
|
|||
let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] }
|
||||
|
||||
it do
|
||||
expect(page).to have_css('.condition-error')
|
||||
expect(page).to have_css('.errors-summary')
|
||||
expect(page).to have_content("Un champ cible n'est plus disponible")
|
||||
end
|
||||
end
|
||||
|
@ -27,7 +27,7 @@ describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do
|
|||
let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] }
|
||||
|
||||
it do
|
||||
expect(page).to have_css('.condition-error')
|
||||
expect(page).to have_css('.errors-summary')
|
||||
expect(page).to have_content("Le champ « #{tdc.libelle} » est de type « adresse » et ne peut pas être utilisé comme champ cible.")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -137,6 +137,18 @@ FactoryBot.define 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' }
|
||||
end
|
||||
|
||||
factory :champ_explication, class: 'Champs::ExplicationChamp' do
|
||||
type_de_champ { association :type_de_champ_explication, procedure: dossier.procedure }
|
||||
|
|
|
@ -114,6 +114,20 @@ FactoryBot.define do
|
|||
factory :type_de_champ_header_section do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
end
|
||||
|
||||
factory :type_de_champ_header_section_level_1 do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
header_section_level { 1 }
|
||||
end
|
||||
factory :type_de_champ_header_section_level_2 do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
header_section_level { 2 }
|
||||
end
|
||||
factory :type_de_champ_header_section_level_3 do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:header_section) }
|
||||
header_section_level { 3 }
|
||||
end
|
||||
|
||||
factory :type_de_champ_explication do
|
||||
type_champ { TypeDeChamp.type_champs.fetch(:explication) }
|
||||
end
|
||||
|
|
|
@ -890,6 +890,24 @@ describe ProcedureRevision do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'header_sections_are_valid' do
|
||||
let(:procedure) do
|
||||
create(:procedure).tap do |p|
|
||||
p.draft_revision.add_type_de_champ(type_champ: :header_section, libelle: 'hs', header_section_level: '2')
|
||||
end
|
||||
end
|
||||
let(:draft_revision) { procedure.draft_revision }
|
||||
|
||||
subject do
|
||||
draft_revision.save
|
||||
draft_revision.errors
|
||||
end
|
||||
|
||||
it 'find error' do
|
||||
expect(subject.errors).not_to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
describe "#dependent_conditions" do
|
||||
include Logic
|
||||
|
||||
|
|
|
@ -87,19 +87,19 @@ describe 'As an administrateur I can edit types de champ condition', js: true do
|
|||
end
|
||||
|
||||
scenario "changing target champ to a not managed type" do
|
||||
expect(page).to have_no_selector('.condition-error')
|
||||
expect(page).to have_no_selector('.errors-summary')
|
||||
|
||||
within '.type-de-champ:nth-child(1)' do
|
||||
select('Départements', from: 'Type de champ')
|
||||
end
|
||||
|
||||
within '.type-de-champ:nth-child(2)' do
|
||||
expect(page).to have_selector('.condition-error')
|
||||
expect(page).to have_selector('.errors-summary')
|
||||
end
|
||||
end
|
||||
|
||||
scenario "moving a target champ below the condition" do
|
||||
expect(page).to have_no_selector('.condition-error')
|
||||
expect(page).to have_no_selector('.errors-summary')
|
||||
|
||||
within '.type-de-champ:nth-child(1)' do
|
||||
click_on 'Déplacer le champ vers le bas'
|
||||
|
@ -107,12 +107,12 @@ describe 'As an administrateur I can edit types de champ condition', js: true do
|
|||
|
||||
# the now first champ has an error
|
||||
within '.type-de-champ:nth-child(1)' do
|
||||
expect(page).to have_selector('.condition-error')
|
||||
expect(page).to have_selector('.errors-summary')
|
||||
end
|
||||
end
|
||||
|
||||
scenario "moving the condition champ above the target" do
|
||||
expect(page).to have_no_selector('.condition-error')
|
||||
expect(page).to have_no_selector('.errors-summary')
|
||||
|
||||
within '.type-de-champ:nth-child(2)' do
|
||||
click_on 'Déplacer le champ vers le haut'
|
||||
|
@ -120,7 +120,7 @@ describe 'As an administrateur I can edit types de champ condition', js: true do
|
|||
|
||||
# the now first champ has an error
|
||||
within '.type-de-champ:nth-child(1)' do
|
||||
expect(page).to have_selector('.condition-error')
|
||||
expect(page).to have_selector('.errors-summary')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
describe 'As an administrateur I can edit types de champ', js: true do
|
||||
include ActionView::RecordIdentifier
|
||||
|
||||
let(:administrateur) { procedure.administrateurs.first }
|
||||
let(:estimated_duration_visible) { true }
|
||||
let(:procedure) { create(:procedure, estimated_duration_visible:) }
|
||||
|
@ -192,4 +194,29 @@ describe 'As an administrateur I can edit types de champ', js: true do
|
|||
expect(page).not_to have_content('Durée de remplissage estimée')
|
||||
end
|
||||
end
|
||||
|
||||
context 'header section' do
|
||||
scenario 'invalid order, it pops up errors summary' do
|
||||
add_champ
|
||||
wait_until { procedure.active_revision.types_de_champ_public.size == 1 }
|
||||
first_header = procedure.active_revision.types_de_champ_public.first
|
||||
select('Titre de section', from: 'Type de champ')
|
||||
select('Titre de niveau 1', from: dom_id(first_header, :header_section_level))
|
||||
|
||||
add_champ
|
||||
wait_until { procedure.reload.active_revision.types_de_champ_public.count == 2 }
|
||||
second_header = procedure.active_revision.types_de_champ_public.last
|
||||
select('Titre de section', from: dom_id(second_header, :type_champ))
|
||||
select('Titre de niveau 2', from: dom_id(second_header, :header_section_level))
|
||||
|
||||
within(".types-de-champ-block li:first-child") do
|
||||
page.accept_alert do
|
||||
click_on 'Supprimer'
|
||||
end
|
||||
end
|
||||
|
||||
expect(page).to have_content("Le formulaire contient des erreurs")
|
||||
expect(page).to have_content("Le titre de section suivant est invalide, veuillez le corriger :")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue