create(); $schema = FormSchema::factory()->create([ 'organisation_id' => $org->id, 'snapshot_mode' => 'on_submit', 'is_published' => true, 'public_token' => (string) \Illuminate\Support\Str::ulid(), ]); FormField::factory() ->withOptions(['XS', 'S', 'M']) ->create([ 'form_schema_id' => $schema->id, 'field_type' => FormFieldType::SELECT->value, 'slug' => 'shirtmaat', 'label' => 'Shirtmaat', ]); $service = app(FormSubmissionService::class); $draft = $service->createDraft($schema, null, null, []); $service->submit($draft, null); $snapshot = $draft->fresh()->schema_snapshot; $this->assertIsArray($snapshot); $field = collect($snapshot['fields'])->firstWhere('slug', 'shirtmaat'); $this->assertSame( [ ['value' => 'XS', 'label' => 'XS', 'sort_order' => 0], ['value' => 'S', 'label' => 'S', 'sort_order' => 1], ['value' => 'M', 'label' => 'M', 'sort_order' => 2], ], $field['options'], ); } public function test_submission_snapshot_does_not_emit_locale_options_in_field_translations(): void { $org = Organisation::factory()->create(); $schema = FormSchema::factory()->create([ 'organisation_id' => $org->id, 'snapshot_mode' => 'on_submit', 'is_published' => true, 'public_token' => (string) \Illuminate\Support\Str::ulid(), ]); FormField::factory() ->withOptions([ ['value' => 'a', 'label' => 'A', 'sort_order' => 0, 'translations' => ['nl' => 'AA']], ]) ->create([ 'form_schema_id' => $schema->id, 'field_type' => FormFieldType::SELECT->value, 'slug' => 'choice', 'label' => 'Choice', // Per-locale label kept; the legacy {locale}.options[] is // dead post-WS-5d. 'translations' => ['nl' => ['label' => 'Keuze']], ]); $service = app(FormSubmissionService::class); $draft = $service->createDraft($schema, null, null, []); $service->submit($draft, null); $snapshot = $draft->fresh()->schema_snapshot; $field = collect($snapshot['fields'])->firstWhere('slug', 'choice'); if (is_array($field['translations'] ?? null)) { foreach ($field['translations'] as $locale => $bag) { $this->assertArrayNotHasKey('options', is_array($bag) ? $bag : [], "locale {$locale} kept legacy options key"); } } } public function test_form_field_request_rejects_missing_value_in_spec(): void { $org = Organisation::factory()->create(); $admin = \App\Models\User::factory()->create(); $org->users()->attach($admin, ['role' => 'org_admin']); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); \Laravel\Sanctum\Sanctum::actingAs($admin); $response = $this->postJson("/api/v1/organisations/{$org->id}/forms/schemas/{$schema->id}/fields", [ 'field_type' => FormFieldType::SELECT->value, 'slug' => 'choice', 'label' => 'Choice', 'options' => [ ['label' => 'A', 'sort_order' => 0], ], ]); $response->assertStatus(422); $response->assertJsonValidationErrors(['options.0.value']); } public function test_form_field_request_rejects_duplicate_values_in_spec(): void { $org = Organisation::factory()->create(); $admin = \App\Models\User::factory()->create(); $org->users()->attach($admin, ['role' => 'org_admin']); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); \Laravel\Sanctum\Sanctum::actingAs($admin); $response = $this->postJson("/api/v1/organisations/{$org->id}/forms/schemas/{$schema->id}/fields", [ 'field_type' => FormFieldType::SELECT->value, 'slug' => 'choice', 'label' => 'Choice', 'options' => [ ['value' => 'dup', 'label' => 'A', 'sort_order' => 0], ['value' => 'dup', 'label' => 'B', 'sort_order' => 1], ], ]); $response->assertStatus(422); $response->assertJsonValidationErrors(['options']); } public function test_form_field_request_accepts_valid_spec(): void { $org = Organisation::factory()->create(); $admin = \App\Models\User::factory()->create(); $org->users()->attach($admin, ['role' => 'org_admin']); $schema = FormSchema::factory()->create(['organisation_id' => $org->id]); \Laravel\Sanctum\Sanctum::actingAs($admin); $response = $this->postJson("/api/v1/organisations/{$org->id}/forms/schemas/{$schema->id}/fields", [ 'field_type' => FormFieldType::SELECT->value, 'slug' => 'choice', 'label' => 'Choice', 'options' => [ ['value' => 'red', 'label' => 'Red', 'sort_order' => 0], ['value' => 'green', 'label' => 'Green', 'sort_order' => 1, 'translations' => ['nl' => 'Groen']], ], ]); $response->assertCreated(); $this->assertSame( [ ['value' => 'red', 'label' => 'Red', 'sort_order' => 0], ['value' => 'green', 'label' => 'Green', 'sort_order' => 1, 'translations' => ['nl' => 'Groen']], ], $response->json('data.options'), ); } }