uploads
This commit is contained in:
182
server/tests/Integration/AuthFlowTest.php
Normal file
182
server/tests/Integration/AuthFlowTest.php
Normal file
@@ -0,0 +1,182 @@
|
||||
<?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]);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,18 @@ final class TestDatabase
|
||||
$pdo->exec("INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT r.id, p.id FROM roles r JOIN permissions p ON r.key = 'player' AND p.key = 'planet.public.view'");
|
||||
|
||||
$pdo->exec("INSERT INTO users (username, race_key) VALUES ('tester', 'human')");
|
||||
$stmt = $pdo->prepare(
|
||||
"INSERT INTO users (username, email, password_hash, race_key, title, avatar_key)
|
||||
VALUES (:username, :email, :password_hash, :race_key, :title, :avatar_key)"
|
||||
);
|
||||
$stmt->execute([
|
||||
'username' => 'tester',
|
||||
'email' => 'tester@example.test',
|
||||
'password_hash' => password_hash('change-me', PASSWORD_DEFAULT),
|
||||
'race_key' => 'human',
|
||||
'title' => 'Tester',
|
||||
'avatar_key' => 'avatar-01',
|
||||
]);
|
||||
$userId = (int)$pdo->query("SELECT id FROM users WHERE username = 'tester'")->fetchColumn();
|
||||
|
||||
$pdo->exec("INSERT INTO user_roles (user_id, role_id)
|
||||
|
||||
Reference in New Issue
Block a user