destroy(); Services::resetSingle('response'); } public function testGetTimeoutConfigIncludesThirtyMinuteSettings(): void { $this->expectOutputRegex('/^\s*$/'); $response = $this->controller()->getTimeoutConfig(); $body = json_decode((string) $response->getBody(), true); $this->assertTrue($body['success']); $this->assertSame(1800, $body['timeout']); $this->assertSame(300, $body['warning_time']); $this->assertStringContainsString('session/check-timeout', $body['check_url']); $this->assertStringContainsString('session/ping-activity', $body['keep_alive_url']); } public function testCheckTimeoutReturnsActiveWhenFresh(): void { session()->set('last_activity', time()); $response = $this->controller()->checkTimeout(); $body = json_decode((string) $response->getBody(), true); $this->assertSame('active', $body['status']); $this->assertGreaterThan(0, $body['time_remaining']); } public function testCheckTimeoutExpiresAfterThirtyMinutesOfInactivity(): void { session()->set('last_activity', time() - 1800); $response = $this->controller()->checkTimeout(); $body = json_decode((string) $response->getBody(), true); $this->assertSame('expired', $body['status']); $this->assertStringContainsString('login', $body['redirect']); } public function testPingActivityRefreshesSession(): void { session()->set('last_activity', time() - 60); $response = $this->controller()->pingActivity(); $body = json_decode((string) $response->getBody(), true); $this->assertSame('active', $body['status']); $this->assertSame(1800, $body['time_remaining']); $this->assertGreaterThanOrEqual(time() - 1, session()->get('last_activity')); } private function controller(): SessionTimeoutController { Services::resetSingle('response'); $controller = new SessionTimeoutController(); $request = new IncomingRequest(config(App::class), new URI('https://example.test/session/check-timeout'), 'php://input', new UserAgent()); $controller->initController($request, Services::response(), Services::logger()); return $controller; } }