diff --git a/tests/Controller/Api/ApiAuthControllerTest.php b/tests/Controller/Api/ApiAuthControllerTest.php new file mode 100644 index 0000000..6e375bd --- /dev/null +++ b/tests/Controller/Api/ApiAuthControllerTest.php @@ -0,0 +1,90 @@ +base64UrlEncode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'])); + $payload = array_merge([ + 'userId' => 42, + 'email' => 'orga@test.com', + 'roles' => ['ROLE_ORGANIZER'], + 'iat' => time(), + 'exp' => time() + 86400, + ], $payloadOverrides); + $payloadB64 = $this->base64UrlEncode(json_encode($payload)); + $signature = $this->base64UrlEncode(hash_hmac('sha256', $header.'.'.$payloadB64, self::SECRET, true)); + + return $header.'.'.$payloadB64.'.'.$signature; + } + + private function base64UrlEncode(string $data): string + { + return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); + } + + public function testVerifyJwtValid(): void + { + $token = $this->generateToken(); + $result = ApiAuthController::verifyJwt($token, 'orga@test.com', self::SECRET); + + self::assertSame(42, $result['userId']); + self::assertFalse($result['expired']); + } + + public function testVerifyJwtExpired(): void + { + $token = $this->generateToken(['exp' => time() - 100]); + $result = ApiAuthController::verifyJwt($token, 'orga@test.com', self::SECRET); + + self::assertSame(42, $result['userId']); + self::assertTrue($result['expired']); + } + + public function testVerifyJwtInvalidSignature(): void + { + $token = $this->generateToken(); + $result = ApiAuthController::verifyJwt($token, 'orga@test.com', 'wrong_secret'); + + self::assertNull($result['userId']); + self::assertFalse($result['expired']); + } + + public function testVerifyJwtWrongEmail(): void + { + $token = $this->generateToken(); + $result = ApiAuthController::verifyJwt($token, 'other@test.com', self::SECRET); + + self::assertNull($result['userId']); + self::assertFalse($result['expired']); + } + + public function testVerifyJwtMalformedToken(): void + { + $result = ApiAuthController::verifyJwt('not.a.valid.token.at.all', 'orga@test.com', self::SECRET); + self::assertNull($result['userId']); + } + + public function testVerifyJwtTooFewParts(): void + { + $result = ApiAuthController::verifyJwt('only.two', 'orga@test.com', self::SECRET); + self::assertNull($result['userId']); + } + + public function testVerifyJwtEmptyPayload(): void + { + $header = $this->base64UrlEncode(json_encode(['alg' => 'HS256'])); + $payloadB64 = $this->base64UrlEncode(''); + $signature = $this->base64UrlEncode(hash_hmac('sha256', $header.'.'.$payloadB64, self::SECRET, true)); + + $result = ApiAuthController::verifyJwt($header.'.'.$payloadB64.'.'.$signature, 'orga@test.com', self::SECRET); + self::assertNull($result['userId']); + } +} diff --git a/tests/Controller/ApiDocControllerTest.php b/tests/Controller/ApiDocControllerTest.php new file mode 100644 index 0000000..51afef2 --- /dev/null +++ b/tests/Controller/ApiDocControllerTest.php @@ -0,0 +1,78 @@ +request('GET', '/api/doc'); + + self::assertResponseIsSuccessful(); + self::assertSelectorExists('#env-switcher'); + } + + public function testSpecJsonReturnsJson(): void + { + $client = static::createClient(); + $client->request('GET', '/api/doc/spec.json'); + + self::assertResponseIsSuccessful(); + $data = json_decode($client->getResponse()->getContent(), true); + self::assertIsArray($data); + self::assertCount(5, $data); + self::assertSame('Authentification', $data[0]['name']); + } + + public function testInsomniaExportDownloads(): void + { + $client = static::createClient(); + $client->request('GET', '/api/doc/insomnia.json'); + + self::assertResponseIsSuccessful(); + self::assertStringContainsString('attachment', $client->getResponse()->headers->get('Content-Disposition')); + + $data = json_decode($client->getResponse()->getContent(), true); + self::assertSame('export', $data['_type']); + self::assertSame(4, $data['__export_format']); + self::assertNotEmpty($data['resources']); + } + + public function testInsomniaContainsWorkspaceAndEnv(): void + { + $client = static::createClient(); + $client->request('GET', '/api/doc/insomnia.json'); + + $data = json_decode($client->getResponse()->getContent(), true); + $types = array_column($data['resources'], '_type'); + + self::assertContains('workspace', $types); + self::assertContains('environment', $types); + self::assertContains('request_group', $types); + self::assertContains('request', $types); + } + + public function testInsomniaLoginHasAfterResponseScript(): void + { + $client = static::createClient(); + $client->request('GET', '/api/doc/insomnia.json'); + + $data = json_decode($client->getResponse()->getContent(), true); + $requests = array_filter($data['resources'], fn ($r) => 'request' === ($r['_type'] ?? '')); + + $loginReq = null; + foreach ($requests as $req) { + if (str_contains($req['url'] ?? '', '/api/auth/login') && !str_contains($req['url'] ?? '', 'sso')) { + $loginReq = $req; + break; + } + } + + self::assertNotNull($loginReq); + self::assertArrayHasKey('afterResponseScript', $loginReq); + self::assertStringContainsString('jwt_token', $loginReq['afterResponseScript']); + } +}