create(); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); $field = FormField::factory()->create(['form_schema_id' => $schema->id]); $group = FormFieldConditionalLogicGroup::factory()->forField($field)->create(); $condition = FormFieldConditionalLogicCondition::factory()->inGroup($group)->create(); $this->assertSame($group->id, $condition->fresh()->group->id); } public function test_value_roundtrips_through_json_cast(): void { $org = Organisation::factory()->create(); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); $field = FormField::factory()->create(['form_schema_id' => $schema->id]); $group = FormFieldConditionalLogicGroup::factory()->forField($field)->create(); $stringValue = FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->withOperator(FormFieldConditionalLogicConditionOperator::Equals, 'NL') ->create(); $this->assertSame('NL', $stringValue->fresh()->value); $arrayValue = FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->withOperator(FormFieldConditionalLogicConditionOperator::In, ['a', 'b', 'c']) ->create(); $this->assertSame(['a', 'b', 'c'], $arrayValue->fresh()->value); $boolValue = FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->withOperator(FormFieldConditionalLogicConditionOperator::Equals, true) ->create(); $this->assertTrue($boolValue->fresh()->value); } public function test_valueless_operators_store_null(): void { $org = Organisation::factory()->create(); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); $field = FormField::factory()->create(['form_schema_id' => $schema->id]); $group = FormFieldConditionalLogicGroup::factory()->forField($field)->create(); $empty = FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->withOperator(FormFieldConditionalLogicConditionOperator::Empty) ->create(); $this->assertNull($empty->fresh()->value); $notEmpty = FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->withOperator(FormFieldConditionalLogicConditionOperator::NotEmpty) ->create(); $this->assertNull($notEmpty->fresh()->value); } public function test_enum_catalogue_has_ten_operators(): void { // Parity check against ARCH ยง8 / Phase A seed-scan confirmed set. $values = array_map( fn (FormFieldConditionalLogicConditionOperator $case): string => $case->value, FormFieldConditionalLogicConditionOperator::cases(), ); sort($values); $this->assertSame([ 'contains', 'empty', 'equals', 'greater_than', 'in', 'less_than', 'not_contains', 'not_empty', 'not_equals', 'not_in', ], $values); } public function test_field_slug_index_supports_reverse_lookup(): void { $org = Organisation::factory()->create(); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); $field = FormField::factory()->create(['form_schema_id' => $schema->id]); $group = FormFieldConditionalLogicGroup::factory()->forField($field)->create(); FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->forFieldSlug('gate') ->create(); FormFieldConditionalLogicCondition::factory() ->inGroup($group) ->forFieldSlug('region') ->create(); $gateHits = FormFieldConditionalLogicCondition::query() ->where('field_slug', 'gate') ->count(); $this->assertSame(1, $gateHits); } }