Merge pull request #7544 from betagouv/types_de_champ_controller_manage_condition

feat: rajoute les conditions dans l'éditeur
This commit is contained in:
LeSim 2022-07-12 11:16:15 +02:00 committed by GitHub
commit b9945696f3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 419 additions and 138 deletions

View file

@ -1,3 +1,3 @@
%ul.types-de-champ-block{ id: block_id, data: sortable_options }
- @coordinates.each do |coordinate|
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate)
- @coordinates.each.with_index do |coordinate, i|
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, upper_coordinates: @coordinates.take(i))

View file

@ -1,12 +1,14 @@
class TypesDeChampEditor::ChampComponent < ApplicationComponent
def initialize(coordinate:, focused: false)
attr_reader :coordinate, :upper_coordinates
def initialize(coordinate:, upper_coordinates:, focused: false)
@coordinate = coordinate
@focused = focused
@upper_coordinates = upper_coordinates
end
private
attr_reader :coordinate
delegate :type_de_champ, :revision, :procedure, to: :coordinate
def can_be_mandatory?

View file

@ -83,3 +83,5 @@
.editor-block.flex-grow.cell
= render TypesDeChampEditor::BlockComponent.new(block: coordinate, coordinates: coordinate.revision_types_de_champ)
= render TypesDeChampEditor::AddChampButtonComponent.new(revision: coordinate.revision, parent: coordinate, is_annotation: coordinate.private?)
= render(TypesDeChampEditor::ConditionsComponent.new(tdc: type_de_champ, upper_tdcs: @upper_coordinates.map(&:type_de_champ), procedure_id: procedure.id))

View file

@ -201,7 +201,11 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
end
def render?
@condition.present? || available_targets_for_select.any?
if Flipper.enabled?(:conditional, controller.current_user)
@condition.present? || available_targets_for_select.any?
else
false
end
end
def input_name_for(name)

View file

@ -22,11 +22,11 @@ class TypesDeChampEditor::ConditionsErrorsComponent < ApplicationComponent
elsif left.type == :unmanaged
t('unmanaged', scope: '.errors',
libelle: targeted_champ.libelle,
type_champ: t(targeted_champ.type_champ, scope: '.type'))
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase)
else
t('incompatible', scope: '.errors',
libelle: targeted_champ.libelle,
type_champ: t(targeted_champ.type_champ, scope: '.type'),
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase,
operator: t(operator_name, scope: 'logic.operators').downcase,
right: right.to_s.downcase)
end

View file

@ -1,12 +1,6 @@
---
fr:
type:
number: un nombre
string: un texte
boolean: soit oui, soit non
yes_no: soit oui, soit non
address: une adresse
errors:
not_available: "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ."
unmanaged: "Le champ « %{libelle} » est %{type_champ} et ne peut pas être utilisé comme champ cible."
incompatible: "Le champ « %{libelle} » est %{type_champ}. Il ne peut pas être %{operator} %{right}."
unmanaged: "Le champ « %{libelle} » est de type « %{type_champ} » et ne peut pas être utilisé comme champ cible."
incompatible: "Le champ « %{libelle} » est de type « %{type_champ} ». Il ne peut pas être %{operator} %{right}."

View file

