test: functional test infrastructure (ApiTestCase + db_test + JWT helpers)
- .env.test points at db_test (doctrine when@test appends _test suffix) - ApiTestCase: WebTestCase base with createUser/jwtFor/authJson helpers - InfraSmokeTest: proves boot + DB + JWT auth pipeline works (/health 200, unauth /oauth/userinfo 401, JWT-auth userinfo 200) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
# define your env variables for the test env here
|
||||
KERNEL_CLASS='App\Kernel'
|
||||
APP_SECRET='$ecretf0rt3st'
|
||||
|
||||
# Test DB: doctrine's when@test config appends the `_test` suffix (see
|
||||
# config/packages/doctrine.yaml), so this base name `db` becomes `db_test`.
|
||||
# That database is created in ddev and granted to user `db`.
|
||||
DATABASE_URL="mysql://db:db@db:3306/db?serverVersion=8.0&charset=utf8mb4"
|
||||
|
||||
# JWT — generated keypair is shared with dev; passphrase from .env is fine.
|
||||
# Redis cache/messenger use the same ddev redis; tests don't depend on it.
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests;
|
||||
|
||||
use App\Auth\Entity\User;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
|
||||
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
|
||||
|
||||
/**
|
||||
* Base class for functional API tests.
|
||||
*
|
||||
* Provides a booted KernelBrowser, the EntityManager, and helpers to create
|
||||
* users and issue JWTs so tests can hit authenticated /api and /oauth endpoints.
|
||||
* Runs against the dedicated db_test database (see .env.test / doctrine when@test).
|
||||
*/
|
||||
abstract class ApiTestCase extends WebTestCase
|
||||
{
|
||||
protected KernelBrowser $client;
|
||||
protected EntityManagerInterface $em;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->client = static::createClient();
|
||||
$this->em = static::getContainer()->get(EntityManagerInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persist a user with the given roles. Mobile is randomised per test to
|
||||
* avoid unique-constraint clashes across cases without a full DB reset.
|
||||
*/
|
||||
protected function createUser(array $roles = ['ROLE_USER'], ?string $mobile = null): User
|
||||
{
|
||||
$mobile ??= '0912' . str_pad((string) random_int(0, 9_999_999), 7, '0', STR_PAD_LEFT);
|
||||
$user = new User($mobile);
|
||||
$user->setRoles($roles);
|
||||
$user->setStatus(1);
|
||||
$this->em->persist($user);
|
||||
$this->em->flush();
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
protected function jwtFor(User $user): string
|
||||
{
|
||||
return static::getContainer()
|
||||
->get(JWTTokenManagerInterface::class)
|
||||
->create($user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue an authenticated JSON request and return the decoded response body.
|
||||
*/
|
||||
protected function authJson(string $method, string $uri, User $user, array $body = []): array
|
||||
{
|
||||
$this->client->request(
|
||||
$method,
|
||||
$uri,
|
||||
server: [
|
||||
'HTTP_AUTHORIZATION' => 'Bearer ' . $this->jwtFor($user),
|
||||
'CONTENT_TYPE' => 'application/json',
|
||||
],
|
||||
content: $body ? json_encode($body) : null,
|
||||
);
|
||||
|
||||
return json_decode($this->client->getResponse()->getContent(), true) ?? [];
|
||||
}
|
||||
|
||||
protected function responseCode(): int
|
||||
{
|
||||
return $this->client->getResponse()->getStatusCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Smoke;
|
||||
|
||||
use App\Tests\ApiTestCase;
|
||||
|
||||
/**
|
||||
* Confirms the test infrastructure itself works: app boots, /health serves,
|
||||
* and JWT-authenticated requests reach protected endpoints.
|
||||
*/
|
||||
class InfraSmokeTest extends ApiTestCase
|
||||
{
|
||||
public function testHealthIsPublicAnd200(): void
|
||||
{
|
||||
$this->client->request('GET', '/health');
|
||||
$this->assertSame(200, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testUnauthenticatedApiIs401(): void
|
||||
{
|
||||
$this->client->request('GET', '/oauth/userinfo');
|
||||
$this->assertSame(401, $this->responseCode());
|
||||
}
|
||||
|
||||
public function testJwtAuthReachesUserInfo(): void
|
||||
{
|
||||
$user = $this->createUser(['ROLE_USER']);
|
||||
$body = $this->authJson('GET', '/oauth/userinfo', $user);
|
||||
|
||||
$this->assertSame(200, $this->responseCode());
|
||||
$this->assertTrue($body['success']);
|
||||
$this->assertSame($user->getUuid(), $body['data']['uuid']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user