f = receiptFixture(); $this->admin = User::factory()->create(['tenant_id' => $this->f['tenant']->id, 'department_id' => $this->f['department']->id, 'purchasing_role' => PurchasingRole::Admin]); $this->actingAs($this->admin); $this->url = '/administracao/candidaturas/formularios'; $this->body = ['audience' => 'staff', 'modality' => 'competition', 'version' => 0, 'reason' => 'Configuração fictícia para receber candidaturas.', 'definition' => ['available' => true, 'fields' => [['key' => 'full_name', 'label' => 'Nome completo', 'type' => 'text', 'required' => true]], 'documents' => [['key' => 'cv', 'label' => 'CV', 'required' => true, 'formats' => ['pdf'], 'max_kb' => 1024]]]]; }); test('forms start unconfigured and preserve each company audience modality and historical definition', function () { $this->get($this->url)->assertInertia(fn (Assert $p) => $p->has('forms', 6)->where('forms.0.version', 0)->where('forms.0.definition.available', false)->where('externalPortalAvailable', false)); $this->postJson($this->url, $this->body)->assertRedirect(); $this->postJson($this->url, [...$this->body, 'version' => 1, 'definition' => [...$this->body['definition'], 'available' => false]])->assertRedirect(); $this->get($this->url)->assertInertia(fn (Assert $p) => $p->where('forms.0.version', 2)->where('forms.0.definition.available', false)->where('forms.0.history.1.definition.available', true)->where('forms.1.version', 0)->where('forms.2.version', 0)->where('forms.4.version', 0)); $other = receiptFixture(); $otherAdmin = User::factory()->create(['tenant_id' => $other['tenant']->id, 'department_id' => $other['department']->id, 'purchasing_role' => PurchasingRole::Admin]); $this->actingAs($otherAdmin)->get($this->url)->assertInertia(fn (Assert $p) => $p->where('forms.0.version', 0)->where('forms.0.history', [])); }); test('stale forms unsafe formats duplicate identifiers and empty available forms are rejected', function () { $this->postJson($this->url, $this->body)->assertRedirect(); $this->postJson($this->url, $this->body)->assertUnprocessable(); $bad = [...$this->body, 'version' => 1]; $bad['definition']['documents'][0]['formats'] = ['exe']; $this->postJson($this->url, $bad)->assertUnprocessable(); $bad['definition'] = [...$this->body['definition'], 'fields' => []]; $this->postJson($this->url, $bad)->assertUnprocessable(); $bad['definition'] = $this->body['definition']; $bad['definition']['fields'][] = $bad['definition']['fields'][0]; $this->postJson($this->url, $bad)->assertUnprocessable(); expect(DB::table('submission_forms')->count())->toBe(1); }); test('non administrators cannot read or write forms and audit failure rolls back a version', function () { $this->actingAs($this->f['receiver'])->get($this->url)->assertForbidden(); $this->postJson($this->url, $this->body)->assertForbidden(); $this->actingAs($this->admin); $this->mock(RequisitionWorkflow::class)->shouldReceive('audit')->once()->andThrow(new RuntimeException('Injected forms audit failure')); $this->withoutExceptionHandling(); expect(fn () => $this->postJson($this->url, $this->body))->toThrow(RuntimeException::class); expect(DB::table('submission_forms')->count())->toBe(0); }); test('separate required documents can share a format', function () { $this->body['definition']['documents'][] = ['key' => 'certificate', 'label' => 'Certificado', 'required' => false, 'formats' => ['pdf'], 'max_kb' => 1024]; $this->postJson($this->url, $this->body)->assertRedirect(); expect(DB::table('submission_forms')->count())->toBe(1); });