seed(RoleSeeder::class); Config::set('form_builder.captcha.required_for_purposes', []); $this->org = Organisation::factory()->create(); $this->event = Event::factory()->create(['organisation_id' => $this->org->id]); $this->schema = FormSchema::factory()->create([ 'organisation_id' => $this->org->id, 'purpose' => FormPurpose::EVENT_REGISTRATION, 'owner_type' => 'event', 'owner_id' => $this->event->id, 'is_published' => true, 'public_token' => (string) Str::ulid(), ]); FormField::factory()->create([ 'form_schema_id' => $this->schema->id, 'field_type' => FormFieldType::TEXT->value, 'slug' => 'motivatie', 'label' => 'Motivatie', 'is_portal_visible' => true, 'is_admin_only' => false, ]); } private function submitAs(string $email, string $idempotencyKey, ?string $schemaOverride = null): array { $token = $schemaOverride ?? $this->schema->public_token; $create = $this->postJson( "/api/v1/public/forms/{$token}/submissions", [ 'idempotency_key' => $idempotencyKey, 'public_submitter_name' => 'Bart', 'public_submitter_email' => $email, ], ); $create->assertCreated(); $submissionId = $create->json('data.id'); $submit = $this->postJson( "/api/v1/public/forms/{$token}/submissions/{$submissionId}/submit", ['values' => ['motivatie' => 'x']], ); $submit->assertCreated(); return $submit->json('data'); } public function test_first_submit_has_null_duplicate_submission(): void { $data = $this->submitAs('test@example.test', 'dup-regression-001'); $this->assertNull($data['duplicate_submission']); } public function test_second_submit_same_email_same_schema_exposes_count_one(): void { $this->submitAs('test@example.test', 'dup-regression-010'); $data = $this->submitAs('test@example.test', 'dup-regression-011'); $this->assertIsArray($data['duplicate_submission']); $this->assertSame(1, $data['duplicate_submission']['count']); $this->assertNotEmpty($data['duplicate_submission']['first_submitted_at']); } public function test_third_submit_exposes_count_two_and_first_date_points_to_first(): void { $first = $this->submitAs('test@example.test', 'dup-regression-020'); $this->submitAs('test@example.test', 'dup-regression-021'); $third = $this->submitAs('test@example.test', 'dup-regression-022'); $this->assertSame(2, $third['duplicate_submission']['count']); $this->assertSame( $first['submitted_at'], $third['duplicate_submission']['first_submitted_at'], 'first_submitted_at must continue to point at the oldest submission', ); } public function test_different_email_same_schema_sees_no_duplicate(): void { $this->submitAs('first@example.test', 'dup-regression-030'); $data = $this->submitAs('second@example.test', 'dup-regression-031'); $this->assertNull($data['duplicate_submission']); } public function test_same_email_different_schema_sees_no_duplicate(): void { $this->submitAs('test@example.test', 'dup-regression-040'); $otherSchema = FormSchema::factory()->create([ 'organisation_id' => $this->org->id, 'purpose' => FormPurpose::EVENT_REGISTRATION, 'owner_type' => 'event', 'owner_id' => $this->event->id, 'is_published' => true, 'public_token' => (string) Str::ulid(), ]); FormField::factory()->create([ 'form_schema_id' => $otherSchema->id, 'field_type' => FormFieldType::TEXT->value, 'slug' => 'motivatie', 'label' => 'Motivatie', 'is_portal_visible' => true, 'is_admin_only' => false, ]); $data = $this->submitAs('test@example.test', 'dup-regression-041', $otherSchema->public_token); $this->assertNull($data['duplicate_submission']); } public function test_duplicate_submission_block_includes_dutch_title_and_body(): void { $this->submitAs('test@example.test', 'dup-regression-050'); $data = $this->submitAs('test@example.test', 'dup-regression-051'); $this->assertSame('Je hebt je eerder al aangemeld', $data['duplicate_submission']['title']); $this->assertStringContainsString( 'De organisator ziet beide aanmeldingen', $data['duplicate_submission']['body'], ); } }