seed(RoleSeeder::class); $this->org = Organisation::factory()->create(); $this->actor = User::factory()->create(); $this->org->users()->attach($this->actor, ['role' => 'org_admin']); $this->actor->assignRole('org_admin'); setPermissionsTeamId($this->org->id); $this->service = $this->app->make(FormSchemaService::class); } /** @return iterable */ public static function purposeProvider(): iterable { foreach (FormPurpose::cases() as $case) { yield $case->value => [$case]; } } /** @dataProvider purposeProvider */ public function test_create_and_publish_succeeds_for_purpose(FormPurpose $purpose): void { $schema = $this->service->create( $this->org, [ 'name' => 'Schema '.$purpose->value, 'purpose' => $purpose->value, ], $this->actor, ); $this->seedRequiredBindings($schema, $purpose); $published = $this->service->publish($schema->fresh('fields'), $this->actor); $this->assertTrue((bool) $published->is_published); $this->assertSame($purpose->value, $published->purpose->value ?? $published->purpose); } public function test_event_registration_without_required_bindings_fails_publish(): void { $schema = $this->service->create( $this->org, ['name' => 'ER', 'purpose' => FormPurpose::EVENT_REGISTRATION->value], $this->actor, ); try { $this->service->publish($schema->fresh('fields'), $this->actor); $this->fail('Expected PurposeRequirementsNotMetException'); } catch (PurposeRequirementsNotMetException $e) { $this->assertSame('event_registration', $e->purposeSlug); $this->assertSame( ['person.email', 'person.first_name', 'person.last_name'], $e->missingBindings, ); } } public function test_supplier_intake_without_company_name_binding_fails_publish(): void { $schema = $this->service->create( $this->org, ['name' => 'SI', 'purpose' => FormPurpose::SUPPLIER_INTAKE->value], $this->actor, ); try { $this->service->publish($schema->fresh('fields'), $this->actor); $this->fail('Expected PurposeRequirementsNotMetException'); } catch (PurposeRequirementsNotMetException $e) { $this->assertSame('supplier_intake', $e->purposeSlug); $this->assertSame(['company.name'], $e->missingBindings); } } public function test_event_registration_partial_bindings_reports_only_missing(): void { $schema = $this->service->create( $this->org, ['name' => 'ER-partial', 'purpose' => FormPurpose::EVENT_REGISTRATION->value], $this->actor, ); $this->addBindingField($schema, 'person', 'email', 'email'); try { $this->service->publish($schema->fresh('fields'), $this->actor); $this->fail('Expected PurposeRequirementsNotMetException'); } catch (PurposeRequirementsNotMetException $e) { $this->assertSame( ['person.first_name', 'person.last_name'], $e->missingBindings, ); } } private function seedRequiredBindings(FormSchema $schema, FormPurpose $purpose): void { match ($purpose) { FormPurpose::EVENT_REGISTRATION => [ $this->addBindingField($schema, 'person', 'email', 'email'), $this->addBindingField($schema, 'person', 'first_name', 'first_name'), $this->addBindingField($schema, 'person', 'last_name', 'last_name'), ], FormPurpose::SUPPLIER_INTAKE => [ $this->addBindingField($schema, 'company', 'name', 'company_name'), ], default => null, }; } private function addBindingField(FormSchema $schema, string $entity, string $column, string $slug): FormField { return FormField::factory() ->withEntityBinding($entity, $column) ->create([ 'form_schema_id' => $schema->id, 'field_type' => FormFieldType::TEXT, 'slug' => $slug, 'label' => ucfirst($slug), ]); } }