@ -6,54 +6,58 @@ module Administrateurs
def update
condition = condition_form.to_condition
tdc.update!(condition: condition)
@tdc.update!(condition: condition)
render 'administrateurs/types_de_champ/update.turbo_stream.haml'
@condition_component = build_condition_component
end
def add_row
condition = Logic.add_empty_condition_to(tdc.condition)
tdc.update!(condition: condition)
condition = Logic.add_empty_condition_to(@tdc.condition)
@tdc.update!(condition: condition)
render 'administrateurs/types_de_champ/update.turbo_stream.haml'
@condition_component = build_condition_component
end
def delete_row
condition = condition_form.delete_row(row_index).to_condition
tdc.update!(condition: condition)
@tdc.update!(condition: condition)
render 'administrateurs/types_de_champ/update.turbo_stream.haml'
@condition_component = build_condition_component
end
def destroy
tdc.update!(condition: nil)
@tdc.update!(condition: nil)
render 'administrateurs/types_de_champ/update.turbo_stream.haml'
@condition_component = build_condition_component
end
def change_targeted_champ
condition = condition_form.change_champ(row_index).to_condition
tdc.update!(condition: condition)
@tdc.update!(condition: condition)
render 'administrateurs/types_de_champ/update.turbo_stream.haml'
@condition_component = build_condition_component
end
private
def build_condition_component
TypesDeChampEditor::ConditionsComponent.new(
tdc: @tdc,
upper_tdcs: @upper_tdcs,
procedure_id: @procedure.id
)
end
def condition_form
ConditionForm.new(condition_params)
end
def retrieve_coordinate_and_uppers
@coordinate = draft_revision.coordinate_for(tdc)
@upper_coordinates = draft_revision
.revision_types_de_champ_public
.includes(:type_de_champ)
.take_while { |c| c != @coordinate }
end
def tdc
@tdc ||= draft_revision.find_and_ensure_exclusive_use(params[:stable_id])
@tdc = draft_revision.find_and_ensure_exclusive_use(params[:stable_id])
@coordinate = draft_revision.coordinate_for(@tdc)
@upper_tdcs = draft_revision
.upper_coordinates(@coordinate.position)
.map(&:type_de_champ)
end
def draft_revision

View file

@ -1,13 +1,15 @@
module Administrateurs
class TypesDeChampController < AdministrateurController
before_action :retrieve_procedure, only: [:create, :update, :move, :move_up, :move_down, :destroy]
before_action :procedure_revisable?, only: [:create, :update, :move, :move_up, :move_down, :destroy]
before_action :retrieve_procedure, :procedure_revisable?
def create
type_de_champ = @procedure.draft_revision.add_type_de_champ(type_de_champ_create_params)
type_de_champ = draft.add_type_de_champ(type_de_champ_create_params)
if type_de_champ.valid?
@coordinate = @procedure.draft_revision.coordinate_for(type_de_champ)
@coordinate = draft.coordinate_for(type_de_champ)
@created = champ_component_from(@coordinate, focused: true)
@morphed = champ_components_starting_at(@coordinate.position + 1)
reset_procedure
flash.notice = "Formulaire enregistré"
else
@ -16,12 +18,12 @@ module Administrateurs
end
def update
type_de_champ = @procedure.draft_revision.find_and_ensure_exclusive_use(params[:stable_id])
type_de_champ = draft.find_and_ensure_exclusive_use(params[:stable_id])
if type_de_champ.update(type_de_champ_update_params)
if params[:should_render]
@coordinate = @procedure.draft_revision.coordinate_for(type_de_champ)
end
@coordinate = draft.coordinate_for(type_de_champ)
@morphed = champ_components_starting_at(@coordinate.position)
reset_procedure
flash.notice = "Formulaire enregistré"
else
@ -31,27 +33,53 @@ module Administrateurs
def move
flash.notice = "Formulaire enregistré"
@procedure.draft_revision.move_type_de_champ(params[:stable_id], params[:position].to_i)
draft.move_type_de_champ(params[:stable_id], params[:position].to_i)
end
def move_up
flash.notice = "Formulaire enregistré"
@coordinate = @procedure.draft_revision.move_up_type_de_champ(params[:stable_id])
@coordinate = draft.move_up_type_de_champ(params[:stable_id])
@destroyed = @coordinate
@created = champ_component_from(@coordinate)
# update the one component below
@morphed = champ_components_starting_at(@coordinate.position + 1).take(1)
end
def move_down
flash.notice = "Formulaire enregistré"
@coordinate = @procedure.draft_revision.move_down_type_de_champ(params[:stable_id])
@coordinate = draft.move_down_type_de_champ(params[:stable_id])
@destroyed = @coordinate
@created = champ_component_from(@coordinate)
# update the one component above
@morphed = champ_components_starting_at(@coordinate.position - 1).take(1)
end
def destroy
@coordinate = @procedure.draft_revision.remove_type_de_champ(params[:stable_id])
@coordinate = draft.remove_type_de_champ(params[:stable_id])
reset_procedure
flash.notice = "Formulaire enregistré"
@destroyed = @coordinate
@morphed = champ_components_starting_at(@coordinate.position)
end
private
def champ_components_starting_at(position)
draft
.coordinates_starting_at(position)
.lazy
.map { |c| champ_component_from(c) }
end
def champ_component_from(coordinate, focused: false)
TypesDeChampEditor::ChampComponent.new(
coordinate: coordinate,
upper_coordinates: draft.upper_coordinates(coordinate.position),
focused: focused
)
end
def type_de_champ_create_params
params
.required(:type_de_champ)
@ -82,5 +110,9 @@ module Administrateurs
:znieff
])
end
def draft
@procedure.draft_revision
end
end
end

