172 lines
5.7 KiB
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);
|
|
}
|
|
}
|