schema = FormSchema::factory()->create(); $this->submission = FormSubmission::factory()->create([ 'form_schema_id' => $this->schema->id, ]); } public function test_string_hint_populates_value_indexed_when_filterable(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::TEXT->value, 'value_storage_hint' => FormValueStorageHint::STRING, 'is_filterable' => true, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => 'Bert Hausmans'], ]); $this->assertSame('Bert Hausmans', $value->fresh()->value_indexed); $this->assertNull($value->value_number); $this->assertNull($value->value_date); $this->assertNull($value->value_bool); } public function test_string_hint_leaves_value_indexed_null_when_not_filterable(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::TEXT->value, 'value_storage_hint' => FormValueStorageHint::STRING, 'is_filterable' => false, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => 'Niet-filterable tekst'], ]); $this->assertNull($value->fresh()->value_indexed); } public function test_number_hint_populates_value_number(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::NUMBER->value, 'value_storage_hint' => FormValueStorageHint::NUMBER, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => 42.5], ]); $this->assertEqualsWithDelta(42.5, (float) $value->fresh()->value_number, 0.0001); $this->assertNull($value->fresh()->value_indexed); } public function test_date_hint_populates_value_date(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::DATE->value, 'value_storage_hint' => FormValueStorageHint::DATE, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => '2026-07-04'], ]); $this->assertSame('2026-07-04', $value->fresh()->value_date->format('Y-m-d')); } public function test_bool_hint_populates_value_bool(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::BOOLEAN->value, 'value_storage_hint' => FormValueStorageHint::BOOL, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => true], ]); $this->assertTrue($value->fresh()->value_bool); } public function test_json_hint_leaves_typed_columns_null(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::TABLE_ROWS->value, 'value_storage_hint' => FormValueStorageHint::JSON, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => [['col_a' => 'x', 'col_b' => 'y']], ]); $fresh = $value->fresh(); $this->assertNull($fresh->value_indexed); $this->assertNull($fresh->value_number); $this->assertNull($fresh->value_date); $this->assertNull($fresh->value_bool); } public function test_filterable_multiselect_rebuilds_pivot(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::MULTISELECT->value, 'value_storage_hint' => FormValueStorageHint::JSON, 'is_filterable' => true, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['XS', 'M', 'XXL'], ]); $options = FormValueOption::where('form_value_id', $value->id) ->pluck('option_value') ->sort() ->values() ->all(); $this->assertSame(['M', 'XS', 'XXL'], $options); } public function test_resave_rebuilds_pivot_idempotently(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::MULTISELECT->value, 'is_filterable' => true, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['A', 'B'], ]); $this->assertSame(2, FormValueOption::where('form_value_id', $value->id)->count()); // Resave with different options. $value->value = ['C']; $value->save(); $options = FormValueOption::where('form_value_id', $value->id) ->pluck('option_value') ->all(); $this->assertSame(['C'], $options); } public function test_non_filterable_field_does_not_populate_pivot(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::MULTISELECT->value, 'is_filterable' => false, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['A', 'B'], ]); $this->assertSame(0, FormValueOption::where('form_value_id', $value->id)->count()); } public function test_single_value_filterable_populates_value_indexed_even_when_hint_is_json(): void { $field = FormField::factory()->for($this->schema, 'schema')->create([ 'field_type' => FormFieldType::SELECT->value, 'value_storage_hint' => FormValueStorageHint::JSON, 'is_filterable' => true, ]); $value = FormValue::create([ 'form_submission_id' => $this->submission->id, 'form_field_id' => $field->id, 'value' => ['value' => 'beta'], ]); $this->assertSame('beta', $value->fresh()->value_indexed); } }