Files
crewli/api/tests/Feature/FormBuilder/ValidationRules/FormFieldStrictValidationRulesRequestTest.php

172 lines
5.7 KiB
PHP

<?php
declare(strict_types=1);
namespace Tests\Feature\FormBuilder\ValidationRules;
use App\Enums\FormBuilder\FormFieldType;
use App\Models\FormBuilder\FormField;
use App\Models\FormBuilder\FormFieldValidationRule;
use App\Models\FormBuilder\FormSchema;
use App\Models\Organisation;
use App\Models\User;
use Database\Seeders\RoleSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
/**
* WS-5b commit 3 — FormRequest level strict validation of the
* `validation_rules` array-of-specs shape. Unknown rule_type, bad
* parameter shape, unregistered callback key all return 422 BEFORE any
* write lands.
*/
final class FormFieldStrictValidationRulesRequestTest extends TestCase
{
use RefreshDatabase;
private Organisation $org;
private User $admin;
private FormSchema $schema;
protected function setUp(): void
{
parent::setUp();
$this->seed(RoleSeeder::class);
$this->org = Organisation::factory()->create();
$this->admin = User::factory()->create();
$this->org->users()->attach($this->admin, ['role' => 'org_admin']);
$this->schema = FormSchema::factory()->create(['organisation_id' => $this->org->id]);
}
public function test_store_rejects_unregistered_rule_type(): void
{
Sanctum::actingAs($this->admin);
$response = $this->postJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields",
[
'field_type' => FormFieldType::TEXT->value,
'slug' => 'voornaam',
'label' => 'Voornaam',
'validation_rules' => [
['rule_type' => 'not_a_real_rule', 'parameters' => []],
],
],
);
$response->assertStatus(422);
$this->assertArrayHasKey('validation_rules', $response->json('errors') ?? []);
}
public function test_store_rejects_bad_parameter_shape(): void
{
Sanctum::actingAs($this->admin);
$response = $this->postJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields",
[
'field_type' => FormFieldType::TEXT->value,
'slug' => 'voornaam',
'label' => 'Voornaam',
'validation_rules' => [
['rule_type' => 'min_length', 'parameters' => ['value' => 'not-an-int']],
],
],
);
$response->assertStatus(422);
}
public function test_store_rejects_regex_missing_pattern(): void
{
Sanctum::actingAs($this->admin);
$response = $this->postJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields",
[
'field_type' => FormFieldType::TEXT->value,
'slug' => 'postcode',
'label' => 'Postcode',
'validation_rules' => [
['rule_type' => 'regex', 'parameters' => []],
],
],
);
$response->assertStatus(422);
}
public function test_store_rejects_unregistered_callback_key(): void
{
Config::set('form_builder.validation_callbacks', []);
Sanctum::actingAs($this->admin);
$response = $this->postJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields",
[
'field_type' => FormFieldType::TEXT->value,
'slug' => 'kvk',
'label' => 'KvK-nummer',
'validation_rules' => [
['rule_type' => 'callback', 'parameters' => ['key' => 'not_registered']],
],
],
);
$response->assertStatus(422);
}
public function test_store_accepts_valid_specs_and_persists_rows(): void
{
Sanctum::actingAs($this->admin);
$response = $this->postJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields",
[
'field_type' => FormFieldType::TEXT->value,
'slug' => 'voornaam',
'label' => 'Voornaam',
'validation_rules' => [
['rule_type' => 'min_length', 'parameters' => ['value' => 2]],
['rule_type' => 'max_length', 'parameters' => ['value' => 40]],
],
],
);
$response->assertCreated();
$fieldId = $response->json('data.id');
$rules = FormFieldValidationRule::query()
->where('owner_type', 'form_field')
->where('owner_id', $fieldId)
->pluck('rule_type')
->map(static fn ($r) => $r instanceof \BackedEnum ? $r->value : (string) $r)
->sort()->values()->all();
$this->assertSame(['max_length', 'min_length'], $rules);
// The JSON column is not written on the service path — stays null
// until commit 5 drops it.
$this->assertNull(FormField::query()->findOrFail($fieldId)->validation_rules);
}
public function test_update_empty_array_clears_rules(): void
{
Sanctum::actingAs($this->admin);
$field = FormField::factory()->create(['form_schema_id' => $this->schema->id]);
FormFieldValidationRule::factory()->forField($field)->create();
$this->assertCount(1, $field->fresh()->validationRules);
$response = $this->putJson(
"/api/v1/organisations/{$this->org->id}/forms/schemas/{$this->schema->id}/fields/{$field->id}",
['validation_rules' => []],
);
$response->assertOk();
$this->assertCount(0, $field->fresh()->validationRules);
}
}