View file

@ -33,10 +33,10 @@ class Logic::ChampValue < Logic::Term
end
end
def to_s = "#{type_de_champ.libelle}#{stable_id}"
def to_s = "#{type_de_champ&.libelle}#{stable_id}" # TODO: gerer le cas ou un tdc est supprimé
def type
case type_de_champ.type_champ
case type_de_champ&.type_champ # TODO: gerer le cas ou un tdc est supprimé
when MANAGED_TYPE_DE_CHAMP.fetch(:yes_no),
MANAGED_TYPE_DE_CHAMP.fetch(:checkbox)
CHAMP_VALUE_TYPE.fetch(:boolean)

View file

@ -59,7 +59,7 @@ class ProcedureRevision < ApplicationRecord
h = { type_de_champ: tdc, parent_id: parent_id, position: position }
coordinate = revision_types_de_champ.create!(h)
reorder(coordinate.reload.siblings)
renumber(coordinate.reload.siblings)
end
# they are not aware of the addition
@ -88,7 +88,7 @@ class ProcedureRevision < ApplicationRecord
siblings.insert(position, siblings.delete_at(siblings.index(coordinate)))
reorder(siblings)
renumber(siblings)
coordinate.reload
coordinate
@ -107,7 +107,7 @@ class ProcedureRevision < ApplicationRecord
types_de_champ_public.reset
types_de_champ_private.reset
reorder(coordinate.siblings)
renumber(coordinate.siblings)
coordinate
end
@ -197,6 +197,14 @@ class ProcedureRevision < ApplicationRecord
revision_types_de_champ.find_by!(type_de_champ: tdc)
end
def upper_coordinates(position)
revision_types_de_champ_public.filter { |c| c.position < position }
end
def coordinates_starting_at(position)
revision_types_de_champ_public.reload.filter { |c| position <= c.position }
end
private
def compute_estimated_fill_duration
@ -221,10 +229,10 @@ class ProcedureRevision < ApplicationRecord
.joins(:type_de_champ)
.find_by(type_de_champ: { stable_id: stable_id })
[coordinate, coordinate.type_de_champ]
[coordinate, coordinate&.type_de_champ]
end
def reorder(siblings)
def renumber(siblings)
siblings.to_a.compact.each.with_index do |sibling, position|
sibling.update_column(:position, position)
end
@ -482,7 +490,8 @@ class ProcedureRevision < ApplicationRecord
types_de_champ_public
.map.with_index
.filter_map { |tdc, i| tdc.condition.present? ? [tdc, i] : nil }
.flat_map { |tdc, i| tdc.condition.errors(stable_ids.take(i)) }
.each { |message| errors.add(:condition, message) }
.map { |tdc, i| [tdc, tdc.condition.errors(stable_ids.take(i))] }
.filter { |_tdc, errors| errors.present? }
.each { |tdc, message| errors.add(:condition, message, type_de_champ: tdc) }
end
end

