183 lines
6.7 KiB
PHP
183 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Tests\Integration;
|
|
|
|
use App\Shared\Clock\FixedTimeProvider;
|
|
use App\Tests\Support\TestAppFactory;
|
|
use App\Tests\Support\TestDatabase;
|
|
use PHPUnit\Framework\TestCase;
|
|
use Slim\Psr7\Factory\ServerRequestFactory;
|
|
|
|
final class AuthFlowTest extends TestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
if (session_status() === PHP_SESSION_ACTIVE) {
|
|
$_SESSION = [];
|
|
session_destroy();
|
|
}
|
|
}
|
|
|
|
public function testRegistrationFlowCreatesUserAndLogsIn(): void
|
|
{
|
|
$pdo = TestDatabase::create();
|
|
TestDatabase::reset($pdo);
|
|
TestDatabase::seedMinimal($pdo);
|
|
|
|
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
|
|
$app = TestAppFactory::create($pdo, $time);
|
|
$factory = new ServerRequestFactory();
|
|
|
|
$cookie = null;
|
|
|
|
$step1 = $this->jsonRequest($factory, 'POST', '/auth/register/step1', [
|
|
'race_key' => 'human',
|
|
], $cookie);
|
|
$response1 = $app->handle($step1);
|
|
self::assertSame(200, $response1->getStatusCode());
|
|
$cookie = $this->extractCookie($response1, $cookie);
|
|
$body1 = json_decode((string)$response1->getBody(), true);
|
|
self::assertSame('human', $body1['draft']['race_key']);
|
|
|
|
$step2 = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
|
|
'avatar_key' => 'avatar-01',
|
|
'title' => 'Pionier',
|
|
], $cookie);
|
|
$response2 = $app->handle($step2);
|
|
self::assertSame(200, $response2->getStatusCode());
|
|
$cookie = $this->extractCookie($response2, $cookie);
|
|
$body2 = json_decode((string)$response2->getBody(), true);
|
|
self::assertSame('avatar-01', $body2['draft']['avatar_key']);
|
|
|
|
$step3 = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
|
|
'username' => 'neo',
|
|
'email' => 'neo@example.test',
|
|
'password' => 'change-me',
|
|
], $cookie);
|
|
$response3 = $app->handle($step3);
|
|
self::assertSame(201, $response3->getStatusCode());
|
|
$cookie = $this->extractCookie($response3, $cookie);
|
|
|
|
$meRequest = $factory->createServerRequest('GET', '/me');
|
|
if ($cookie) {
|
|
$meRequest = $meRequest->withHeader('Cookie', $cookie);
|
|
}
|
|
$meResponse = $app->handle($meRequest);
|
|
self::assertSame(200, $meResponse->getStatusCode());
|
|
$meBody = json_decode((string)$meResponse->getBody(), true);
|
|
self::assertSame('neo', $meBody['user']['username']);
|
|
self::assertSame('human', $meBody['user']['race_key']);
|
|
|
|
$draftCheck = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
|
|
'avatar_key' => 'avatar-01',
|
|
'title' => 'Test',
|
|
], $cookie);
|
|
$draftResponse = $app->handle($draftCheck);
|
|
self::assertSame(409, $draftResponse->getStatusCode());
|
|
}
|
|
|
|
public function testLoginSuccessAndFailure(): void
|
|
{
|
|
$pdo = TestDatabase::create();
|
|
TestDatabase::reset($pdo);
|
|
TestDatabase::seedMinimal($pdo);
|
|
|
|
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
|
|
$app = TestAppFactory::create($pdo, $time);
|
|
$factory = new ServerRequestFactory();
|
|
|
|
$badLogin = $this->jsonRequest($factory, 'POST', '/auth/login', [
|
|
'username_or_email' => 'tester',
|
|
'password' => 'wrong-pass',
|
|
]);
|
|
$badResponse = $app->handle($badLogin);
|
|
self::assertSame(401, $badResponse->getStatusCode());
|
|
|
|
$goodLogin = $this->jsonRequest($factory, 'POST', '/auth/login', [
|
|
'username_or_email' => 'tester',
|
|
'password' => 'change-me',
|
|
]);
|
|
$goodResponse = $app->handle($goodLogin);
|
|
self::assertSame(200, $goodResponse->getStatusCode());
|
|
$cookie = $this->extractCookie($goodResponse, null);
|
|
|
|
$meRequest = $factory->createServerRequest('GET', '/me');
|
|
if ($cookie) {
|
|
$meRequest = $meRequest->withHeader('Cookie', $cookie);
|
|
}
|
|
$meResponse = $app->handle($meRequest);
|
|
self::assertSame(200, $meResponse->getStatusCode());
|
|
}
|
|
|
|
public function testRegistrationRejectsDuplicates(): void
|
|
{
|
|
$pdo = TestDatabase::create();
|
|
TestDatabase::reset($pdo);
|
|
TestDatabase::seedMinimal($pdo);
|
|
|
|
$time = new FixedTimeProvider(new \DateTimeImmutable('2026-02-03 00:00:00'));
|
|
$app = TestAppFactory::create($pdo, $time);
|
|
$factory = new ServerRequestFactory();
|
|
|
|
$cookie = null;
|
|
|
|
$step1 = $this->jsonRequest($factory, 'POST', '/auth/register/step1', [
|
|
'race_key' => 'human',
|
|
], $cookie);
|
|
$response1 = $app->handle($step1);
|
|
$cookie = $this->extractCookie($response1, $cookie);
|
|
|
|
$step2 = $this->jsonRequest($factory, 'POST', '/auth/register/step2', [
|
|
'avatar_key' => 'avatar-01',
|
|
'title' => 'Pilot',
|
|
], $cookie);
|
|
$response2 = $app->handle($step2);
|
|
$cookie = $this->extractCookie($response2, $cookie);
|
|
|
|
$dupUsername = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
|
|
'username' => 'tester',
|
|
'email' => 'unique@example.test',
|
|
'password' => 'change-me',
|
|
], $cookie);
|
|
$dupResponse = $app->handle($dupUsername);
|
|
self::assertSame(409, $dupResponse->getStatusCode());
|
|
|
|
$dupEmail = $this->jsonRequest($factory, 'POST', '/auth/register/step3', [
|
|
'username' => 'unique-user',
|
|
'email' => 'tester@example.test',
|
|
'password' => 'change-me',
|
|
], $cookie);
|
|
$dupEmailResponse = $app->handle($dupEmail);
|
|
self::assertSame(409, $dupEmailResponse->getStatusCode());
|
|
}
|
|
|
|
/**
|
|
* @param array<string,mixed> $payload
|
|
*/
|
|
private function jsonRequest(ServerRequestFactory $factory, string $method, string $path, array $payload = [], ?string $cookie = null): \Psr\Http\Message\ServerRequestInterface
|
|
{
|
|
$request = $factory->createServerRequest($method, $path)
|
|
->withHeader('Content-Type', 'application/json');
|
|
if ($cookie) {
|
|
$request = $request->withHeader('Cookie', $cookie);
|
|
}
|
|
if ($payload !== []) {
|
|
$request->getBody()->write(json_encode($payload));
|
|
$request->getBody()->rewind();
|
|
}
|
|
return $request;
|
|
}
|
|
|
|
private function extractCookie(\Psr\Http\Message\ResponseInterface $response, ?string $fallback): ?string
|
|
{
|
|
$setCookie = $response->getHeaderLine('Set-Cookie');
|
|
if ($setCookie === '') {
|
|
return $fallback;
|
|
}
|
|
$parts = explode(';', $setCookie);
|
|
return trim($parts[0]);
|
|
}
|
|
}
|