create(); $field = FormField::factory()->create([ 'form_schema_id' => $schema->id, 'slug' => 'comments', 'field_type' => FormFieldType::TEXT->value, ]); $submission = FormSubmission::factory()->create([ 'form_schema_id' => $schema->id, 'organisation_id' => $schema->organisation_id, ]); $this->app->make(FormValueService::class)->upsertMany( $submission, ['comments' => ''], null, ); $row = FormValue::query() ->withoutGlobalScopes() ->where('form_submission_id', $submission->id) ->where('form_field_id', $field->id) ->first(); $this->assertNotNull($row, 'A form_value row MUST exist for an explicitly-blank submitted field (RFC Q7 invariant).'); } public function test_field_not_submitted_has_no_form_value_row(): void { // Absence in slugToValue โ†’ no row written. This is the "skipped by // conditional logic" path that RFC Q7 distinguishes from explicit // null โ€” the resolver excludes it from the candidate set. $schema = FormSchema::factory()->create(); $field = FormField::factory()->create([ 'form_schema_id' => $schema->id, 'slug' => 'visible_field', ]); $submission = FormSubmission::factory()->create([ 'form_schema_id' => $schema->id, 'organisation_id' => $schema->organisation_id, ]); $this->app->make(FormValueService::class)->upsertMany($submission, [], null); $row = FormValue::query() ->withoutGlobalScopes() ->where('form_submission_id', $submission->id) ->where('form_field_id', $field->id) ->first(); $this->assertNull($row, 'Absent form_field MUST have no form_value row (RFC Q7 invariant).'); } }