View file

@ -0,0 +1,8 @@
- rendered = render @condition_component
- if rendered.present?
= turbo_stream.morph dom_id(@tdc, :conditions) do
- rendered
end
- else
= turbo_stream.remove dom_id(@tdc, :conditions)

View file

@ -0,0 +1 @@
= render partial: 'update'

View file

@ -0,0 +1 @@
= render partial: 'update'

View file

@ -0,0 +1 @@
= render partial: 'update'

View file

@ -0,0 +1 @@
= render partial: 'update'

View file

@ -0,0 +1 @@
= render partial: 'update'

View file

@ -1,9 +1,19 @@
- sibling = coordinate.previous_sibling
- if @destroyed.present?
= turbo_stream.remove dom_id(@destroyed, :type_de_champ_editor)
- if @created.present?
- if @created.coordinate.previous_sibling.present?
= turbo_stream.after dom_id(@created.coordinate.previous_sibling, :type_de_champ_editor) do
= render @created
- else
= turbo_stream.prepend dom_id(@created.coordinate.block, :types_de_champ_editor_block) do
= render @created
- @morphed&.each do |champ_component|
= turbo_stream.morph dom_id(champ_component.coordinate, :type_de_champ_editor) do
= render champ_component
= turbo_stream.morph dom_id(@coordinate.revision, :estimated_fill_duration) do
= render TypesDeChampEditor::EstimatedFillDurationComponent.new(revision: @coordinate.revision, is_annotation: @coordinate.private?)
- if sibling.present?
= turbo_stream.after dom_id(sibling, :type_de_champ_editor) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, focused: true)
- else
= turbo_stream.prepend dom_id(coordinate.block, :types_de_champ_editor_block) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: coordinate, focused: true)
= turbo_stream.dispatch 'sortable:sort'

View file

@ -1,2 +1 @@
- if @coordinate&.type_de_champ&.valid?
= render partial: 'insert', locals: { coordinate: @coordinate }
= render partial: 'insert'

View file

@ -1,4 +1 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= turbo_stream.dispatch 'sortable:sort'
= turbo_stream.morph dom_id(@coordinate.revision, :estimated_fill_duration) do
= render TypesDeChampEditor::EstimatedFillDurationComponent.new(revision: @coordinate.revision, is_annotation: @coordinate.private?)
= render partial: 'insert'

View file

@ -1,2 +1 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= render partial: 'insert', locals: { coordinate: @coordinate }
= render partial: 'insert'

View file

@ -1,2 +1 @@
= turbo_stream.remove dom_id(@coordinate, :type_de_champ_editor)
= render partial: 'insert', locals: { coordinate: @coordinate }
= render partial: 'insert'

View file

@ -1,5 +1 @@
- if @coordinate&.type_de_champ&.valid?
= turbo_stream.morph dom_id(@coordinate, :type_de_champ_editor) do
= render TypesDeChampEditor::ChampComponent.new(coordinate: @coordinate)
= turbo_stream.morph dom_id(@coordinate.revision, :estimated_fill_duration) do
= render TypesDeChampEditor::EstimatedFillDurationComponent.new(revision: @coordinate.revision, is_annotation: @coordinate.private?)
= render partial: 'insert'

View file

@ -1,6 +1,12 @@
describe TypesDeChampEditor::ConditionsComponent, type: :component do
include Logic
# TODO: remove along with feature flipping
before do
allow_any_instance_of(ApplicationController).to receive(:current_user).and_return(nil)
allow(Flipper).to receive(:enabled?).with(:conditional, anything).and_return(true)
end
describe 'render' do
let(:tdc) { create(:type_de_champ, condition: condition) }
let(:condition) { nil }

View file

@ -5,9 +5,7 @@ describe Administrateurs::ConditionsController, type: :controller do
let(:first_coordinate) { procedure.draft_revision.revision_types_de_champ.first }
let(:second_tdc) { procedure.draft_revision.types_de_champ.second }
before do
sign_in(procedure.administrateurs.first.user)
end
before { sign_in(procedure.administrateurs.first.user) }
let(:default_params) do
{
@ -17,9 +15,7 @@ describe Administrateurs::ConditionsController, type: :controller do
end
describe '#update' do
before do
post :update, params: params
end
before { post :update, params: params, format: :turbo_stream }
let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) }
@ -38,26 +34,22 @@ describe Administrateurs::ConditionsController, type: :controller do
it do
expect(second_tdc.reload.condition).to eq(ds_eq(champ_value(1), constant(2)))
expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc))
expect(assigns(:upper_coordinates)).to eq([first_coordinate])
expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ])
end
end
describe '#add_row' do
before do
post :add_row, params: default_params
end
before { post :add_row, params: default_params, format: :turbo_stream }
it do
expect(second_tdc.reload.condition).to eq(empty_operator(empty, empty))
expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc))
expect(assigns(:upper_coordinates)).to eq([first_coordinate])
expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ])
end
end
describe '#delete_row' do
before do
delete :delete_row, params: params.merge(row_index: 0)
end
before { delete :delete_row, params: params.merge(row_index: 0), format: :turbo_stream }
let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) }
@ -76,20 +68,20 @@ describe Administrateurs::ConditionsController, type: :controller do
it do
expect(second_tdc.reload.condition).to eq(nil)
expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc))
expect(assigns(:upper_coordinates)).to eq([first_coordinate])
expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ])
end
end
describe '#destroy' do
before do
second_tdc.update(condition: empty_operator(empty, empty))
delete :destroy, params: default_params
delete :destroy, params: default_params, format: :turbo_stream
end
it do
expect(second_tdc.reload.condition).to eq(nil)
expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc))
expect(assigns(:upper_coordinates)).to eq([first_coordinate])
expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ])
end
end
@ -98,7 +90,7 @@ describe Administrateurs::ConditionsController, type: :controller do
before do
second_tdc.update(condition: empty_operator(empty, empty))
patch :change_targeted_champ, params: params
patch :change_targeted_champ, params: params, format: :turbo_stream
end
let(:params) { default_params.merge(type_de_champ: { condition_form: condition_form }) }
@ -118,7 +110,7 @@ describe Administrateurs::ConditionsController, type: :controller do
it do
expect(second_tdc.reload.condition).to eq(ds_eq(champ_value(number_tdc.stable_id), constant(0)))
expect(assigns(:coordinate)).to eq(procedure.draft_revision.coordinate_for(second_tdc))
expect(assigns(:upper_coordinates)).to eq([first_coordinate])
expect(assigns(:upper_tdcs)).to eq([first_coordinate.type_de_champ])
end
end
end

View file

