true]); $this->withoutVite(); }); test('anonymous visitors enter the real dashboard without creating an authenticated identity', function () { $this->get('/')->assertRedirect('/dashboard'); $this->get('/dashboard')->assertInertia(fn (Assert $p) => $p->component('dashboard')->where('auth.user', null)->where('company', null)->where('stats.total', 0)->where('publicNavigation.dataScope', 'none')); $this->assertGuest('web'); expect(User::query()->count())->toBe(0); }); test('all allowlisted real screens support direct anonymous navigation without business queries', function () { $queries = []; DB::listen(function ($query) use (&$queries) { $queries[] = $query->sql; }); $fixtures = []; foreach (PublicNavigation::PAGES as $path => $component) { $response = $this->get($path)->assertOk()->assertInertia(fn (Assert $p) => $p->component($component)->where('auth.user', null)); $fixtures[$component] = $response->original->getData()['page']; $this->assertGuest('web'); } expect($queries)->toBe([]); file_put_contents(storage_path('app/private/public-navigation-fixtures.json'), json_encode($fixtures, JSON_THROW_ON_ERROR)); }); test('anonymous searches pagination and filters stay empty and never select either organisation', function () { foreach (['Empresa reservada A', 'Empresa reservada B'] as $name) { $tenant = Tenant::query()->create(['name' => $name]); User::factory()->create(['tenant_id' => $tenant->id, 'name' => 'Nome confidencial']); } $this->get('/requisicoes?search=Empresa&page=2&status=pending')->assertInertia(fn (Assert $p) => $p->where('filters.search', 'Empresa')->where('requisitions.data', [])->where('requisitions.current_page', 2))->assertDontSee('Nome confidencial')->assertDontSee('Empresa reservada'); $this->get('/stock?search=Nome&warehouse_id=1')->assertInertia(fn (Assert $p) => $p->where('items', [])->where('filters.search', 'Nome')); }); test('sensitive records access settings exports and every business write remain authenticated', function () { foreach (['/pessoas/cadastro', '/pessoas/1', '/fornecedores/1/dados-bancarios', '/administracao/parametrizacao', '/relatorios', '/relatorios/compras.csv', '/settings/profile'] as $path) { $this->get($path)->assertRedirect(); } $this->get('/api/supplier-payables')->assertUnauthorized(); foreach (['/requisicoes', '/pessoas', '/stock/artigos', '/administracao/parametrizacao/tax'] as $path) { $this->postJson($path, [])->assertUnauthorized(); } }); test('authenticated sessions retain their original controllers and permissions and disabled mode remains private', function () { $tenant = Tenant::query()->create(['name' => 'Empresa autenticada']); $user = User::factory()->create(['tenant_id' => $tenant->id, 'purchasing_role' => PurchasingRole::Requester]); $this->actingAs($user)->get('/dashboard')->assertInertia(fn (Assert $p) => $p->where('company.name', 'Empresa autenticada')->missing('publicNavigation')); $this->get('/administracao/parametrizacao')->assertForbidden(); auth()->logout(); config(['public_navigation.enabled' => false]); $this->get('/dashboard')->assertRedirect(); }); test('every authenticated mutation route remains inaccessible to an anonymous visitor', function () { $checked = 0; foreach (Route::getRoutes() as $route) { if (! collect($route->gatherMiddleware())->contains(fn ($middleware) => $middleware === 'auth' || str_starts_with($middleware, 'auth:'))) { continue; } $uri = '/'.preg_replace('/\{[^}]+\}/', '1', $route->uri()); foreach (array_intersect($route->methods(), ['POST', 'PUT', 'PATCH', 'DELETE']) as $method) { $response = $this->json($method, $uri, []); expect(in_array($response->status(), [401, 404], true))->toBeTrue($method.' '.$uri.' must remain protected'); $checked++; } } expect($checked)->toBeGreaterThan(50); $this->assertGuest('web'); });