File manager - Edit - /var/www/html/homologBancodetalentos/tests/Feature/TalentBank/ReportParityTest.php
Back
<?php namespace Tests\Feature\TalentBank; use App\Models\TalentBank\Candidate; use App\Models\TalentBank\Ethnicity; use App\Models\TalentBank\Gender; use App\Models\TalentBank\Neighbourhood; use App\Models\TalentBank\Occupation; use Illuminate\Foundation\Testing\DatabaseTransactions; use Illuminate\Support\Carbon; use Tests\TestCase; /** * Congela o contrato mínimo do endpoint GET /api/talent-bank/report/candidate * e verifica paridade com o legado (SIATI) para todos os filtros relevantes: * ethnicity, age_between, neighbourhoods, occupations. */ class ReportParityTest extends TestCase { use DatabaseTransactions; protected function setUp(): void { parent::setUp(); config(['talent_bank.bypass_auth' => true]); } // ────────────────────────────────────────────── // Helpers de fixture // ────────────────────────────────────────────── private function ethnicity(string $name): Ethnicity { return Ethnicity::firstOrCreate(['name' => $name]); } private function gender(string $name): Gender { return Gender::firstOrCreate(['name' => $name]); } private function neighbourhood(string $suffix = ''): Neighbourhood { return Neighbourhood::query()->create(['name' => 'Bairro Parity '.$suffix.uniqid()]); } private function occupation(string $suffix = ''): Occupation { return Occupation::query()->create(['name' => 'Cargo Parity '.$suffix.uniqid()]); } /** Cria um candidato com defaults mínimos e permite sobrescrever campos. */ private function candidate(array $attrs = []): Candidate { return Candidate::query()->create(array_merge([ 'cpf' => (string) random_int(10000000000, 99999999999), 'name' => 'Candidato Parity '.uniqid(), 'email' => 'rpt+'.uniqid().'@example.com', 'active' => true, 'neighbourhood_id' => $attrs['neighbourhood_id'] ?? $this->neighbourhood()->id, 'occupation_id' => $attrs['occupation_id'] ?? $this->occupation()->id, 'gender_id' => $attrs['gender_id'] ?? $this->gender('Outro')->id, 'ethnicity_id' => $attrs['ethnicity_id'] ?? $this->ethnicity('Pardo')->id, ], $attrs)); } // ────────────────────────────────────────────── // 1. Contrato mínimo do payload // ────────────────────────────────────────────── public function test_report_payload_minimum_contract_shape(): void { $this->candidate(); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0'); $r->assertOk(); $r->assertJsonStructure([ 'data' => [ 'list' => [ 'candidates' => [ '*' => ['id', 'cpf', 'name', 'ethnicity', 'neighbourhood'], ], ], 'counters' => [ 'total', 'brancos', 'pretos', 'pardos', 'indigenas', 'amarelos', 'feminino', 'masculino', 'outro', 'special_needs', ], ], 'message', ]); } // ────────────────────────────────────────────── // 2. Ethnicity: string no payload (compat legado) // ────────────────────────────────────────────── /** * Legado retornava `"ethnicity": "Branco"` (coluna texto). * Novo usa ethnicity_id + relacionamento, mas deve serializar o nome — não um objeto. */ public function test_report_ethnicity_field_in_list_is_string_compatible_with_legacy(): void { $this->candidate(['ethnicity_id' => $this->ethnicity('Branco')->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0ðnicity=Branco'); $r->assertOk(); $candidates = $r->json('data.list.candidates'); $this->assertNotEmpty($candidates); foreach ($candidates as $c) { $this->assertIsString($c['ethnicity'], '"ethnicity" deve ser string para manter compatibilidade com legado'); $this->assertSame('Branco', $c['ethnicity']); } } // ────────────────────────────────────────────── // 3. Filtro ?ethnicity= // ────────────────────────────────────────────── public function test_ethnicity_filter_returns_only_matching_candidates(): void { $branco = $this->ethnicity('Branco'); $pardo = $this->ethnicity('Pardo'); $a = $this->candidate(['ethnicity_id' => $branco->id]); $b = $this->candidate(['ethnicity_id' => $branco->id]); $c = $this->candidate(['ethnicity_id' => $pardo->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0ðnicity=Branco'); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($a->id, $ids); $this->assertContains($b->id, $ids); $this->assertNotContains($c->id, $ids); } /** Quando ?ethnicity= está presente, os contadores de etnia devem ser suprimidos — idêntico ao legado. */ public function test_ethnicity_filter_suppresses_ethnicity_counters(): void { $this->candidate(['ethnicity_id' => $this->ethnicity('Branco')->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0ðnicity=Branco'); $r->assertOk(); $counters = $r->json('data.counters'); $this->assertArrayNotHasKey('brancos', $counters); $this->assertArrayNotHasKey('pretos', $counters); $this->assertArrayNotHasKey('pardos', $counters); $this->assertArrayNotHasKey('indigenas', $counters); $this->assertArrayNotHasKey('amarelos', $counters); } /** Sem ?ethnicity=, todos os cinco contadores de etnia devem aparecer — idêntico ao legado. */ public function test_no_ethnicity_filter_includes_all_ethnicity_counters(): void { $this->candidate(['ethnicity_id' => $this->ethnicity('Branco')->id]); $this->candidate(['ethnicity_id' => $this->ethnicity('Preto')->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0'); $r->assertOk(); $counters = $r->json('data.counters'); foreach (['brancos', 'pretos', 'pardos', 'indigenas', 'amarelos'] as $key) { $this->assertArrayHasKey($key, $counters, "Contador \"{$key}\" ausente sem filtro de etnia"); } } public function test_ethnicity_counter_values_match_actual_db_counts(): void { $branco = $this->ethnicity('Branco'); $preto = $this->ethnicity('Preto'); $this->candidate(['ethnicity_id' => $branco->id]); $this->candidate(['ethnicity_id' => $branco->id]); $this->candidate(['ethnicity_id' => $preto->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0'); $r->assertOk(); $counters = $r->json('data.counters'); $this->assertGreaterThanOrEqual(2, $counters['brancos']); $this->assertGreaterThanOrEqual(1, $counters['pretos']); } // ────────────────────────────────────────────── // 4. Filtro ?age_between= // ────────────────────────────────────────────── public function test_age_between_filter_returns_candidates_in_range(): void { $inside1 = $this->candidate(['birth_date' => Carbon::now()->subYears(28)->format('Y-m-d')]); $inside2 = $this->candidate(['birth_date' => Carbon::now()->subYears(32)->format('Y-m-d')]); $outside = $this->candidate(['birth_date' => Carbon::now()->subYears(45)->format('Y-m-d')]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&age_between=25,35'); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($inside1->id, $ids, 'Candidato de 28 anos deve estar na faixa 25-35'); $this->assertContains($inside2->id, $ids, 'Candidato de 32 anos deve estar na faixa 25-35'); $this->assertNotContains($outside->id, $ids, 'Candidato de 45 anos não deve estar na faixa 25-35'); } public function test_age_between_excludes_candidates_without_birth_date(): void { $no_birth = $this->candidate(); // birth_date = null $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&age_between=20,40'); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertNotContains($no_birth->id, $ids, 'Candidato sem birth_date não deve aparecer em filtro de faixa etária'); } // ────────────────────────────────────────────── // 5. Filtro ?neighbourhoods= // ────────────────────────────────────────────── public function test_neighbourhoods_filter_returns_only_matching_candidates(): void { $bairroA = $this->neighbourhood('A'); $bairroB = $this->neighbourhood('B'); $inA = $this->candidate(['neighbourhood_id' => $bairroA->id]); $inB = $this->candidate(['neighbourhood_id' => $bairroB->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&neighbourhoods='.$bairroA->id); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($inA->id, $ids); $this->assertNotContains($inB->id, $ids); } /** O legado adicionava contadores indexados pelo nome do bairro — o novo deve fazer o mesmo. */ public function test_neighbourhoods_filter_adds_per_neighbourhood_counters_by_name(): void { $bairroA = $this->neighbourhood('A'); $this->candidate(['neighbourhood_id' => $bairroA->id]); $this->candidate(['neighbourhood_id' => $bairroA->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&neighbourhoods='.$bairroA->id); $r->assertOk(); $counters = $r->json('data.counters'); $this->assertArrayHasKey('neighbourhoods', $counters, 'Contador de bairros ausente'); $this->assertArrayHasKey($bairroA->name, $counters['neighbourhoods'], "Nome do bairro ausente nos contadores"); $this->assertSame(2, $counters['neighbourhoods'][$bairroA->name]); } public function test_neighbourhoods_filter_supports_multiple_ids_comma_separated(): void { $bairroA = $this->neighbourhood('A'); $bairroB = $this->neighbourhood('B'); $bairroC = $this->neighbourhood('C'); $inA = $this->candidate(['neighbourhood_id' => $bairroA->id]); $inB = $this->candidate(['neighbourhood_id' => $bairroB->id]); $inC = $this->candidate(['neighbourhood_id' => $bairroC->id]); $r = $this->getJson("/api/talent-bank/report/candidate?paginate=0&neighbourhoods={$bairroA->id},{$bairroB->id}"); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($inA->id, $ids); $this->assertContains($inB->id, $ids); $this->assertNotContains($inC->id, $ids); } // ────────────────────────────────────────────── // 6. Filtro ?occupations= // ────────────────────────────────────────────── public function test_occupations_filter_returns_only_matching_candidates(): void { $occA = $this->occupation('A'); $occB = $this->occupation('B'); $inA = $this->candidate(['occupation_id' => $occA->id]); $inB = $this->candidate(['occupation_id' => $occB->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&occupations='.$occA->id); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($inA->id, $ids); $this->assertNotContains($inB->id, $ids); } /** O legado adicionava contadores indexados pelo nome da ocupação — o novo deve fazer o mesmo. */ public function test_occupations_filter_adds_per_occupation_counters_by_name(): void { $occA = $this->occupation('A'); $this->candidate(['occupation_id' => $occA->id]); $this->candidate(['occupation_id' => $occA->id]); $r = $this->getJson('/api/talent-bank/report/candidate?paginate=0&occupations='.$occA->id); $r->assertOk(); $counters = $r->json('data.counters'); $this->assertArrayHasKey('occupations', $counters, 'Contador de ocupações ausente'); $this->assertArrayHasKey($occA->name, $counters['occupations'], 'Nome da ocupação ausente nos contadores'); $this->assertSame(2, $counters['occupations'][$occA->name]); } public function test_occupations_filter_supports_multiple_ids_comma_separated(): void { $occA = $this->occupation('A'); $occB = $this->occupation('B'); $occC = $this->occupation('C'); $inA = $this->candidate(['occupation_id' => $occA->id]); $inB = $this->candidate(['occupation_id' => $occB->id]); $inC = $this->candidate(['occupation_id' => $occC->id]); $r = $this->getJson("/api/talent-bank/report/candidate?paginate=0&occupations={$occA->id},{$occB->id}"); $r->assertOk(); $ids = array_column($r->json('data.list.candidates'), 'id'); $this->assertContains($inA->id, $ids); $this->assertContains($inB->id, $ids); $this->assertNotContains($inC->id, $ids); } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.28 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings