Mostrar oportunidades publicadas antes do registo de candidatos

This commit is contained in:
2026-10-30 21:15:27 +02:00
parent bf84575d10
commit c22846b2b1
10 changed files with 528 additions and 8 deletions
@@ -12,6 +12,7 @@ use App\Services\RequisitionWorkflow;
use App\Services\SubmissionForms;
use Illuminate\Database\QueryException;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
@@ -44,6 +45,43 @@ beforeEach(function () {
'answers' => ['full_name' => 'Pessoa fictícia', 'availability_location' => $this->profile['availability']]];
});
test('guests see only explicitly published public opportunity fields while submission remains authenticated', function () {
Auth::guard('candidate')->logout();
Auth::guard('web')->logout();
$this->get($this->base)->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 1)
->where('opportunities.data.0', ['id' => $this->process->id, 'title' => 'Oportunidade fictícia', 'kind' => 'service', 'closes_on' => $this->process->closes_on, 'description' => $this->publication['description']])
->where('auth.user', null)->where('organizationAccess', null));
$this->get($this->base.'/oportunidades/'.$this->process->id)->assertUnauthorized();
$this->postJson($this->base.'/oportunidades/'.$this->process->id, $this->body)->assertUnauthorized();
expect(DB::table('candidate_submissions')->count())->toBe(0);
$this->actingAs($this->admin);
app(CandidateSubmissions::class)->publish($this->admin, $this->process->id, [...$this->publication, 'version' => 1, 'active' => false]);
$this->get($this->base)->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 0));
app(CandidateSubmissions::class)->publish($this->admin, $this->process->id, [...$this->publication, 'version' => 2]);
$this->travel(8)->days();
$this->get($this->base)->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 0));
});
test('public opportunity listing is paginated within the company and remains visible to existing users when registration closes', function () {
$process = (array) DB::table('people_processes')->where('id', $this->process->id)->first();
$publication = (array) DB::table('candidate_opportunity_publications')->where('people_process_id', $this->process->id)->first();
unset($process['id'], $publication['id']);
for ($index = 0; $index < 12; $index++) {
$id = DB::table('people_processes')->insertGetId([...$process, 'operation_key' => (string) Str::uuid()]);
DB::table('candidate_opportunity_publications')->insert([...$publication, 'people_process_id' => $id]);
}
app(CandidateProfiles::class)->configure($this->admin, ['version' => 1, 'registration_open' => false, 'notice' => 'Aviso fictício de registos temporariamente encerrados.', 'reason' => 'Encerrar novos registos no ensaio.']);
$this->get($this->base)->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 12)->where('opportunities.total', 13)->where('opportunities.next_page_url', $this->base.'?opportunities_page=2')->where('portal.registration_open', false));
$this->get($this->base.'?opportunities_page=2')->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 1));
$this->get($this->base.'/perfil?opportunities_page=2')->assertInertia(fn (Assert $p) => $p->has('opportunities', 1)->where('opportunityPagination.prev', $this->base.'/perfil?opportunities_page=1')->where('opportunityPagination.next', null));
$other = Tenant::query()->create(['name' => 'Empresa sem oportunidades']);
$otherAdmin = User::factory()->create(['tenant_id' => $other->id, 'purchasing_role' => PurchasingRole::Admin]);
$this->actingAs($otherAdmin);
app(CandidateProfiles::class)->configure($otherAdmin, ['version' => 0, 'registration_open' => true, 'notice' => 'Aviso fictício da outra empresa sem oportunidades.', 'reason' => 'Configurar portal separado no ensaio.']);
$this->get('/candidaturas/'.$other->id)->assertInertia(fn (Assert $p) => $p->has('opportunities.data', 0));
$this->getJson($this->base.'?opportunities_page=invalid')->assertUnprocessable();
});
test('electronic submission returns a scoped receipt and preserves the actual profile and answers', function () {
$this->get($this->base.'/oportunidades/'.$this->process->id)->assertInertia(fn (Assert $p) => $p->where('opportunity.description', 'Descrição pública fictícia da oportunidade.')->missing('opportunity.purpose')->missing('opportunity.selection'));
$url = $this->base.'/oportunidades/'.$this->process->id;
+38
View File
@@ -62,6 +62,44 @@ test.each([true, false])(
expect(html).not.toContain('/dashboard');
},
);
test('public entry shows published opportunities and pagination while keeping application behind candidate login', () => {
const initialPage = {
...page,
props: {
...page.props,
company: { id: 1, name: 'Empresa fictícia' },
portal: {
version: 1,
registration_open: false,
notice: 'Aviso fictício.',
},
opportunities: {
data: [
{
id: 7,
title: 'Serviço publicado',
kind: 'service',
closes_on: '2026-11-10',
description: 'Descrição pública do serviço.',
},
],
prev_page_url: null,
next_page_url: '/candidaturas/1?opportunities_page=2',
},
},
};
const html = renderToString(
<App initialPage={initialPage} initialComponent={Entry} />,
);
expect(html).toContain('Serviço publicado');
expect(html).toContain('Descrição pública do serviço.');
expect(html).toContain('Prestação de serviços');
expect(html).toContain('href="#candidate-login"');
expect(html).toContain('/candidaturas/1?opportunities_page=2');
expect(html).not.toContain('/oportunidades/7');
expect(html).not.toContain('anexos ainda está em desenvolvimento');
});
test('candidate profile renders geography and retained version without internal evaluation controls', () => {
const initialPage = {
...page,