first commit

This commit is contained in:
julien
2026-03-16 01:47:07 +01:00
commit 8f7e61bda0
185 changed files with 27731 additions and 0 deletions

View File

@@ -0,0 +1,144 @@
<?php
declare(strict_types=1);
namespace Tests;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface as Response;
use Slim\Psr7\Factory\ServerRequestFactory;
use Slim\Psr7\Response as SlimResponse;
/**
* Classe de base pour les tests de contrôleurs.
*
* Fournit des helpers pour construire des requêtes PSR-7 sans serveur,
* des assertions sur les redirections et les réponses JSON,
* ainsi qu'un stub de Twig qui retourne la réponse inchangée.
*
* Chaque test de contrôleur invoque directement l'action (méthode publique)
* sans passer par le routeur Slim — les middlewares sont testés séparément.
*/
abstract class ControllerTestCase extends TestCase
{
// ── Factories ────────────────────────────────────────────────────
/**
* Crée une requête GET avec des paramètres de query optionnels.
*
* @param string $uri URI de la requête (ex: '/admin/posts')
* @param array<string, mixed> $queryParams Paramètres de query string
* @param array<string, mixed> $serverParams Paramètres serveur (ex: REMOTE_ADDR)
*/
protected function makeGet(
string $uri = '/',
array $queryParams = [],
array $serverParams = [],
): \Psr\Http\Message\ServerRequestInterface {
$factory = new ServerRequestFactory();
$request = $factory->createServerRequest('GET', $uri, $serverParams);
if ($queryParams !== []) {
$request = $request->withQueryParams($queryParams);
}
return $request;
}
/**
* Crée une requête POST avec un corps parsé optionnel.
*
* @param string $uri URI de la requête (ex: '/auth/login')
* @param array<string, mixed> $body Corps de la requête (form data)
* @param array<string, mixed> $serverParams Paramètres serveur (ex: REMOTE_ADDR)
*/
protected function makePost(
string $uri = '/',
array $body = [],
array $serverParams = [],
): \Psr\Http\Message\ServerRequestInterface {
$factory = new ServerRequestFactory();
$request = $factory->createServerRequest('POST', $uri, $serverParams);
if ($body !== []) {
$request = $request->withParsedBody($body);
}
return $request;
}
/**
* Crée une réponse PSR-7 vide (status 200).
*/
protected function makeResponse(): SlimResponse
{
return new SlimResponse();
}
/**
* Crée un mock de Twig dont render() retourne la réponse reçue en premier argument.
*
* Cela permet aux tests de contrôleurs qui appellent $this->view->render()
* de recevoir une réponse 200 sans instancier un environnement Twig réel.
*
* @return \Slim\Views\Twig&\PHPUnit\Framework\MockObject\MockObject
*/
protected function makeTwigMock(): \Slim\Views\Twig
{
$twig = $this->createMock(\Slim\Views\Twig::class);
$twig->method('render')->willReturnArgument(0);
return $twig;
}
// ── Assertions ───────────────────────────────────────────────────
/**
* Vérifie qu'une réponse est une redirection vers l'URL attendue.
*/
protected function assertRedirectTo(Response $res, string $expectedLocation): void
{
$this->assertSame(302, $res->getStatusCode(), 'Le code HTTP devrait être 302');
$this->assertSame(
$expectedLocation,
$res->getHeaderLine('Location'),
"La redirection devrait pointer vers {$expectedLocation}",
);
}
/**
* Vérifie le code HTTP d'une réponse.
*/
protected function assertStatus(Response $res, int $expectedStatus): void
{
$this->assertSame($expectedStatus, $res->getStatusCode());
}
/**
* Vérifie que le corps de la réponse est du JSON contenant les clés attendues.
*
* @param array<string, mixed> $expectedSubset Sous-ensemble de clés/valeurs attendues
*/
protected function assertJsonContains(Response $res, array $expectedSubset): void
{
$body = (string) $res->getBody();
$decoded = json_decode($body, true);
$this->assertIsArray($decoded, 'Le corps de la réponse devrait être du JSON valide');
foreach ($expectedSubset as $key => $value) {
$this->assertArrayHasKey($key, $decoded, "La clé JSON '{$key}' devrait être présente");
$this->assertSame($value, $decoded[$key], "La valeur JSON de '{$key}' est incorrecte");
}
}
/**
* Vérifie que le Content-Type de la réponse est application/json.
*/
protected function assertJsonContentType(Response $res): void
{
$this->assertStringContainsString(
'application/json',
$res->getHeaderLine('Content-Type'),
);
}
}