Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions go/validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -602,8 +602,21 @@ func isVisibilityRuleSatisfied(rule VisibilityRule, values url.Values) bool {
conditionMet = strings.HasSuffix(fieldValue, condition.Comparison.Value)
case "EqualsField":
// the value stored in Comparison.Value is the name of another field
comparisonValue := values.Get(condition.Comparison.Value)
conditionMet = fieldValue == comparisonValue
// Check if ANY value from fieldName matches ANY value from the other field
fieldValues := values[condition.FieldName]
otherFieldValues := values[condition.Comparison.Value]
conditionMet = false
for _, fv := range fieldValues {
for _, ofv := range otherFieldValues {
if fv == ofv {
conditionMet = true
break
}
}
if conditionMet {
break
}
}
case "GreaterThan":
// Try to parse comparison value as float64
comparisonValue, comparisonErr := strconv.ParseFloat(condition.Comparison.Value, 64)
Expand Down
116 changes: 116 additions & 0 deletions go/validate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,122 @@ func TestVisibilityRules(t *testing.T) {
},
expectedError: ErrRequiredFieldMissing,
},
{
name: "EqualsField with multi-value fields - any value matches (Elm behavior)",
formFields: `
[
{
"name": "skills",
"type": {
"type": "ChooseMultiple",
"choices": ["Go", "Elm", "JavaScript", "Python"]
},
"label": "Your Skills",
"presence": "Required"
},
{
"name": "preferred_skills",
"type": {
"type": "ChooseMultiple",
"choices": ["Go", "Elm", "JavaScript", "Python"]
},
"label": "Preferred Skills",
"presence": "Required"
},
{
"type": {
"type": "ShortText",
"inputType": "text",
"attributes": {
"type": "text",
"class": "size-0-invisible",
"value": "form-invalid",
"pattern": "form-ok"
}
},
"label": "Skills Match Indicator",
"presence": "Required",
"visibilityRule": [
{
"type": "HideWhen",
"conditions": [
{
"type": "Field",
"fieldName": "skills",
"comparison": {
"type": "EqualsField",
"value": "preferred_skills"
}
}
]
}
]
}
]`,
values: url.Values{
"skills": []string{"Go", "Elm"},
"preferred_skills": []string{"Python", "Elm", "JavaScript"},
},
expectedError: nil, // Should pass - "Elm" is in both lists, so condition is met, field is hidden
},
{
name: "EqualsField with multi-value fields - no overlap",
formFields: `
[
{
"name": "skills",
"type": {
"type": "ChooseMultiple",
"choices": ["Go", "Elm", "JavaScript", "Python"]
},
"label": "Your Skills",
"presence": "Required"
},
{
"name": "preferred_skills",
"type": {
"type": "ChooseMultiple",
"choices": ["Go", "Elm", "JavaScript", "Python"]
},
"label": "Preferred Skills",
"presence": "Required"
},
{
"type": {
"type": "ShortText",
"inputType": "text",
"attributes": {
"type": "text",
"class": "size-0-invisible",
"value": "form-invalid",
"pattern": "form-ok"
}
},
"label": "Skills Match Indicator",
"presence": "Required",
"visibilityRule": [
{
"type": "HideWhen",
"conditions": [
{
"type": "Field",
"fieldName": "skills",
"comparison": {
"type": "EqualsField",
"value": "preferred_skills"
}
}
]
}
]
}
]`,
values: url.Values{
"skills": []string{"Go", "Elm"},
"preferred_skills": []string{"Python", "JavaScript"},
},
expectedError: ErrRequiredFieldMissing, // Should fail - no overlap, so field is visible but missing value
},
}

