Merge pull request #7767 from betagouv/condition_on_multiple_choice
feat(conditonal): ajoute l'operator d'inclusion dans une liste pour le conditionnel
This commit is contained in:
commit
0f2552d593
19 changed files with 211 additions and 35 deletions
|
@ -1,7 +1,7 @@
|
||||||
@import "colors";
|
@import "colors";
|
||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
.conditionnel {
|
form.form > .conditionnel {
|
||||||
|
|
||||||
.condition-error {
|
.condition-error {
|
||||||
background: $background-red;
|
background: $background-red;
|
||||||
|
@ -64,7 +64,7 @@
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
input[type=number] {
|
input[type=text] {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -119,6 +119,10 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
|
||||||
[t('is', scope: 'logic'), Eq.name],
|
[t('is', scope: 'logic'), Eq.name],
|
||||||
[t('is_not', scope: 'logic'), NotEq.name]
|
[t('is_not', scope: 'logic'), NotEq.name]
|
||||||
]
|
]
|
||||||
|
when ChampValue::CHAMP_VALUE_TYPE.fetch(:enums)
|
||||||
|
[
|
||||||
|
[t(IncludeOperator.name, scope: 'logic.operators'), IncludeOperator.name]
|
||||||
|
]
|
||||||
when ChampValue::CHAMP_VALUE_TYPE.fetch(:number)
|
when ChampValue::CHAMP_VALUE_TYPE.fetch(:number)
|
||||||
[Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq]
|
[Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq]
|
||||||
.map(&:name)
|
.map(&:name)
|
||||||
|
@ -151,7 +155,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
|
||||||
options_for_select(empty_target_for_select),
|
options_for_select(empty_target_for_select),
|
||||||
id: input_id_for('value', row_index)
|
id: input_id_for('value', row_index)
|
||||||
)
|
)
|
||||||
when :enum
|
when :enum, :enums
|
||||||
enums_for_select = left.options
|
enums_for_select = left.options
|
||||||
|
|
||||||
if right_invalid
|
if right_invalid
|
||||||
|
@ -165,7 +169,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
|
||||||
class: { alert: right_invalid }
|
class: { alert: right_invalid }
|
||||||
)
|
)
|
||||||
when :number
|
when :number
|
||||||
number_field_tag(
|
text_field_tag(
|
||||||
input_name_for('value'),
|
input_name_for('value'),
|
||||||
right.value,
|
right.value,
|
||||||
required: true,
|
required: true,
|
||||||
|
@ -173,7 +177,7 @@ class TypesDeChampEditor::ConditionsComponent < ApplicationComponent
|
||||||
class: { alert: right_invalid }
|
class: { alert: right_invalid }
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
number_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index))
|
text_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -7,28 +7,42 @@ class TypesDeChampEditor::ConditionsErrorsComponent < ApplicationComponent
|
||||||
|
|
||||||
def errors
|
def errors
|
||||||
@conditions
|
@conditions
|
||||||
.filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? }
|
.flat_map { |condition| condition.errors(@upper_tdcs.map(&:stable_id)) }
|
||||||
.map { |condition| row_error(Logic.split_condition(condition)) }
|
.map { |error| humanize(error) }
|
||||||
.uniq
|
.uniq
|
||||||
.map { |message| tag.li(message) }
|
.map { |message| tag.li(message) }
|
||||||
.then { |lis| tag.ul(lis.reduce(&:+)) }
|
.then { |lis| tag.ul(lis.reduce(&:+)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def row_error((left, operator_name, right))
|
def humanize(error)
|
||||||
targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == left.stable_id }
|
case error
|
||||||
|
in { type: :not_available }
|
||||||
if targeted_champ.nil?
|
|
||||||
t('not_available', scope: '.errors')
|
t('not_available', scope: '.errors')
|
||||||
elsif left.type == :unmanaged
|
in { type: :unmanaged, stable_id: stable_id }
|
||||||
t('unmanaged', scope: '.errors',
|
targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == stable_id }
|
||||||
|
t('unmanaged',
|
||||||
|
scope: '.errors',
|
||||||
libelle: targeted_champ.libelle,
|
libelle: targeted_champ.libelle,
|
||||||
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase)
|
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase)
|
||||||
else
|
in { type: :incompatible, stable_id: stable_id, right: right, operator_name: operator_name }
|
||||||
|
targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == stable_id }
|
||||||
t('incompatible', scope: '.errors',
|
t('incompatible', scope: '.errors',
|
||||||
libelle: targeted_champ.libelle,
|
libelle: targeted_champ.libelle,
|
||||||
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase,
|
type_champ: t(targeted_champ.type_champ, scope: 'activerecord.attributes.type_de_champ.type_champs')&.downcase,
|
||||||
operator: t(operator_name, scope: 'logic.operators').downcase,
|
operator: t(operator_name, scope: 'logic.operators').downcase,
|
||||||
right: right.to_s.downcase)
|
right: right.to_s.downcase)
|
||||||
|
in { type: :required_number, operator_name: operator_name }
|
||||||
|
t('required_number', scope: '.errors',
|
||||||
|
operator: t(operator_name, scope: 'logic.operators'))
|
||||||
|
in { type: :not_included, stable_id: stable_id, right: right }
|
||||||
|
targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == stable_id }
|
||||||
|
t('not_included', scope: '.errors',
|
||||||
|
libelle: targeted_champ.libelle,
|
||||||
|
right: right.to_s.downcase)
|
||||||
|
in { type: :required_list }
|
||||||
|
t('required_list', scope: '.errors')
|
||||||
|
else
|
||||||
|
nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
---
|
||||||
|
fr:
|
||||||
|
errors:
|
||||||
|
not_available: "A targeted field is not available."
|
||||||
|
unmanaged: "The field « %{libelle} » is a « %{type_champ} » and cannot be used as conditional source."
|
||||||
|
incompatible: "The field « %{libelle} » is a « %{type_champ} ». It cannot be %{operator} « %{right} »."
|
||||||
|
required_number: "« %{operator} » applies only to number."
|
||||||
|
required_list: "The « include » operator only applies to simple or multiple choice."
|
||||||
|
not_included: "« %{right} » is not included in « %{libelle} »."
|
|
@ -3,4 +3,7 @@ fr:
|
||||||
errors:
|
errors:
|
||||||
not_available: "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ."
|
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 de type « %{type_champ} » et ne peut pas être utilisé comme champ cible."
|
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}."
|
incompatible: "Le champ « %{libelle} » est de type « %{type_champ} ». Il ne peut pas être %{operator} « %{right} »."
|
||||||
|
required_number: "« %{operator} » ne s'applique qu'à des nombres."
|
||||||
|
required_list: "Lʼopérateur « inclus » ne s'applique qu'au choix simple ou multiple."
|
||||||
|
not_included: "« %{right} » ne fait pas partie de « %{libelle} »."
|
||||||
|
|
|
@ -8,7 +8,7 @@ module Logic
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.class_from_name(name)
|
def self.class_from_name(name)
|
||||||
[ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, And, Or]
|
[ChampValue, Constant, Empty, LessThan, LessThanEq, Eq, NotEq, GreaterThanEq, GreaterThan, EmptyOperator, IncludeOperator, And, Or]
|
||||||
.find { |c| c.name == name }
|
.find { |c| c.name == name }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ module Logic
|
||||||
operator_class = EmptyOperator
|
operator_class = EmptyOperator
|
||||||
in [:enum, _]
|
in [:enum, _]
|
||||||
operator_class = Eq
|
operator_class = Eq
|
||||||
|
in [:enums, _]
|
||||||
|
operator_class = IncludeOperator
|
||||||
in [:number, EmptyOperator]
|
in [:number, EmptyOperator]
|
||||||
operator_class = Eq
|
operator_class = Eq
|
||||||
in [:number, _]
|
in [:number, _]
|
||||||
|
@ -35,7 +37,7 @@ module Logic
|
||||||
Constant.new(true)
|
Constant.new(true)
|
||||||
when :empty
|
when :empty
|
||||||
Empty.new
|
Empty.new
|
||||||
when :enum
|
when :enum, :enums
|
||||||
Constant.new(left.options.first.second)
|
Constant.new(left.options.first.second)
|
||||||
when :number
|
when :number
|
||||||
Constant.new(0)
|
Constant.new(0)
|
||||||
|
@ -49,8 +51,8 @@ module Logic
|
||||||
case [left.type, right.type]
|
case [left.type, right.type]
|
||||||
in [a, ^a] # syntax for same type
|
in [a, ^a] # syntax for same type
|
||||||
true
|
true
|
||||||
in [:enum, :string]
|
in [:enum, :string] | [:enums, :string]
|
||||||
left.options.map(&:second).include?(right.value)
|
true
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
@ -84,6 +86,8 @@ module Logic
|
||||||
|
|
||||||
def less_than_eq(left, right) = Logic::LessThanEq.new(left, right)
|
def less_than_eq(left, right) = Logic::LessThanEq.new(left, right)
|
||||||
|
|
||||||
|
def ds_include(left, right) = Logic::IncludeOperator.new(left, right)
|
||||||
|
|
||||||
def constant(value) = Logic::Constant.new(value)
|
def constant(value) = Logic::Constant.new(value)
|
||||||
|
|
||||||
def champ_value(stable_id) = Logic::ChampValue.new(stable_id)
|
def champ_value(stable_id) = Logic::ChampValue.new(stable_id)
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Logic::BinaryOperator < Logic::Term
|
||||||
errors = []
|
errors = []
|
||||||
|
|
||||||
if @left.type != :number || @right.type != :number
|
if @left.type != :number || @right.type != :number
|
||||||
errors += ["les types sont incompatibles : #{self}"]
|
errors << { type: :required_number, operator_name: self.class.name }
|
||||||
end
|
end
|
||||||
|
|
||||||
errors + @left.errors(stable_ids) + @right.errors(stable_ids)
|
errors + @left.errors(stable_ids) + @right.errors(stable_ids)
|
||||||
|
|
|
@ -4,13 +4,15 @@ class Logic::ChampValue < Logic::Term
|
||||||
:checkbox,
|
:checkbox,
|
||||||
:integer_number,
|
:integer_number,
|
||||||
:decimal_number,
|
:decimal_number,
|
||||||
:drop_down_list
|
:drop_down_list,
|
||||||
|
:multiple_drop_down_list
|
||||||
)
|
)
|
||||||
|
|
||||||
CHAMP_VALUE_TYPE = {
|
CHAMP_VALUE_TYPE = {
|
||||||
boolean: :boolean,
|
boolean: :boolean, # from yes_no or checkbox champ
|
||||||
number: :number,
|
number: :number, # from integer or decimal number champ
|
||||||
enum: :enum,
|
enum: :enum, # a choice from a dropdownlist
|
||||||
|
enums: :enums, # multiple choice from a dropdownlist (multipledropdownlist)
|
||||||
empty: :empty,
|
empty: :empty,
|
||||||
unmanaged: :unmanaged
|
unmanaged: :unmanaged
|
||||||
}
|
}
|
||||||
|
@ -35,6 +37,8 @@ class Logic::ChampValue < Logic::Term
|
||||||
targeted_champ.for_api
|
targeted_champ.for_api
|
||||||
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
||||||
targeted_champ.selected
|
targeted_champ.selected
|
||||||
|
when MANAGED_TYPE_DE_CHAMP.fetch(:multiple_drop_down_list)
|
||||||
|
targeted_champ.selected_options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -49,6 +53,8 @@ class Logic::ChampValue < Logic::Term
|
||||||
CHAMP_VALUE_TYPE.fetch(:number)
|
CHAMP_VALUE_TYPE.fetch(:number)
|
||||||
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
when MANAGED_TYPE_DE_CHAMP.fetch(:drop_down_list)
|
||||||
CHAMP_VALUE_TYPE.fetch(:enum)
|
CHAMP_VALUE_TYPE.fetch(:enum)
|
||||||
|
when MANAGED_TYPE_DE_CHAMP.fetch(:multiple_drop_down_list)
|
||||||
|
CHAMP_VALUE_TYPE.fetch(:enums)
|
||||||
else
|
else
|
||||||
CHAMP_VALUE_TYPE.fetch(:unmanaged)
|
CHAMP_VALUE_TYPE.fetch(:unmanaged)
|
||||||
end
|
end
|
||||||
|
@ -56,7 +62,7 @@ class Logic::ChampValue < Logic::Term
|
||||||
|
|
||||||
def errors(stable_ids)
|
def errors(stable_ids)
|
||||||
if !stable_ids.include?(stable_id)
|
if !stable_ids.include?(stable_id)
|
||||||
["le type de champ stable_id=#{stable_id} n'est pas disponible"]
|
[{ type: :not_available }]
|
||||||
else
|
else
|
||||||
[]
|
[]
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,10 +2,24 @@ class Logic::Eq < Logic::BinaryOperator
|
||||||
def operation = :==
|
def operation = :==
|
||||||
|
|
||||||
def errors(stable_ids = [])
|
def errors(stable_ids = [])
|
||||||
errors = []
|
errors = [@left, @right]
|
||||||
|
.filter { |term| term.type == :unmanaged }
|
||||||
|
.map { |term| { type: :unmanaged, stable_id: term.stable_id } }
|
||||||
|
|
||||||
if !Logic.compatible_type?(@left, @right)
|
if !Logic.compatible_type?(@left, @right)
|
||||||
errors += ["les types sont incompatibles : #{self}"]
|
errors << {
|
||||||
|
type: :incompatible,
|
||||||
|
stable_id: @left.try(:stable_id),
|
||||||
|
right: @right,
|
||||||
|
operator_name: self.class.name
|
||||||
|
}
|
||||||
|
elsif @left.type == :enum &&
|
||||||
|
!left.options.map(&:second).include?(right.value)
|
||||||
|
errors << {
|
||||||
|
type: :not_included,
|
||||||
|
stable_id: @left.stable_id,
|
||||||
|
right: @right
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
errors + @left.errors(stable_ids) + @right.errors(stable_ids)
|
errors + @left.errors(stable_ids) + @right.errors(stable_ids)
|
||||||
|
|
29
app/models/logic/include_operator.rb
Normal file
29
app/models/logic/include_operator.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
class Logic::IncludeOperator < Logic::BinaryOperator
|
||||||
|
def operation = :include?
|
||||||
|
|
||||||
|
def errors(stable_ids = [])
|
||||||
|
result = []
|
||||||
|
|
||||||
|
if left_not_a_list?
|
||||||
|
result << { type: :required_list }
|
||||||
|
elsif right_value_not_in_list?
|
||||||
|
result << {
|
||||||
|
type: :not_included,
|
||||||
|
stable_id: @left.stable_id,
|
||||||
|
right: @right
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
result + @left.errors(stable_ids) + @right.errors(stable_ids)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def left_not_a_list?
|
||||||
|
@left.type != :enums
|
||||||
|
end
|
||||||
|
|
||||||
|
def right_value_not_in_list?
|
||||||
|
!@left.options.map(&:second).include?(@right.value)
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,3 +1,11 @@
|
||||||
|
= turbo_stream.replace 'breadcrumbs' , render(partial: 'administrateurs/breadcrumbs',
|
||||||
|
locals: { steps: [['Démarches', admin_procedures_path],
|
||||||
|
[@procedure.libelle.truncate_words(10), admin_procedure_path(@procedure)],
|
||||||
|
['Configuration des champs']],
|
||||||
|
preview: @procedure.draft_revision.valid? })
|
||||||
|
|
||||||
|
= turbo_stream.replace 'errors-summary', render(TypesDeChampEditor::ErrorsSummary.new(revision: @procedure.draft_revision))
|
||||||
|
|
||||||
- rendered = render @condition_component
|
- rendered = render @condition_component
|
||||||
|
|
||||||
- if rendered.present?
|
- if rendered.present?
|
||||||
|
|
|
@ -12,3 +12,4 @@ fr:
|
||||||
'Logic::And': Et
|
'Logic::And': Et
|
||||||
'Logic::Or': Ou
|
'Logic::Or': Ou
|
||||||
'Logic::NotEq': N'est pas
|
'Logic::NotEq': N'est pas
|
||||||
|
'Logic::IncludeOperator': Contient
|
||||||
|
|
|
@ -28,7 +28,7 @@ describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(page).to have_css('.condition-error')
|
expect(page).to have_css('.condition-error')
|
||||||
expect(page).to have_content("ne peut pas être utilisé")
|
expect(page).to have_content("Le champ « #{tdc.libelle} » est de type « adresse » et ne peut pas être utilisé comme champ cible.")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -37,7 +37,39 @@ describe TypesDeChampEditor::ConditionsErrorsComponent, type: :component do
|
||||||
let(:upper_tdcs) { [tdc] }
|
let(:upper_tdcs) { [tdc] }
|
||||||
let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant('a'))] }
|
let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant('a'))] }
|
||||||
|
|
||||||
it { expect(page).to have_content("Il ne peut pas être") }
|
it { expect(page).to have_content("Le champ « #{tdc.libelle} » est de type « nombre entier ». Il ne peut pas être égal à « a ».") }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a number operator is applied on not a number' do
|
||||||
|
let(:tdc) { create(:type_de_champ_multiple_drop_down_list) }
|
||||||
|
let(:upper_tdcs) { [tdc] }
|
||||||
|
let(:conditions) { [greater_than(champ_value(tdc.stable_id), constant('a text'))] }
|
||||||
|
|
||||||
|
it { expect(page).to have_content("« Supérieur à » ne s'applique qu'à des nombres.") }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the include operator is applied on a list' do
|
||||||
|
let(:tdc) { create(:type_de_champ_integer_number) }
|
||||||
|
let(:upper_tdcs) { [tdc] }
|
||||||
|
let(:conditions) { [ds_include(champ_value(tdc.stable_id), constant('a text'))] }
|
||||||
|
|
||||||
|
it { expect(page).to have_content("Lʼopérateur « inclus » ne s'applique qu'au choix simple ou multiple.") }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a choice is not in a drop_down' do
|
||||||
|
let(:tdc) { create(:type_de_champ_drop_down_list) }
|
||||||
|
let(:upper_tdcs) { [tdc] }
|
||||||
|
let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant('another choice'))] }
|
||||||
|
|
||||||
|
it { expect(page).to have_content("« another choice » ne fait pas partie de « #{tdc.libelle} ».") }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a choice is not in a multiple_drop_down' do
|
||||||
|
let(:tdc) { create(:type_de_champ_multiple_drop_down_list) }
|
||||||
|
let(:upper_tdcs) { [tdc] }
|
||||||
|
let(:conditions) { [ds_include(champ_value(tdc.stable_id), constant('another choice'))] }
|
||||||
|
|
||||||
|
it { expect(page).to have_content("« another choice » ne fait pas partie de « #{tdc.libelle} ».") }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,7 +16,7 @@ describe Logic::BinaryOperator do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#errors' do
|
describe '#errors' do
|
||||||
it { expect(greater_than(constant(1), constant(true)).errors).to eq(['les types sont incompatibles : (1 > Oui)']) }
|
it { expect(greater_than(constant(1), constant(true)).errors).to eq([{ operator_name: "Logic::GreaterThan", type: :required_number }]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,6 @@ describe Logic::ChampValue do
|
||||||
let(:champ) { create(:champ) }
|
let(:champ) { create(:champ) }
|
||||||
|
|
||||||
it { expect(champ_value(champ.stable_id).errors([champ.stable_id])).to be_empty }
|
it { expect(champ_value(champ.stable_id).errors([champ.stable_id])).to be_empty }
|
||||||
it { expect(champ_value(champ.stable_id).errors(['other stable ids'])).to eq(["le type de champ stable_id=#{champ.stable_id} n'est pas disponible"]) }
|
it { expect(champ_value(champ.stable_id).errors(['other stable ids'])).to eq([{ type: :not_available }]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,15 @@ describe Logic::Eq do
|
||||||
|
|
||||||
describe '#errors' do
|
describe '#errors' do
|
||||||
it { expect(ds_eq(constant(true), constant(true)).errors).to be_empty }
|
it { expect(ds_eq(constant(true), constant(true)).errors).to be_empty }
|
||||||
it { expect(ds_eq(constant(true), constant(1)).errors).to eq(["les types sont incompatibles : (Oui == 1)"]) }
|
it do
|
||||||
|
expected = {
|
||||||
|
operator_name: "Logic::Eq",
|
||||||
|
right: constant(1),
|
||||||
|
stable_id: nil,
|
||||||
|
type: :incompatible
|
||||||
|
}
|
||||||
|
expect(ds_eq(constant(true), constant(1)).errors).to eq([expected])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#==' do
|
describe '#==' do
|
||||||
|
|
29
spec/models/logic/include_operator_spec.rb
Normal file
29
spec/models/logic/include_operator_spec.rb
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
describe Logic::IncludeOperator do
|
||||||
|
include Logic
|
||||||
|
|
||||||
|
let(:champ) { create(:champ_multiple_drop_down_list, value: '["val1", "val2"]') }
|
||||||
|
|
||||||
|
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('something else')).compute([champ])).to be(false) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#errors' do
|
||||||
|
it { expect(ds_include(champ_value(champ.stable_id), constant('val1')).errors([champ.stable_id])).to be_empty }
|
||||||
|
it do
|
||||||
|
expected = {
|
||||||
|
right: constant('something else'),
|
||||||
|
stable_id: champ.stable_id,
|
||||||
|
type: :not_included
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(ds_include(champ_value(champ.stable_id), constant('something else')).errors([champ.stable_id])).to eq([expected])
|
||||||
|
end
|
||||||
|
|
||||||
|
it { expect(ds_include(constant(1), constant('val1')).errors).to eq([{ type: :required_list }]) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#==' do
|
||||||
|
it { expect(ds_include(champ_value(champ.stable_id), constant('val1'))).to eq(ds_include(champ_value(champ.stable_id), constant('val1'))) }
|
||||||
|
end
|
||||||
|
end
|
|
@ -8,7 +8,15 @@ describe Logic::NotEq do
|
||||||
|
|
||||||
describe '#errors' do
|
describe '#errors' do
|
||||||
it { expect(ds_not_eq(constant(true), constant(true)).errors).to be_empty }
|
it { expect(ds_not_eq(constant(true), constant(true)).errors).to be_empty }
|
||||||
it { expect(ds_not_eq(constant(true), constant(1)).errors).to eq(["les types sont incompatibles : (Oui != 1)"]) }
|
it do
|
||||||
|
expected = {
|
||||||
|
operator_name: "Logic::NotEq",
|
||||||
|
right: constant(1),
|
||||||
|
stable_id: nil,
|
||||||
|
type: :incompatible
|
||||||
|
}
|
||||||
|
expect(ds_not_eq(constant(true), constant(1)).errors).to eq([expected])
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#==' do
|
describe '#==' do
|
||||||
|
|
|
@ -49,6 +49,14 @@ describe Logic do
|
||||||
|
|
||||||
it { is_expected.to eq(ds_eq(champ_value(drop_down), constant(first_option))) }
|
it { is_expected.to eq(ds_eq(champ_value(drop_down), constant(first_option))) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when multiple dropdown empty operator true' do
|
||||||
|
let(:multiple_drop_down) { create(:type_de_champ_multiple_drop_down_list) }
|
||||||
|
let(:first_option) { multiple_drop_down.drop_down_list_enabled_non_empty_options.first }
|
||||||
|
let(:condition) { empty_operator(champ_value(multiple_drop_down), constant(true)) }
|
||||||
|
|
||||||
|
it { is_expected.to eq(ds_include(champ_value(multiple_drop_down), constant(first_option))) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.compatible_type?' do
|
describe '.compatible_type?' do
|
||||||
|
@ -60,8 +68,7 @@ describe Logic do
|
||||||
let(:first_option) { drop_down.drop_down_list_enabled_non_empty_options.first }
|
let(:first_option) { drop_down.drop_down_list_enabled_non_empty_options.first }
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(Logic.compatible_type?(champ_value(drop_down.stable_id), constant(first_option))).to be true
|
expect(Logic.compatible_type?(champ_value(drop_down.stable_id), constant('a'))).to be true
|
||||||
expect(Logic.compatible_type?(champ_value(drop_down.stable_id), constant('a'))).to be false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue