[ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], ], ]); $this->assertSame([ 'operator' => 'all', 'children' => [ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], ], ], $result); } public function test_translates_any_group_to_internal_form(): void { $result = FormFieldConditionalLogicService::normaliseLegacyShape([ 'any' => [ ['field_slug' => 'region', 'operator' => 'equals', 'value' => 'NL'], ['field_slug' => 'region', 'operator' => 'equals', 'value' => 'BE'], ], ]); $this->assertSame('any', $result['operator']); $this->assertCount(2, $result['children']); } public function test_recursively_normalises_nested_groups(): void { $result = FormFieldConditionalLogicService::normaliseLegacyShape([ 'all' => [ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], [ 'any' => [ ['field_slug' => 'region', 'operator' => 'equals', 'value' => 'NL'], ['field_slug' => 'region', 'operator' => 'equals', 'value' => 'BE'], ], ], ], ]); $this->assertSame('all', $result['operator']); $this->assertCount(2, $result['children']); // First child: condition leaf — passthrough. $this->assertSame( ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], $result['children'][0], ); // Second child: nested ANY group — translated. $this->assertSame('any', $result['children'][1]['operator']); $this->assertCount(2, $result['children'][1]['children']); } public function test_passes_through_internal_shape_unchanged(): void { $internal = [ 'operator' => 'all', 'children' => [ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], ], ]; $this->assertSame($internal, FormFieldConditionalLogicService::normaliseLegacyShape($internal)); } public function test_passes_through_condition_leaf_unchanged(): void { // Conditions at root are technically invalid (a tree must start // with a group); the normaliser returns the leaf as-is and the // downstream `assertSpecsValid` produces the 422 error. $leaf = ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes']; $this->assertSame($leaf, FormFieldConditionalLogicService::normaliseLegacyShape($leaf)); } public function test_returns_unknown_group_key_as_passthrough_for_downstream_assert(): void { // `xor` is not in the FormFieldConditionalLogicGroupOperator enum. // Normaliser returns the node unchanged; assertSpecsValid will // raise `InvalidConditionalLogicSpecException` with "Unknown // group operator ''" because the passthrough lacks `operator`. $node = [ 'xor' => [ ['field_slug' => 'a', 'operator' => 'equals', 'value' => 1], ], ]; $this->assertSame($node, FormFieldConditionalLogicService::normaliseLegacyShape($node)); } public function test_returns_empty_array_unchanged(): void { $this->assertSame([], FormFieldConditionalLogicService::normaliseLegacyShape([])); } public function test_skips_non_array_children_silently(): void { // Defensive: malformed children that are scalars get stripped // (existing behaviour — `if (is_array($child))` guard). Surfaces // downstream as a "group requires at least one child" error if // every child was scalar. $result = FormFieldConditionalLogicService::normaliseLegacyShape([ 'all' => [ 'string-not-an-array', ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], 42, ], ]); $this->assertCount(1, $result['children']); $this->assertSame( ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], $result['children'][0], ); } }