seed(RoleSeeder::class); $this->org = Organisation::factory()->create(); $this->admin = User::factory()->create(); $this->org->users()->attach($this->admin, ['role' => 'org_admin']); $this->schema = FormSchema::factory()->create(['organisation_id' => $this->org->id]); } public function test_store_rejects_unknown_comparison_operator(): void { Sanctum::actingAs($this->admin); FormField::factory()->create(['form_schema_id' => $this->schema->id, 'slug' => 'gate']); $response = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields", [ 'field_type' => FormFieldType::TEXT->value, 'slug' => 'target', 'label' => 'Target', 'conditional_logic' => [ 'show_when' => [ 'all' => [ ['field_slug' => 'gate', 'operator' => 'matches_regex', 'value' => 'y'], ], ], ], ], ); $response->assertStatus(422); $response->assertJsonValidationErrors(['conditional_logic']); } public function test_store_rejects_root_condition_without_group(): void { Sanctum::actingAs($this->admin); $response = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields", [ 'field_type' => FormFieldType::TEXT->value, 'slug' => 'target', 'label' => 'Target', // Condition at root — invalid; ARCH §8 requires a group wrapper. 'conditional_logic' => [ 'show_when' => [ 'field_slug' => 'gate', 'operator' => 'equals', 'value' => 'y', ], ], ], ); $response->assertStatus(422); $response->assertJsonValidationErrors(['conditional_logic']); } public function test_store_rejects_empty_group(): void { Sanctum::actingAs($this->admin); $response = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields", [ 'field_type' => FormFieldType::TEXT->value, 'slug' => 'target', 'label' => 'Target', 'conditional_logic' => ['show_when' => ['all' => []]], ], ); $response->assertStatus(422); $response->assertJsonValidationErrors(['conditional_logic']); } public function test_store_rejects_unknown_field_slug(): void { Sanctum::actingAs($this->admin); $response = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields", [ 'field_type' => FormFieldType::TEXT->value, 'slug' => 'target', 'label' => 'Target', 'conditional_logic' => [ 'show_when' => [ 'all' => [ ['field_slug' => 'nonexistent', 'operator' => 'equals', 'value' => 'y'], ], ], ], ], ); $response->assertStatus(422); $this->assertStringContainsString('nonexistent', (string) $response->json('message')); } public function test_store_accepts_valid_tree_and_persists_relational_rows(): void { Sanctum::actingAs($this->admin); FormField::factory()->create(['form_schema_id' => $this->schema->id, 'slug' => 'gate']); $response = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields", [ 'field_type' => FormFieldType::TEXT->value, 'slug' => 'target', 'label' => 'Target', 'conditional_logic' => [ 'show_when' => [ 'all' => [ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], ], ], ], ], ); $response->assertStatus(201); $this->assertSame([ 'show_when' => [ 'all' => [ ['field_slug' => 'gate', 'operator' => 'equals', 'value' => 'yes'], ], ], ], $response->json('data.conditional_logic')); } }