test(form-builder): cover purpose registry and morph-map alignment

- PurposeRegistryTest: all seven purposes load with expected shape;
  `get()` throws PurposeNotFoundException on unknown slug;
  `allSubjectTypes()` returns exactly [artist, company, person, user];
  `publicAccessibleSlugs()` is only `[event_registration]`.
- PurposeSchemaLifecycleTest: data-provider-driven create → publish
  for all seven purposes; negative tests for event_registration (three
  missing bindings) and supplier_intake (company.name missing); partial
  binding test reports only the missing subset.
- CustomPurposeEscapeRemovedTest: column gone, config file gone,
  FormPurpose::CUSTOM gone, store endpoint rejects `'custom'`, resource
  payload omits the field.
- SubjectTypeRegistryConsolidationTest: submission validation accepts
  registry subject types, rejects everything else including the legacy
  `event` alias that used to be allowed.
- MorphMapAlignmentTest: compile-time guard that every
  PurposeRegistry::allSubjectTypes() alias appears in the morph-map and
  in AppServiceProvider::PURPOSE_SUBJECT_FQCN.
- FormPurposeTest rewritten to cover the seven v1.0 cases and the
  registry-delegation helpers (now extends Tests\TestCase for the
  container).
- Public/listener tests swap the removed PUBLIC_RSVP / PUBLIC_COMPLAINT
  / FEEDBACK references for valid v1.0 purposes, preserving their
  negative-path assertions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 14:36:09 +02:00
parent a71201f4d3
commit 55ba4f24c0
13 changed files with 555 additions and 82 deletions

View File

@@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace Tests\Feature\FormBuilder\Purposes;
use App\Enums\FormBuilder\FormSubmissionMode;
use App\FormBuilder\Purposes\Exceptions\PurposeNotFoundException;
use App\FormBuilder\Purposes\PurposeRegistry;
use Tests\TestCase;
final class PurposeRegistryTest extends TestCase
{
private function registry(): PurposeRegistry
{
return $this->app->make(PurposeRegistry::class);
}
public function test_loads_all_seven_purposes_from_config(): void
{
$registry = $this->registry();
$all = $registry->all();
$this->assertCount(7, $all);
$this->assertSame(
[
'event_registration',
'artist_advance',
'supplier_intake',
'post_event_evaluation',
'incident_report',
'signature_contract',
'user_profile',
],
array_keys($all),
);
}
public function test_event_registration_definition_is_complete(): void
{
$def = $this->registry()->get('event_registration');
$this->assertSame('event_registration', $def->slug);
$this->assertSame('Aanmelding vrijwilligers/crew', $def->label);
$this->assertSame('person', $def->subjectType);
$this->assertSame(FormSubmissionMode::SINGLE, $def->defaultSubmissionMode);
$this->assertTrue($def->allowsPublicAccess);
$this->assertSame(
['person.email', 'person.first_name', 'person.last_name'],
$def->requiredBindings,
);
}
public function test_artist_advance_uses_draft_single(): void
{
$def = $this->registry()->get('artist_advance');
$this->assertSame('artist', $def->subjectType);
$this->assertSame(FormSubmissionMode::DRAFT_SINGLE, $def->defaultSubmissionMode);
$this->assertFalse($def->allowsPublicAccess);
$this->assertSame([], $def->requiredBindings);
}
public function test_supplier_intake_requires_company_name(): void
{
$def = $this->registry()->get('supplier_intake');
$this->assertSame('company', $def->subjectType);
$this->assertSame(FormSubmissionMode::SINGLE, $def->defaultSubmissionMode);
$this->assertFalse($def->allowsPublicAccess);
$this->assertSame(['company.name'], $def->requiredBindings);
}
public function test_get_throws_on_unknown_slug(): void
{
$this->expectException(PurposeNotFoundException::class);
$this->registry()->get('does_not_exist');
}
public function test_has_returns_false_for_unknown_slug(): void
{
$this->assertFalse($this->registry()->has('does_not_exist'));
$this->assertTrue($this->registry()->has('event_registration'));
}
public function test_all_subject_types_returns_four_sorted_aliases(): void
{
$this->assertSame(
['artist', 'company', 'person', 'user'],
$this->registry()->allSubjectTypes(),
);
}
public function test_public_accessible_slugs_is_only_event_registration(): void
{
$this->assertSame(
['event_registration'],
$this->registry()->publicAccessibleSlugs(),
);
}
public function test_result_is_memoised_on_instance(): void
{
$registry = $this->registry();
$first = $registry->all();
$second = $registry->all();
$this->assertSame($first, $second);
// Same PurposeDefinition instance per slug across calls.
$this->assertSame($first['event_registration'], $second['event_registration']);
}
}