withoutVite(); Storage::fake('local'); config(['portal.legacy_content_qa_enabled' => true, 'investor-path.enabled' => true]); $bytes = json_encode(['format' => 'investmoz-legacy-article-v1', 'source_url' => 'https://investemoz.tempo.co.mz/agronegocio', 'content_html' => '

Conhecer corredores

Link', 'title' => 'Agronegocio', 'author' => 'Autor sintético', 'legacy_id' => 171985, 'legacy_category' => 'Oportunidades', 'published_at' => '2026-04-06T09:19:07+00:00', 'modified_at' => '2026-04-20T12:41:43+00:00'], JSON_THROW_ON_ERROR); $id = (string) Str::uuid(); Storage::disk('local')->put('legacy/'.$id, $bytes); DB::table('documents')->insert(['id' => $id, 'source_system' => 'synthetic-test', 'external_id' => 'legacy-tempo-post-171985-20260420', 'file_name' => 'source.json', 'media_type' => 'application/json', 'storage_key' => 'legacy/'.$id, 'sha256' => hash('sha256', $bytes), 'malware_scanned_sha256' => hash('sha256', $bytes), 'malware_scan_status' => 'clean', 'size_bytes' => strlen($bytes), 'status' => 'active', 'rights_status' => 'authorized', 'data_classification' => 'public']); $this->resource = DB::table('portal_resources')->insertGetId(['document_id' => $id, 'title' => 'Agronegocio', 'category' => 'education', 'topic' => 'agronegocio', 'published' => true, 'rights_status' => 'authorized', 'source_url' => 'https://investemoz.tempo.co.mz/agronegocio', 'source_reference' => 'Exemplar sintético; não oficial.', 'metadata_version' => 1]); } public function test_public_read_search_and_sanitization_do_not_create_opportunities_and_private_sources_are_hidden(): void { $count = DB::table('opportunities')->count(); $this->get('/agronegocio')->assertOk()->assertInertia(fn (Assert $page) => $page->component('portal/legacy') ->where('article.id', $this->resource)->where('article.calculation_use', false)); $html = app(LegacyContent::class)->article()['html']; $this->assertStringNotContainsString('script', $html); $this->assertStringNotContainsString('javascript', $html); $this->assertStringNotContainsString('onclick', $html); $this->get('/explorar/agronegocio?q=corredores')->assertOk()->assertInertia(fn (Assert $page) => $page->where('match', true)); $this->get('/explorar/agronegocio?q=absent')->assertOk()->assertInertia(fn (Assert $page) => $page->where('match', false)); $this->getJson('/investimentos/a-partir-de/agronegocio')->assertUnauthorized(); $this->assertSame($count, DB::table('opportunities')->count()); DB::table('portal_resources')->where('id', $this->resource)->update(['published' => false]); $this->get('/agronegocio')->assertNotFound(); config(['portal.legacy_content_qa_enabled' => false]); $this->get('/explorar/agronegocio')->assertNotFound(); } public function test_original_heading_text_is_preserved_with_an_accessible_article_hierarchy(): void { $source = '

Turismo

Territórios

Localizações

'; $html = app(LegacyContent::class)->sanitize($source); $this->assertSame('

Turismo

Territórios

Localizações

', $html); $this->assertSame('

Secção

Subsecção

', app(LegacyContent::class)->sanitize('

Secção

Subsecção

')); $this->assertStringContainsString('

Turismo

', $source); } public function test_source_is_saved_once_in_existing_dossier_recovered_and_isolated_from_other_accounts_and_projects(): void { $owner = User::factory()->create(); $other = User::factory()->create(); $data = ['title' => 'Ideia sintética', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'content_resource_id' => $this->resource]; $case = $this->actingAs($owner)->postJson('/investimentos', $data)->assertCreated()->json('id'); $first = $this->getJson('/investimentos/'.$case)->assertOk()->json(); $this->assertCount(19, $first['steps']); $this->assertCount(5, $first['phases']); $this->assertSame($this->resource, $first['content_sources'][0]['resource_id']); $this->postJson('/investimentos/'.$case.'/conteudos', ['version' => $first['case']['version'], 'resource_id' => $this->resource])->assertOk(); $again = $this->getJson('/investimentos/'.$case)->assertOk()->json(); $this->assertSame($first['case']['version'], $again['case']['version']); $this->assertSame($first['content_sources'], $again['content_sources']); $this->assertSame($case, $this->postJson('/investimentos', $data)->assertCreated()->json('id')); $this->actingAs($other)->getJson('/investimentos/'.$case)->assertForbidden(); $this->postJson('/investimentos/'.$case.'/conteudos', ['version' => $first['case']['version'], 'resource_id' => $this->resource])->assertForbidden(); $this->actingAs($owner); unset($data['content_resource_id']); $data['client_key'] = (string) Str::uuid(); $independent = $this->postJson('/investimentos', $data)->assertCreated()->json('id'); $this->assertSame([], $this->getJson('/investimentos/'.$independent)->assertOk()->json('content_sources')); $before = DB::table('desk_cases')->count(); $data['client_key'] = (string) Str::uuid(); $data['content_resource_id'] = $this->resource + 100; $this->postJson('/investimentos', $data)->assertUnprocessable(); $this->assertSame($before, DB::table('desk_cases')->count()); } private function sectorArticle(string $slug, string $title, string $body): int { $identity = config('legacy_content.articles.'.$slug); $document = (string) Str::uuid(); $bytes = json_encode(['format' => 'investmoz-legacy-article-v1', 'source_url' => $identity['source_url'], 'content_html' => $body, 'title' => $title, 'author' => 'Autor sintético', 'legacy_id' => 123, 'legacy_category' => 'Turismo', 'published_at' => '2026-04-01T00:00:00+00:00', 'modified_at' => '2026-04-02T00:00:00+00:00'], JSON_THROW_ON_ERROR); Storage::disk('local')->put('legacy/'.$document, $bytes); DB::table('documents')->insert(['id' => $document, 'source_system' => 'synthetic-test', 'external_id' => $identity['external_id'], 'file_name' => 'source.json', 'media_type' => 'application/json', 'storage_key' => 'legacy/'.$document, 'sha256' => hash('sha256', $bytes), 'malware_scanned_sha256' => hash('sha256', $bytes), 'malware_scan_status' => 'clean', 'size_bytes' => strlen($bytes), 'status' => 'active', 'rights_status' => 'authorized', 'data_classification' => 'public']); return DB::table('portal_resources')->insertGetId(['document_id' => $document, 'title' => $title, 'category' => 'education', 'topic' => $identity['sector_slug'], 'published' => true, 'rights_status' => 'authorized', 'source_url' => $identity['source_url'], 'source_reference' => 'Exemplar sintético.', 'metadata_version' => 1]); } public function test_energy_and_mining_remain_distinct_and_each_reference_returns_to_its_article(): void { $this->sectorArticle('energia-mineracao', 'Energia e Mineração', 'EnergiaMineração'); $energy = $this->sectorArticle('energia', 'Energia', '

Rede e geração.

'); $mining = $this->sectorArticle('mineracao', 'Mineração', '

Recursos minerais.

'); $this->get('/explorar/energia-mineracao?q=geração')->assertOk()->assertInertia(fn (Assert $page) => $page->has('articles', 1)->where('articles.0.id', $energy)); $index = app(LegacyContent::class)->article('energia-mineracao'); $this->assertStringContainsString('href="/energia"', $index['html']); $this->assertStringContainsString('href="/mineracao"', $index['html']); $owner = User::factory()->create(); $case = $this->actingAs($owner)->postJson('/investimentos', ['title' => 'Energia sintética', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'content_resource_id' => $energy])->assertCreated()->json('id'); $first = $this->getJson('/investimentos/'.$case)->assertOk()->json(); $this->postJson('/investimentos/'.$case.'/conteudos', ['version' => $first['case']['version'], 'resource_id' => $mining])->assertOk(); $sources = $this->getJson('/investimentos/'.$case)->assertOk()->json('content_sources'); $this->assertSame(['/energia', '/mineracao'], array_column($sources, 'return_href')); $this->assertSame([$energy, $mining], array_column($sources, 'resource_id')); DB::table('portal_resources')->where('id', $mining)->update(['published' => false]); $this->get('/mineracao')->assertNotFound(); $this->assertStringContainsString('https://investemoz.tempo.co.mz/mineracao', app(LegacyContent::class)->article('energia-mineracao')['html']); } public function test_tourism_is_textual_and_empty_financial_source_is_not_a_published_article(): void { $this->sectorArticle('turismo', 'Turismo', '

Província da Zambézia e turismo.

'); $tourism = app(LegacyContent::class)->article('turismo'); $this->assertSame([], $tourism['territorial_references']); $this->assertFalse(DB::table('portal_resource_links')->where('target_type', 'territory')->exists()); $finance = $this->sectorArticle('mercado-financeiro', 'Mercado Financeiro', ''); $this->get('/mercado-financeiro')->assertNotFound(); $this->get('/explorar/mercado-financeiro')->assertNotFound(); $this->actingAs(User::factory()->create())->postJson('/investimentos', ['title' => 'Ideia', 'client_key' => (string) Str::uuid(), 'reuse_consent' => true, 'content_resource_id' => $finance])->assertUnprocessable(); } }