bootApp(); } public function testHomeRedirectsToLoginWhenAnonymous(): void { $response = $this->request('GET', '/'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/login', $response->getHeaderLine('Location')); } public function testHomeRedirectsToDashboardWhenAuthenticated(): void { $_SESSION['_user'] = (new UserContext(1, 'Admin', 'admin', null, UserContext::SOURCE_LOCAL))->toArray(); $_SESSION['_last_active'] = time(); $_SESSION['_authenticated_at'] = time(); $response = $this->request('GET', '/'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/app/dashboard', $response->getHeaderLine('Location')); } public function testHealthzReturnsOk(): void { $response = $this->request('GET', '/healthz'); self::assertSame(200, $response->getStatusCode()); $body = json_decode((string) $response->getBody(), true); self::assertSame('ok', $body['status']); self::assertArrayHasKey('api_reachable', $body); self::assertArrayHasKey('last_api_check_at', $body); } public function testAppMeRedirectsAnonymousToLogin(): void { $response = $this->request('GET', '/app/me'); self::assertSame(302, $response->getStatusCode()); self::assertSame('/login', $response->getHeaderLine('Location')); self::assertSame('/app/me', $_SESSION['_next'] ?? null); } public function testAppMeRendersForLoggedInUser(): void { $_SESSION['_user'] = (new UserContext(7, 'Admin', 'admin', 'a@x', UserContext::SOURCE_LOCAL))->toArray(); $_SESSION['_last_active'] = time(); $_SESSION['_authenticated_at'] = time(); $this->enqueueApiResponse(200, [ 'user_id' => 7, 'role' => 'admin', 'email' => 'a@x', 'display_name' => 'Admin', 'is_local' => true, ]); $response = $this->request('GET', '/app/me'); self::assertSame(200, $response->getStatusCode()); $body = (string) $response->getBody(); self::assertStringContainsString('My identity', $body); self::assertStringContainsString('admin', $body); self::assertStringContainsString('7', $body); } public function testNoAccessPageRenders(): void { $response = $this->request('GET', '/no-access'); self::assertSame(200, $response->getStatusCode()); self::assertStringContainsString('No access', (string) $response->getBody()); } }