test(api) : tests fonctionnels pagination Category (5 cas) + non-regression AuditLog (2 cas)
This commit is contained in:
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Tests\Module\Catalog\Api;
|
||||
|
||||
use DateTimeImmutable;
|
||||
|
||||
/**
|
||||
* Tests du contrat de pagination sur GET /api/categories (ERP-72).
|
||||
*
|
||||
* Invariants testes :
|
||||
* - la collection expose les metadonnees Hydra (totalItems, view, member) ;
|
||||
* - itemsPerPage est plafonne au maximum global (50) ;
|
||||
* - une page hors limites retourne une collection vide, pas une 500 ;
|
||||
* - ?pagination=false retourne tous les items sans troncature (select-box) ;
|
||||
* - la pagination est compatible avec le flag ?includeDeleted=true.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class CategoryPaginationTest extends AbstractCatalogApiTestCase
|
||||
{
|
||||
/**
|
||||
* La collection expose les metadonnees de pagination JSON-LD sans prefixe :
|
||||
* `totalItems`, `view`, `member` (convention API Platform 4, pas hydra:*).
|
||||
*
|
||||
* On cree 12 categories pour depasser la limite par page (10) : la cle
|
||||
* `view` n'est presente que lorsqu'il y a plus d'items que la taille de page.
|
||||
*/
|
||||
public function testCollectionExposesHydraPaginationMetadata(): void
|
||||
{
|
||||
$type = $this->createCategoryType();
|
||||
for ($i = 1; $i <= 12; ++$i) {
|
||||
$this->createCategory(self::TEST_CATEGORY_PREFIX.'meta_'.$i, $type);
|
||||
}
|
||||
|
||||
$client = $this->createAdminClient();
|
||||
$response = $client->request('GET', '/api/categories');
|
||||
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
|
||||
$data = $response->toArray();
|
||||
self::assertArrayHasKey('totalItems', $data, 'La collection doit exposer totalItems.');
|
||||
self::assertArrayHasKey('view', $data, 'La collection doit exposer view (pagination) quand totalItems > itemsPerPage.');
|
||||
self::assertIsArray($data['member'], 'member doit etre un tableau.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Un itemsPerPage arbitrairement grand (99999) doit etre plafonne au
|
||||
* maximum global configure (50). On cree 12 categories pour etre certain
|
||||
* de disposer de donnees ; le cap doit s'appliquer quelle que soit la taille
|
||||
* reelle de la collection.
|
||||
*/
|
||||
public function testItemsPerPageIsCappedAtMaximum(): void
|
||||
{
|
||||
$type = $this->createCategoryType();
|
||||
for ($i = 1; $i <= 12; ++$i) {
|
||||
$this->createCategory(self::TEST_CATEGORY_PREFIX.'cap_'.$i, $type);
|
||||
}
|
||||
|
||||
$client = $this->createAdminClient();
|
||||
$response = $client->request('GET', '/api/categories?itemsPerPage=99999');
|
||||
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
// Le cap global est 50 : jamais plus d'items par page que le maximum.
|
||||
self::assertLessThanOrEqual(
|
||||
50,
|
||||
count($response->toArray()['member']),
|
||||
'itemsPerPage doit etre plafonne au maximum global (50).',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Une page tres elevee (99999) sur une petite collection ne doit pas
|
||||
* produire une 500 PG (OFFSET negatif ou depassement de capacite) mais
|
||||
* retourner 200 avec un tableau member vide.
|
||||
*/
|
||||
public function testOutOfBoundPageReturnsEmptyCollectionNot500(): void
|
||||
{
|
||||
$type = $this->createCategoryType();
|
||||
$this->createCategory(self::TEST_CATEGORY_PREFIX.'oob', $type);
|
||||
|
||||
$client = $this->createAdminClient();
|
||||
$response = $client->request('GET', '/api/categories?page=99999');
|
||||
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
// La page 99999 est forcement vide (on a bien moins que 99999*10 items).
|
||||
self::assertSame(
|
||||
[],
|
||||
$response->toArray()['member'],
|
||||
'Une page hors limites doit retourner un member vide, jamais une 500.',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* ?pagination=false permet au frontend de desactiver la pagination pour
|
||||
* alimenter un select-box. On cree exactement 12 categories dont les noms
|
||||
* commencent par `test_cat_select_` : le filtre sur ce prefixe isole nos
|
||||
* entrees des donnees concurrentes et prouve que les 12 items sont tous
|
||||
* retournes (et pas seulement les 10 premiers de la page 1).
|
||||
*/
|
||||
public function testClientCanDisablePaginationToFeedASelect(): void
|
||||
{
|
||||
$type = $this->createCategoryType();
|
||||
for ($i = 1; $i <= 12; ++$i) {
|
||||
$this->createCategory(self::TEST_CATEGORY_PREFIX.'select_'.$i, $type);
|
||||
}
|
||||
|
||||
$client = $this->createAdminClient();
|
||||
$response = $client->request('GET', '/api/categories?pagination=false');
|
||||
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
|
||||
$members = $response->toArray()['member'];
|
||||
|
||||
// Filtre sur le sous-prefixe pour ne pas comptabiliser les categories
|
||||
// d'autres tests qui partagent la meme base de donnees.
|
||||
$selectItems = array_values(array_filter(
|
||||
$members,
|
||||
fn (array $m): bool => str_starts_with($m['name'], self::TEST_CATEGORY_PREFIX.'select_'),
|
||||
));
|
||||
|
||||
self::assertCount(
|
||||
12,
|
||||
$selectItems,
|
||||
'?pagination=false doit retourner toutes les categories (pas seulement la page 1).',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* La pagination doit fonctionner conjointement avec le flag ?includeDeleted=true.
|
||||
* On seed 3 categories actives + 2 soft-deleted, on demande itemsPerPage=5 :
|
||||
* la page 1 doit contenir exactement 5 items et totalItems doit valoir >= 5.
|
||||
*/
|
||||
public function testPaginationCombinedWithIncludeDeletedFlag(): void
|
||||
{
|
||||
$type = $this->createCategoryType();
|
||||
|
||||
// 3 categories actives.
|
||||
for ($i = 1; $i <= 3; ++$i) {
|
||||
$this->createCategory(self::TEST_CATEGORY_PREFIX.'pag_active_'.$i, $type);
|
||||
}
|
||||
|
||||
// 2 categories soft-deleted.
|
||||
for ($i = 1; $i <= 2; ++$i) {
|
||||
$this->createCategory(
|
||||
self::TEST_CATEGORY_PREFIX.'pag_deleted_'.$i,
|
||||
$type,
|
||||
new DateTimeImmutable(),
|
||||
);
|
||||
}
|
||||
|
||||
$client = $this->createAdminClient();
|
||||
$response = $client->request('GET', '/api/categories?includeDeleted=true&itemsPerPage=5');
|
||||
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
|
||||
$data = $response->toArray();
|
||||
// La page retournee ne doit pas exceder itemsPerPage=5.
|
||||
self::assertCount(
|
||||
5,
|
||||
$data['member'],
|
||||
'La page 1 doit contenir exactement 5 items (itemsPerPage=5 avec >= 5 categories disponibles).',
|
||||
);
|
||||
self::assertGreaterThanOrEqual(
|
||||
5,
|
||||
$data['totalItems'],
|
||||
'totalItems doit refleter au moins les 5 categories seedees (actives + soft-deleted).',
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user