seed(RoleSeeder::class); $this->org = Organisation::factory()->create(); $this->admin = User::factory()->create(); $this->org->users()->attach($this->admin, ['role' => 'org_admin']); $this->submitter = User::factory()->create(); $this->org->users()->attach($this->submitter, ['role' => 'org_member']); $this->schema = FormSchema::factory()->create([ 'organisation_id' => $this->org->id, 'snapshot_mode' => FormSchemaSnapshotMode::ON_SUBMIT, ]); $this->field = FormField::factory()->create([ 'form_schema_id' => $this->schema->id, 'field_type' => FormFieldType::TEXT->value, 'slug' => 'motivatie', 'label' => 'Motivatie', 'role_restrictions' => null, ]); } public function test_create_draft_and_submit_stores_schema_snapshot(): void { Sanctum::actingAs($this->submitter); // Create draft (subject = user self) $create = $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/submissions", ['subject_type' => 'user', 'subject_id' => $this->submitter->id], ); $create->assertCreated(); $submissionId = $create->json('data.id'); // Upsert values $this->putJson( "/api/v1/organisations/{$this->org->id}/forms/submissions/{$submissionId}/field-values", ['values' => ['motivatie' => 'Ik doe graag mee.']], )->assertOk(); // Submit $this->postJson("/api/v1/organisations/{$this->org->id}/forms/submissions/{$submissionId}/submit") ->assertOk() ->assertJsonPath('data.status', FormSubmissionStatus::SUBMITTED->value); $submission = FormSubmission::query()->findOrFail($submissionId); $this->assertNotNull($submission->schema_snapshot); $this->assertEquals($this->schema->version, $submission->schema_version_at_submit); } public function test_review_transitions_status_and_records_reviewer(): void { Sanctum::actingAs($this->admin); $submission = FormSubmission::factory()->create([ 'form_schema_id' => $this->schema->id, 'status' => FormSubmissionStatus::SUBMITTED->value, 'submitted_by_user_id' => $this->submitter->id, 'submitted_at' => now(), ]); $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/submissions/{$submission->id}/review", ['status' => FormSubmissionReviewStatus::APPROVED->value, 'review_notes' => 'Goed ingevuld.'], )->assertOk(); $fresh = $submission->fresh(); $this->assertSame($this->admin->id, $fresh->reviewed_by_user_id); } public function test_delegate_creates_active_delegation(): void { Sanctum::actingAs($this->submitter); $other = User::factory()->create(); $this->org->users()->attach($other, ['role' => 'org_member']); $submission = FormSubmission::factory()->create([ 'form_schema_id' => $this->schema->id, 'status' => FormSubmissionStatus::DRAFT->value, 'subject_type' => 'user', 'subject_id' => $this->submitter->id, ]); $this->postJson( "/api/v1/organisations/{$this->org->id}/forms/submissions/{$submission->id}/delegate", ['delegated_to_user_id' => $other->id, 'message' => 'Kijk er even naar.'], )->assertCreated(); $this->assertSame(1, $submission->fresh()->delegations()->whereNull('revoked_at')->count()); } public function test_update_blocked_for_non_subject_non_delegatee(): void { $outsider = User::factory()->create(); $this->org->users()->attach($outsider, ['role' => 'org_member']); Sanctum::actingAs($outsider); $submission = FormSubmission::factory()->create([ 'form_schema_id' => $this->schema->id, 'status' => FormSubmissionStatus::DRAFT->value, 'subject_type' => 'user', 'subject_id' => $this->submitter->id, ]); $this->putJson( "/api/v1/organisations/{$this->org->id}/forms/submissions/{$submission->id}/field-values", ['values' => ['motivatie' => 'hack']], )->assertStatus(403); } }