for _, tt := range scenarios {
Expand Down
180 changes: 180 additions & 0 deletions tests/MainTest.elm
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,186 @@ suite =
-- Comparison is as-is: whitespace and duplicates are not normalized
Main.evaluateCondition values (Main.Field "a" (Main.EqualsField "b"))
|> Expect.equal True
, test "EqualsField with multi-value fields - any value matches (integration test)" <|
\_ ->
let
-- Mirror the Go test: ChooseMultiple fields with EqualsField visibility rule
formFields =
Array.fromList
[ { label = "Your Skills"
, name = Just "skills"
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ChooseMultiple
{ choices =
[ { label = "Go", value = "Go" }
, { label = "Elm", value = "Elm" }
, { label = "JavaScript", value = "JavaScript" }
, { label = "Python", value = "Python" }
]
, filter = Nothing
, maxAllowed = Nothing
, minRequired = Nothing
}
, visibilityRule = []
}
, { label = "Preferred Skills"
, name = Just "preferred_skills"
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ChooseMultiple
{ choices =
[ { label = "Go", value = "Go" }
, { label = "Elm", value = "Elm" }
, { label = "JavaScript", value = "JavaScript" }
, { label = "Python", value = "Python" }
]
, filter = Nothing
, maxAllowed = Nothing
, minRequired = Nothing
}
, visibilityRule = []
}
, { label = "Skills Match Indicator"
, name = Nothing
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ShortText
(Main.fromRawCustomElement
{ inputType = "text"
, inputTag = "input"
, attributes =
Dict.fromList
[ ( "type", "text" )
, ( "class", "size-0-invisible" )
, ( "value", "form-invalid" )
, ( "pattern", "form-ok" )
]
}
)
, visibilityRule =
[ Main.HideWhen
[ Main.Field "skills" (Main.EqualsField "preferred_skills") ]
]
}
]

-- Values with overlap: "Elm" is in both lists
values =
Dict.fromList
[ ( "skills", [ "Go", "Elm" ] )
, ( "preferred_skills", [ "Python", "Elm", "JavaScript" ] )
]
in
Expect.all
[ \_ ->
-- The EqualsField condition should be met (overlap exists)
Main.evaluateCondition values (Main.Field "skills" (Main.EqualsField "preferred_skills"))
|> Expect.equal True
, \_ ->
-- The third field should be hidden (HideWhen condition met)
case Array.get 2 formFields of
Just field ->
Main.isVisibilityRuleSatisfied field.visibilityRule values
|> Expect.equal False

Nothing ->
Expect.fail "Field 2 not found"
]
()
, test "EqualsField with multi-value fields - no overlap (integration test)" <|
\_ ->
let
-- Same form structure as above
formFields =
Array.fromList
[ { label = "Your Skills"
, name = Just "skills"
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ChooseMultiple
{ choices =
[ { label = "Go", value = "Go" }
, { label = "Elm", value = "Elm" }
, { label = "JavaScript", value = "JavaScript" }
, { label = "Python", value = "Python" }
]
, filter = Nothing
, maxAllowed = Nothing
, minRequired = Nothing
}
, visibilityRule = []
}
, { label = "Preferred Skills"
, name = Just "preferred_skills"
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ChooseMultiple
{ choices =
[ { label = "Go", value = "Go" }
, { label = "Elm", value = "Elm" }
, { label = "JavaScript", value = "JavaScript" }
, { label = "Python", value = "Python" }
]
, filter = Nothing
, maxAllowed = Nothing
, minRequired = Nothing
}
, visibilityRule = []
}
, { label = "Skills Match Indicator"
, name = Nothing
, presence = Main.Required
, description = Main.AttributeNotNeeded
, type_ =
Main.ShortText
(Main.fromRawCustomElement
{ inputType = "text"
, inputTag = "input"
, attributes =
Dict.fromList
[ ( "type", "text" )
, ( "class", "size-0-invisible" )
, ( "value", "form-invalid" )
, ( "pattern", "form-ok" )
]
}
)
, visibilityRule =
[ Main.HideWhen
[ Main.Field "skills" (Main.EqualsField "preferred_skills") ]
]
}
]

-- Values with NO overlap
values =
Dict.fromList
[ ( "skills", [ "Go", "Elm" ] )
, ( "preferred_skills", [ "Python", "JavaScript" ] )
]
in
Expect.all
[ \_ ->
-- The EqualsField condition should NOT be met (no overlap)
Main.evaluateCondition values (Main.Field "skills" (Main.EqualsField "preferred_skills"))
|> Expect.equal False
, \_ ->
-- The third field should be visible (HideWhen condition not met)
case Array.get 2 formFields of
Just field ->
Main.isVisibilityRuleSatisfied field.visibilityRule values
|> Expect.equal True

Nothing ->
Expect.fail "Field 2 not found"
]
()
]
, describe "list attribute handling"
[ test "fromRawCustomElement removes list attribute" <|
Expand Down
Loading