@ -1,65 +1,159 @@
describe Administrateurs::TypesDeChampController, type: :controller do
let(:admin) { create(:administrateur) }
let(:procedure) do
create(:procedure).tap do |p|
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l1')
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l2')
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'l3')
p.draft_revision.add_type_de_champ(type_champ: :yes_no, libelle: 'bon dossier', private: true)
end
end
describe '#types_de_champs editor' do
let(:procedure) { create(:procedure) }
def first_coordinate = procedure.draft_revision.revision_types_de_champ_public.first
def second_coordinate = procedure.draft_revision.revision_types_de_champ_public.reload.second
def third_coordinate = procedure.draft_revision.revision_types_de_champ_public.reload.third
before do
admin.procedures << procedure
sign_in(admin.user)
def extract_libelle(champ_component) = [champ_component.coordinate.libelle, champ_component.upper_coordinates.map(&:libelle)]
def morpheds
assigns(:morphed)
.map { |component| extract_libelle(component) }.to_a
end
before { sign_in(procedure.administrateurs.first.user) }
describe '#create' do
let(:params) { default_params }
let(:default_params) do
{
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'l1.5',
placeholder: "custom placeholder",
after_stable_id: first_coordinate.stable_id
}
}
end
let(:type_champ) { TypeDeChamp.type_champs.fetch(:text) }
subject { post :create, params: params, format: :turbo_stream }
context "create type_de_champ text" do
before do
post :create, params: {
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ',
private: false,
placeholder: "custom placeholder"
}
}, format: :turbo_stream
end
let(:type_champ) { TypeDeChamp.type_champs.fetch(:text) }
it { expect(response).to have_http_status(:ok) }
# l1, l2, l3 => l1, l1.5, l2, l3
# created: (l1.5, [l1]), morphed: (l2, [l1, l1.5]), (l3, [l1, l1.5, l2])
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
expect(assigns(:coordinate)).to eq(second_coordinate)
expect(extract_libelle(assigns(:created))).to eq(['l1.5', ['l1']])
expect(morpheds).to eq([['l2', ['l1', 'l1.5']], ['l3', ['l1', 'l1.5', 'l2']]])
end
end
context "validate type_de_champ linked_drop_down_list" do
let(:type_champ) { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
before do
post :create, params: {
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ',
private: false
}
}, format: :turbo_stream
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
end
it { expect(response).to have_http_status(:ok) }
end
context "create type_de_champ linked_drop_down_list" do
let(:type_champ) { TypeDeChamp.type_champs.fetch(:linked_drop_down_list) }
let(:params) { default_params.deep_merge(type_de_champ: { drop_down_list_value: '--value--' }) }
before do
post :create, params: {
procedure_id: procedure.id,
type_de_champ: {
type_champ: type_champ,
libelle: 'Nouveau champ',
drop_down_list_value: '--value--',
private: false
}
}, format: :turbo_stream
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
end
end
end
it { expect(response).to have_http_status(:ok) }
describe '#update' do
let(:params) do
{
procedure_id: procedure.id,
stable_id: second_coordinate.stable_id,
type_de_champ: {
libelle: 'updated'
}
}
end
subject { post :update, params: params, format: :turbo_stream }
# l1, l2, l3 => l1, updated, l3
# morphed: (updated, [l1]), (l3, [l1, updated])
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
expect(second_coordinate.libelle).to eq('updated')
expect(assigns(:coordinate)).to eq(second_coordinate)
expect(morpheds).to eq([['updated', ['l1']], ['l3', ['l1', 'updated']]])
end
end
# l1, l2, l3 => l1, l3, l2
# destroyed: l3, created: (l3, [l1]), morphed: (l2, [l1, l3])
describe '#move_up' do
let(:params) do
{ procedure_id: procedure.id, stable_id: third_coordinate.stable_id }
end
subject { patch :move_up, params: params, format: :turbo_stream }
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
expect(second_coordinate.libelle).to eq('l3')
expect(assigns(:coordinate)).to eq(second_coordinate)
expect(assigns(:destroyed).libelle).to eq('l3')
expect(extract_libelle(assigns(:created))).to eq(['l3', ['l1']])
expect(morpheds).to eq([['l2', ['l1', 'l3']]])
end
end
# l1, l2, l3 => l2, l1, l3
# destroyed: l1, created: (l1, [l2]), morphed: (l2, [])
describe '#move_down' do
let(:params) do
{ procedure_id: procedure.id, stable_id: first_coordinate.stable_id }
end
subject { patch :move_down, params: params, format: :turbo_stream }
it do
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
expect(assigns(:coordinate)).to eq(second_coordinate)
expect(assigns(:destroyed).libelle).to eq('l1')
expect(extract_libelle(assigns(:created))).to eq(['l1', ['l2']])
expect(morpheds).to eq([['l2', []]])
end
end
# l1, l2, l3 => l1, l3
# destroyed: l2, morphed: (l3, [l1])
describe '#destroy' do
let(:params) do
{ procedure_id: procedure.id, stable_id: second_coordinate.stable_id }
end
subject { delete :destroy, params: params, format: :turbo_stream }
it do
used_to_be_second_coordinate = second_coordinate
is_expected.to have_http_status(:ok)
expect(flash.alert).to eq(nil)
expect(assigns(:coordinate)).to eq(used_to_be_second_coordinate)
expect(assigns(:destroyed).libelle).to eq('l2')
expect(morpheds).to eq([['l3', ['l1']]])
end
end
end

View file

@ -0,0 +1,129 @@
describe 'As an administrateur I can edit types de champ condition', js: true do
include Logic
let(:administrateur) { procedure.administrateurs.first }
let(:procedure) do
create(:procedure).tap do |p|
p.draft_revision.add_type_de_champ(type_champ: :integer_number, libelle: 'age')
# private
p.draft_revision.add_type_de_champ(type_champ: :boolean, libelle: 'bon dossier', private: true)
p.draft_revision.add_type_de_champ(type_champ: :text, libelle: 'nom du parent')
end
end
let(:first_tdc) { procedure.draft_revision.types_de_champ.first }
let(:second_tdc) { procedure.draft_revision.types_de_champ.second }
before do
login_as administrateur.user, scope: :user
# TODO: remove along with feature flipping
allow(Flipper).to receive(:enabled?).with(:conditional, anything).and_return(true)
visit champs_admin_procedure_path(procedure)
end
scenario "adding a new condition" do
within '.type-de-champ:nth-child(2)' do
click_on 'cliquer pour activer'
within '.condition-table tbody tr:nth-child(1)' do
expect(page).to have_select('type_de_champ[condition_form][rows][][targeted_champ]', options: ['Sélectionner', 'age'])
within('.target') { select('age') }
within('.operator') { select('Supérieur ou égal à') }
within('.value') { fill_in with: 18 }
end
end
expected_condition = greater_than_eq(champ_value(first_tdc.stable_id), constant(18))
wait_until { second_tdc.reload.condition == expected_condition }
end
scenario "the first type de champ is removed" do
within '.type-de-champ:nth-child(1)' do
click_on 'Supprimer'
page.accept_alert
end
# the condition table is deleted
expect(page).to have_no_content('Logique conditionnelle')
end
context 'with a preexisting condition' do
before do
second_tdc.update(condition: greater_than_eq(champ_value(first_tdc.stable_id), constant(18)))
page.refresh
end
scenario "removing all conditions" do
within '.type-de-champ:nth-child(2)' do
click_on 'cliquer pour désactiver'
page.accept_alert
# the condition table is deleted
expect(page).to have_no_table
end
end
scenario "removing a condition" do
within '.type-de-champ:nth-child(2)' do
within '.condition-table tbody tr:nth-child(1)' do
within('.delete-column') { click_on 'Supprimer la ligne' }
end
# the condition table is deleted
expect(page).to have_no_table
end
end
scenario "adding a second row" do
within '.type-de-champ:nth-child(2)' do
click_on 'Ajouter une condition'
# the condition table has 2 rows
within '.condition-table tbody' do
expect(page).to have_selector('tr', count: 2)
end
end
end
scenario "changing target champ to a not managed type" do
expect(page).to have_no_selector('.condition-error')
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')
end
end
scenario "moving a target champ below the condition" do
expect(page).to have_no_selector('.condition-error')
within '.type-de-champ:nth-child(1)' do
click_on 'Déplacer le champ vers le bas'
end
# the now first champ has an error
within '.type-de-champ:nth-child(1)' do
expect(page).to have_selector('.condition-error')
end
end
scenario "moving the condition champ above the target" do
expect(page).to have_no_selector('.condition-error')
within '.type-de-champ:nth-child(2)' do
click_on 'Déplacer le champ vers le haut'
end
# the now first champ has an error
within '.type-de-champ:nth-child(1)' do
expect(page).to have_selector('.condition-error')
end
end
end
end