RFC §3 Q9 contract — applicator is purpose-agnostic; per-purpose
differences live in PurposeSubjectResolver. Sessie 2's smoke matrix
covered only event_registration; this commit fills the remaining six.
Coverage per file (18 tests total, all passing):
- SignatureContractPurposePipelineTest (3 tests)
happy path + conflict resolution + no_auth missing-context
target: User via auth (User::email/first_name/last_name)
- UserProfilePurposePipelineTest (3 tests)
happy path + conflict resolution + no_auth missing-context
target: User via auth
- SupplierIntakePurposePipelineTest (3 tests)
happy path + conflict resolution + no_production_request missing-context
target: Company subject pre-set by production_request flow
- PostEventEvaluationPurposePipelineTest (4 tests)
happy path + conflict resolution + no_person_for_user + no_auth
target: Person via auth user → Person.event_id link
- IncidentReportPurposePipelineTest (4 tests)
happy path (auth + Person link)
+ conflict resolution
+ anonymous-allowed (null subject → COMPLETED, empty applications)
+ auth-without-Person (null subject branch)
Unique purpose: only one allowed to legitimately resolve to no subject.
- ArtistAdvancePurposePipelineTest (1 test)
no_portal_token missing-context only.
Happy path + subject_not_found branches require the Artist model
(BACKLOG: ARCH-09); morphTo can't materialise a non-existent class.
Documented inline; full coverage follows once ARCH-09 lands.
Each test wires the schema_snapshot directly with the applicator-shape
binding entries (matches sessie 2's FormBindingApplicatorIntegrationTest
pattern). All bindings use registered binding-target attributes from
config/form_builder/binding_targets.php to satisfy BindingTypeRegistry's
strict resolve() at apply time.
Refs: RFC-WS-6.md §3 Q9, ARCH-BINDINGS.md § 6.5
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 lines
3.1 KiB
PHP
78 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\FormBuilder\Bindings\Pipeline;
|
|
|
|
use App\Enums\FormBuilder\FormPurpose;
|
|
use App\Exceptions\FormBuilder\PurposeSubjectResolutionException;
|
|
use App\FormBuilder\Bindings\FormBindingApplicator;
|
|
use App\Models\FormBuilder\FormSchema;
|
|
use App\Models\FormBuilder\FormSubmission;
|
|
use App\Models\Organisation;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\TestCase;
|
|
|
|
/**
|
|
* End-to-end pipeline smoke for the artist_advance purpose.
|
|
*
|
|
* RFC §3 Q9 case matrix (failure paths only — happy path requires the
|
|
* Artist model which isn't yet implemented; tracked via BACKLOG: ARCH-09):
|
|
*
|
|
* - Missing portal token (subject_type ≠ 'artist')
|
|
* - Subject not found (subject_type='artist' but no morph target row)
|
|
*
|
|
* Subject resolution: ArtistAdvanceSubjectResolver expects the portal-token
|
|
* route to have pre-set submission.subject_type='artist' + subject_id. The
|
|
* resolver throws if either is missing or the morph target row is absent.
|
|
*
|
|
* Ref: ARCH-BINDINGS.md § 6.5
|
|
*/
|
|
final class ArtistAdvancePurposePipelineTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_missing_portal_token_throws_no_portal_token(): void
|
|
{
|
|
// Submission lacks subject_type='artist' (the portal route would
|
|
// have set this from the portal_token context). Resolver throws.
|
|
$org = Organisation::factory()->create();
|
|
$schema = FormSchema::factory()->create([
|
|
'organisation_id' => $org->id,
|
|
'purpose' => FormPurpose::ARTIST_ADVANCE->value,
|
|
]);
|
|
$submission = FormSubmission::factory()->create([
|
|
'form_schema_id' => $schema->id,
|
|
'subject_type' => null,
|
|
'subject_id' => null,
|
|
]);
|
|
$submission->schema_snapshot = ['fields' => []];
|
|
$submission->save();
|
|
|
|
try {
|
|
DB::transaction(fn () => resolve(FormBindingApplicator::class)->apply($submission->fresh()));
|
|
$this->fail('Expected PurposeSubjectResolutionException');
|
|
} catch (PurposeSubjectResolutionException $e) {
|
|
$this->assertSame('artist_advance', $e->purposeSlug);
|
|
$this->assertSame('no_portal_token', $e->reasonCode);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* test_subject_claims_artist_but_record_gone — REMOVED until BACKLOG
|
|
* ARCH-09 lands the Artist model. Hitting subject_type='artist' would
|
|
* reach the resolver's `$submission->subject` morph access, which
|
|
* Laravel's HasRelationships::newRelatedInstance instantiates as
|
|
* `new App\Models\Artist`. The class doesn't exist yet (only the
|
|
* morph alias is registered as a string), so the test crashes with
|
|
* "Class not found" before reaching the subject_not_found branch.
|
|
*
|
|
* Once the Artist model + factory land, this case becomes testable:
|
|
* just create an Artist subject row, link the submission to it, and
|
|
* proceed with happy-path + conflict resolution patterns. The other
|
|
* five purposes here exercise the full pattern; artist_advance is
|
|
* limited to the no_portal_token branch above.
|
|
*/
|
|
}
|