feat: migrer vers Symfony 8, PHP 8.4 et les dépendances majeures associées

- PHP 8.3 → 8.4 (Dockerfile + composer.json)
- Symfony 7.0 → 8.0 (tous les composants symfony/*)
- API Platform 3.x → 4.x : migration openapiContext → openapi: new Operation(...)
- Doctrine DBAL 3 → 4 : suppression use_savepoints, replace prepare/executeQuery
- Doctrine ORM 2.x → 3.x : ClassMetadataInfo → ClassMetadata, setParameters → setParameter
- Doctrine Bundle 2.x → 3.x, Fixtures Bundle 3.x → 4.x
- zenstruck/foundry 1.x → 2.x : ModelFactory → PersistentObjectFactory, getDefaults → defaults
- phpmd/phpmd 2.x → 3.x-dev (seule version supportant Symfony 8)
- phparkitect 0.3 → 0.8 : NotDependsOnTheseNamespaces prend un array
- symfony/mercure-bundle 0.3 → 0.4, symfony/monolog-bundle 3 → 4
- Suppression de runtime/frankenphp-symfony (intégré nativement dans symfony/runtime 8)
- worker.Caddyfile : suppression de APP_RUNTIME (détection automatique Symfony 8)
- Routes errors.xml/wdt.xml/profiler.xml → .php (Symfony 8 supprime le XML)
- Types::ARRAY → Types::JSON dans Entity/Manga.php (DBAL 4 retire array type)
- Suppression de src/Schedule.php (doublon vide avec MonitoringSchedule)
- Tests : hydra:Collection → Collection, hydra:member → member (API Platform 4)
This commit is contained in:
ext.jeremy.guillot@maxicoffee.domains
2026-03-26 17:55:12 +01:00
parent 5a0888eb28
commit 5ed303612a
371 changed files with 6194 additions and 4160 deletions

View File

@@ -32,7 +32,7 @@ class ConvertFileTest extends AbstractApiTestCase
'files' => [
'file' => $uploadedFile,
],
]
],
]);
// Then - Vérifier la réponse
@@ -84,7 +84,7 @@ class ConvertFileTest extends AbstractApiTestCase
'files' => [
'file' => $uploadedFile,
],
]
],
]);
// Then - Vérifier l'erreur de validation
@@ -121,7 +121,7 @@ class ConvertFileTest extends AbstractApiTestCase
'files' => [
'file' => $uploadedFile,
],
]
],
]);
// Then - Vérifier l'erreur de validation
@@ -140,18 +140,18 @@ class ConvertFileTest extends AbstractApiTestCase
// Pour les tests, on peut simplement créer un fichier avec une extension .cbr
// En production, ce serait un vrai fichier RAR
$newPath = $tempFile . '.cbr';
$newPath = $tempFile.'.cbr';
rename($tempFile, $newPath);
// Utiliser un fichier CBZ existant comme base et le renommer en CBR pour les tests
$existingCbzFile = __DIR__ . '/../../Fixtures/chapter.cbz';
$existingCbzFile = __DIR__.'/../../Fixtures/chapter.cbz';
if (file_exists($existingCbzFile)) {
copy($existingCbzFile, $newPath);
} else {
// Fallback: créer un fichier ZIP simple avec extension CBR
// Un fichier CBR est essentiellement un fichier RAR, mais pour les tests on peut simuler avec un ZIP
$zip = new \ZipArchive();
if ($zip->open($newPath, \ZipArchive::CREATE) === TRUE) {
if (true === $zip->open($newPath, \ZipArchive::CREATE)) {
$zip->addFromString('test.txt', 'Test content for CBR simulation');
$zip->close();
}

View File

@@ -2,7 +2,6 @@
namespace App\Tests\Feature\Manga;
use App\Domain\Manga\Domain\Contract\Service\ImageProcessorInterface;
use App\Tests\Feature\AbstractApiTestCase;
use Zenstruck\Foundry\Test\ResetDatabase;
@@ -25,17 +24,17 @@ class CreateMangaDirectlyTest extends AbstractApiTestCase
'status' => 'ongoing',
'externalId' => 'external-123',
'imageUrl' => 'http://example.com/image.jpg',
'rating' => 4.5
]
'rating' => 4.5,
],
]);
// Then
$this->assertResponseIsSuccessful();
// Verify the manga was created in database
$entityManager = static::getContainer()->get('doctrine')->getManager();
$manga = $entityManager->getRepository(\App\Entity\Manga::class)->findOneBy(['slug' => 'one-piece']);
$this->assertNotNull($manga);
$this->assertEquals('One Piece', $manga->getTitle());
$this->assertEquals('Test description', $manga->getDescription());
@@ -64,16 +63,16 @@ class CreateMangaDirectlyTest extends AbstractApiTestCase
'status' => 'ongoing',
'externalId' => 'external-123',
'imageUrl' => null,
'rating' => 4.5
]
'rating' => 4.5,
],
]);
// Then
$this->assertResponseIsSuccessful();
$entityManager = static::getContainer()->get('doctrine')->getManager();
$manga = $entityManager->getRepository(\App\Entity\Manga::class)->findOneBy(['slug' => 'one-piece']);
$this->assertNotNull($manga);
$this->assertNull($manga->getImageUrl());
$this->assertNull($manga->getThumbnailUrl());
@@ -87,14 +86,14 @@ class CreateMangaDirectlyTest extends AbstractApiTestCase
'json' => [
'title' => '', // Invalid: empty title
'publicationYear' => 'invalid', // Invalid: not a number
]
],
]);
// Then
$this->assertResponseStatusCodeSame(400);
$this->assertJsonContains([
'hydra:title' => 'An error occurred',
'hydra:description' => 'The type of the "publicationYear" attribute must be "int", "string" given.'
'title' => 'An error occurred',
'detail' => 'The type of the "publicationYear" attribute must be "int", "string" given.',
]);
}
@@ -113,16 +112,16 @@ class CreateMangaDirectlyTest extends AbstractApiTestCase
'status' => 'ongoing',
'externalId' => 'external-123',
'imageUrl' => null,
'rating' => 4.5
]
'rating' => 4.5,
],
]);
// Then
$this->assertResponseStatusCodeSame(422);
$this->assertJsonContains([
'hydra:title' => 'An error occurred',
'hydra:description' => 'publicationYear: L\'année de publication doit être comprise entre 1900 et 2100',
'title' => 'An error occurred'
'title' => 'An error occurred',
'detail' => 'publicationYear: L\'année de publication doit être comprise entre 1900 et 2100',
'title' => 'An error occurred',
]);
}
}
}

View File

@@ -6,20 +6,20 @@ use App\Entity\Chapter;
use App\Tests\Factory\ChapterFactory;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;
class DeleteCbzTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function test_it_deletes_chapter_cbz_file(): void
public function testItDeletesChapterCbzFile(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
$chapter = ChapterFactory::createOne([
@@ -27,7 +27,7 @@ class DeleteCbzTest extends AbstractApiTestCase
'number' => 1.0,
'title' => 'Chapter 1',
'visible' => true,
'cbzPath' => '/path/to/test.cbz'
'cbzPath' => '/path/to/test.cbz',
]);
$this->entityManager->flush();
@@ -45,7 +45,7 @@ class DeleteCbzTest extends AbstractApiTestCase
$this->assertEmpty($freshChapter->getCbzPath());
}
public function test_it_returns_404_for_non_existent_chapter(): void
public function testItReturns404ForNonExistentChapter(): void
{
// When
static::createClient()->request('DELETE', '/api/manga/chapters/999999/cbz');
@@ -54,12 +54,12 @@ class DeleteCbzTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(404);
}
public function test_it_returns_404_for_chapter_without_cbz(): void
public function testItReturns404ForChapterWithoutCbz(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'Test Manga',
'slug' => 'test-manga'
'slug' => 'test-manga',
]);
$chapter = ChapterFactory::createOne([
@@ -67,7 +67,7 @@ class DeleteCbzTest extends AbstractApiTestCase
'number' => 1.0,
'title' => 'Test Chapter',
'visible' => true,
'cbzPath' => null // No CBZ file
'cbzPath' => null, // No CBZ file
]);
$this->entityManager->flush();
@@ -80,12 +80,12 @@ class DeleteCbzTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(404);
}
public function test_it_returns_404_for_invisible_chapter(): void
public function testItReturns404ForInvisibleChapter(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'Test Manga',
'slug' => 'test-manga'
'slug' => 'test-manga',
]);
$chapter = ChapterFactory::createOne([
@@ -93,7 +93,7 @@ class DeleteCbzTest extends AbstractApiTestCase
'number' => 1.0,
'title' => 'Test Chapter',
'visible' => false, // Invisible chapter
'cbzPath' => '/path/to/test.cbz'
'cbzPath' => '/path/to/test.cbz',
]);
$this->entityManager->flush();

View File

@@ -6,27 +6,27 @@ use App\Entity\Chapter;
use App\Tests\Factory\ChapterFactory;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;
class DeleteChapterTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function test_it_soft_deletes_chapter(): void
public function testItSoftDeletesChapter(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
$chapter = ChapterFactory::createOne([
'manga' => $manga,
'number' => 1.0,
'title' => 'Chapter 1',
'visible' => true
'visible' => true,
]);
$chapterId = $chapter->getId();
@@ -42,7 +42,7 @@ class DeleteChapterTest extends AbstractApiTestCase
$this->assertFalse($freshChapter->isVisible());
}
public function test_it_returns_404_for_non_existent_chapter(): void
public function testItReturns404ForNonExistentChapter(): void
{
// When
static::createClient()->request('DELETE', '/api/manga/chapters/999999');
@@ -51,19 +51,19 @@ class DeleteChapterTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(404);
}
public function test_it_returns_404_for_already_soft_deleted_chapter(): void
public function testItReturns404ForAlreadySoftDeletedChapter(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'Test Manga',
'slug' => 'test-manga'
'slug' => 'test-manga',
]);
$chapter = ChapterFactory::createOne([
'manga' => $manga,
'number' => 1.0,
'title' => 'Test Chapter',
'visible' => false // Already soft deleted
'visible' => false, // Already soft deleted
]);
$this->entityManager->flush();

View File

@@ -2,25 +2,25 @@
namespace App\Tests\Feature\Manga;
use App\Entity\Manga;
use App\Entity\Chapter;
use App\Tests\Factory\MangaFactory;
use App\Entity\Manga;
use App\Tests\Factory\ChapterFactory;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\Foundry\Test\Factories;
use Zenstruck\Foundry\Test\ResetDatabase;
class DeleteMangaTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function test_it_deletes_manga_with_chapters(): void
public function testItDeletesMangaWithChapters(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
// Create chapters for the manga
@@ -28,21 +28,21 @@ class DeleteMangaTest extends AbstractApiTestCase
'manga' => $manga,
'number' => 1.0,
'title' => 'Chapter 1',
'visible' => true
'visible' => true,
]);
ChapterFactory::createMany(2, [
'manga' => $manga,
'number' => 2.0,
'title' => 'Chapter 2',
'visible' => true
'visible' => true,
]);
ChapterFactory::createMany(1, [
'manga' => $manga,
'number' => 3.0,
'title' => 'Chapter 3',
'visible' => true
'visible' => true,
]);
$mangaId = $manga->getId();
@@ -66,7 +66,7 @@ class DeleteMangaTest extends AbstractApiTestCase
$this->assertCount(0, $chaptersAfter);
}
public function test_it_returns_404_for_non_existent_manga(): void
public function testItReturns404ForNonExistentManga(): void
{
// When
static::createClient()->request('DELETE', '/api/mangas/999999');
@@ -74,5 +74,4 @@ class DeleteMangaTest extends AbstractApiTestCase
// Then
$this->assertResponseStatusCodeSame(404);
}
}

View File

@@ -2,7 +2,6 @@
namespace App\Tests\Feature\Manga;
use App\Entity\Chapter;
use App\Tests\Factory\ChapterFactory;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
@@ -12,14 +11,15 @@ use Zenstruck\Foundry\Test\ResetDatabase;
class DownloadCbzTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function test_it_downloads_chapter_cbz(): void
public function testItDownloadsChapterCbz(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
$chapter = ChapterFactory::createOne([
@@ -27,7 +27,7 @@ class DownloadCbzTest extends AbstractApiTestCase
'number' => 1.0,
'title' => 'Chapter 1',
'visible' => true,
'cbzPath' => '/app/tests/Shared/Files/test-chapter.cbz'
'cbzPath' => '/app/tests/Shared/Files/test-chapter.cbz',
]);
$chapterId = $chapter->getId();
@@ -44,7 +44,7 @@ class DownloadCbzTest extends AbstractApiTestCase
$this->assertStringContainsString('test-chapter.cbz', $response->headers->get('Content-Disposition'));
}
public function test_it_returns_404_for_non_existent_chapter(): void
public function testItReturns404ForNonExistentChapter(): void
{
// When
static::createClient()->request('GET', '/api/manga/chapters/999999/download');
@@ -53,12 +53,12 @@ class DownloadCbzTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(404);
}
public function test_it_returns_404_for_chapter_without_cbz(): void
public function testItReturns404ForChapterWithoutCbz(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'Test Manga',
'slug' => 'test-manga'
'slug' => 'test-manga',
]);
$chapter = ChapterFactory::createOne([
@@ -66,7 +66,7 @@ class DownloadCbzTest extends AbstractApiTestCase
'number' => 1.0,
'title' => 'Test Chapter',
'visible' => true,
'cbzPath' => null // No CBZ file
'cbzPath' => null, // No CBZ file
]);
$this->entityManager->flush();

View File

@@ -2,7 +2,6 @@
namespace App\Tests\Feature\Manga;
use App\Entity\Chapter;
use App\Tests\Factory\ChapterFactory;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
@@ -12,14 +11,15 @@ use Zenstruck\Foundry\Test\ResetDatabase;
class DownloadVolumeTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function test_it_downloads_volume_cbz(): void
public function testItDownloadsVolumeCbz(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
// Create chapters for volume 1
@@ -27,7 +27,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'manga' => $manga,
'volume' => 1,
'visible' => true,
'cbzPath' => __DIR__ . '/../../Shared/Files/test-chapter.cbz'
'cbzPath' => __DIR__.'/../../Shared/Files/test-chapter.cbz',
]);
$mangaId = $manga->getId();
@@ -43,7 +43,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
$this->assertStringContainsString('one-piece_vol1.cbz', $contentDisposition);
}
public function test_it_returns_404_when_manga_not_found(): void
public function testItReturns404WhenMangaNotFound(): void
{
// Act
static::createClient()->request('GET', '/api/mangas/999999/volumes/1/download');
@@ -52,12 +52,12 @@ class DownloadVolumeTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
}
public function test_it_returns_404_when_volume_not_found(): void
public function testItReturns404WhenVolumeNotFound(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
$mangaId = $manga->getId();
@@ -69,12 +69,12 @@ class DownloadVolumeTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
}
public function test_it_returns_404_when_no_available_chapters_in_volume(): void
public function testItReturns404WhenNoAvailableChaptersInVolume(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
// Create chapters for volume 1 but all without CBZ files
@@ -82,7 +82,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'manga' => $manga,
'volume' => 1,
'visible' => true,
'cbzPath' => null // No CBZ files
'cbzPath' => null, // No CBZ files
]);
$mangaId = $manga->getId();
@@ -94,12 +94,12 @@ class DownloadVolumeTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
}
public function test_it_only_includes_visible_chapters_with_cbz(): void
public function testItOnlyIncludesVisibleChaptersWithCbz(): void
{
// Arrange
$manga = MangaFactory::createOne([
'title' => 'One Piece',
'slug' => 'one-piece'
'slug' => 'one-piece',
]);
// Create a mix of chapters
@@ -108,7 +108,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'volume' => 1,
'number' => 1.0,
'visible' => true,
'cbzPath' => __DIR__ . '/../../Shared/Files/test-chapter.cbz'
'cbzPath' => __DIR__.'/../../Shared/Files/test-chapter.cbz',
]);
ChapterFactory::createOne([
@@ -116,7 +116,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'volume' => 1,
'number' => 2.0,
'visible' => false, // Soft deleted
'cbzPath' => __DIR__ . '/../../Shared/Files/test-chapter.cbz'
'cbzPath' => __DIR__.'/../../Shared/Files/test-chapter.cbz',
]);
ChapterFactory::createOne([
@@ -124,7 +124,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'volume' => 1,
'number' => 3.0,
'visible' => true,
'cbzPath' => null // No CBZ
'cbzPath' => null, // No CBZ
]);
ChapterFactory::createOne([
@@ -132,7 +132,7 @@ class DownloadVolumeTest extends AbstractApiTestCase
'volume' => 1,
'number' => 4.0,
'visible' => true,
'cbzPath' => __DIR__ . '/../../Shared/Files/test-chapter.cbz'
'cbzPath' => __DIR__.'/../../Shared/Files/test-chapter.cbz',
]);
$mangaId = $manga->getId();

View File

@@ -24,8 +24,8 @@ class EditMangaTest extends AbstractApiTestCase
'status' => 'ongoing',
'externalId' => 'external-123',
'imageUrl' => 'http://example.com/image.jpg',
'rating' => 4.5
]
'rating' => 4.5,
],
]);
$this->assertResponseIsSuccessful();
@@ -37,7 +37,7 @@ class EditMangaTest extends AbstractApiTestCase
$mangaId = $createdManga->getId();
// When - Edit the manga
$response = $client->request('PUT', '/api/mangas/' . $mangaId . '/edit', [
$response = $client->request('PUT', '/api/mangas/'.$mangaId.'/edit', [
'json' => [
'title' => 'One Piece Updated',
'description' => 'Updated description',
@@ -46,8 +46,8 @@ class EditMangaTest extends AbstractApiTestCase
'genres' => ['action', 'adventure', 'comedy'],
'status' => 'completed',
'rating' => 4.8,
'alternativeSlugs' => ['onepiece', 'op']
]
'alternativeSlugs' => ['onepiece', 'op'],
],
]);
// Then
@@ -80,8 +80,8 @@ class EditMangaTest extends AbstractApiTestCase
'author' => 'Eiichiro Oda',
'publicationYear' => 1997,
'genres' => ['action', 'adventure'],
'status' => 'ongoing'
]
'status' => 'ongoing',
],
]);
$this->assertResponseIsSuccessful();
@@ -93,14 +93,14 @@ class EditMangaTest extends AbstractApiTestCase
$mangaId = $createdManga->getId();
// When - Try to edit with invalid data
$client->request('PUT', '/api/mangas/' . $mangaId . '/edit', [
$client->request('PUT', '/api/mangas/'.$mangaId.'/edit', [
'json' => [
'title' => '', // Invalid: empty title
'publicationYear' => 2200, // Invalid: year > 2100
'genres' => [], // Invalid: empty genres
'status' => 'invalid-status', // Invalid status
'rating' => 6.0 // Invalid: rating > 5
]
'rating' => 6.0, // Invalid: rating > 5
],
]);
// Then
@@ -113,8 +113,8 @@ class EditMangaTest extends AbstractApiTestCase
$client = static::createClient();
$client->request('PUT', '/api/mangas/9999999/edit', [
'json' => [
'title' => 'Updated Title'
]
'title' => 'Updated Title',
],
]);
// Then
@@ -134,8 +134,8 @@ class EditMangaTest extends AbstractApiTestCase
'publicationYear' => 1997,
'genres' => ['action', 'adventure'],
'status' => 'ongoing',
'rating' => 4.5
]
'rating' => 4.5,
],
]);
$this->assertResponseIsSuccessful();
@@ -147,11 +147,11 @@ class EditMangaTest extends AbstractApiTestCase
$mangaId = $createdManga->getId();
// When - Edit only title and rating
$client->request('PUT', '/api/mangas/' . $mangaId . '/edit', [
$client->request('PUT', '/api/mangas/'.$mangaId.'/edit', [
'json' => [
'title' => 'One Piece - Updated Title Only',
'rating' => 4.9
]
'rating' => 4.9,
],
]);
// Then

View File

@@ -4,14 +4,14 @@ namespace Tests\Feature\Manga;
use App\Entity\Chapter;
use App\Entity\Manga;
use Zenstruck\Foundry\Test\ResetDatabase;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Zenstruck\Foundry\Test\ResetDatabase;
class EditMultipleChaptersTest extends WebTestCase
{
use ResetDatabase;
public function test_it_edits_multiple_chapters(): void
public function testItEditsMultipleChapters(): void
{
// Given
$client = static::createClient();
@@ -46,19 +46,19 @@ class EditMultipleChaptersTest extends WebTestCase
[
'id' => (string) $chapter1->getId(),
'title' => 'New Title 1',
'volume' => 2
'volume' => 2,
],
[
'id' => (string) $chapter2->getId(),
'title' => null,
'volume' => 3
]
]
'volume' => 3,
],
],
];
// When
$client->request('POST', '/api/chapters/batch-edit', [], [], [
'CONTENT_TYPE' => 'application/json'
'CONTENT_TYPE' => 'application/json',
], json_encode($data));
// Then
@@ -76,7 +76,7 @@ class EditMultipleChaptersTest extends WebTestCase
$this->assertEquals(3, $updatedChapter2->getVolume());
}
public function test_it_returns_404_when_chapter_not_found(): void
public function testItReturns404WhenChapterNotFound(): void
{
// Given
$client = static::createClient();
@@ -86,21 +86,21 @@ class EditMultipleChaptersTest extends WebTestCase
[
'id' => '999',
'title' => 'New Title',
'volume' => 1
]
]
'volume' => 1,
],
],
];
// When
$client->request('POST', '/api/chapters/batch-edit', [], [], [
'CONTENT_TYPE' => 'application/json'
'CONTENT_TYPE' => 'application/json',
], json_encode($data));
// Then
$this->assertResponseStatusCodeSame(404);
}
public function test_it_validates_required_fields(): void
public function testItValidatesRequiredFields(): void
{
// Given
$client = static::createClient();
@@ -109,15 +109,15 @@ class EditMultipleChaptersTest extends WebTestCase
'chapters' => [
[
'title' => 'New Title',
'volume' => 1
'volume' => 1,
// id manquant
]
]
],
],
];
// When
$client->request('POST', '/api/chapters/batch-edit', [], [], [
'CONTENT_TYPE' => 'application/json'
'CONTENT_TYPE' => 'application/json',
], json_encode($data));
// Then

View File

@@ -49,8 +49,8 @@ class FetchMangaChaptersTest extends AbstractApiTestCase
static::createClient()->request('POST', '/api/manga/chapters/fetch', [
'json' => [
'mangaId' => $mangaId
]
'mangaId' => $mangaId,
],
]);
$this->assertResponseStatusCodeSame(202);
@@ -65,8 +65,8 @@ class FetchMangaChaptersTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/manga/chapters/fetch', [
'json' => [
'mangaId' => ''
]
'mangaId' => '',
],
]);
$this->assertResponseStatusCodeSame(422);
@@ -74,9 +74,9 @@ class FetchMangaChaptersTest extends AbstractApiTestCase
'violations' => [
[
'propertyPath' => 'mangaId',
'message' => 'L\'identifiant du manga est obligatoire'
]
]
'message' => 'L\'identifiant du manga est obligatoire',
],
],
]);
}

View File

@@ -12,7 +12,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
{
use ResetDatabase;
public function test_it_finds_exact_match_by_filename(): void
public function testItFindsExactMatchByFilename(): void
{
// Given
$this->createManga('One Piece', 'one-piece');
@@ -21,8 +21,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'one-piece_vol108_ch1094.cbz'
]
'filename' => 'one-piece_vol108_ch1094.cbz',
],
]);
// Then
@@ -37,10 +37,9 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertEquals(1094.0, $data['matches'][0]['chapterNumber']);
$this->assertEquals(108, $data['matches'][0]['volumeNumber']);
$this->assertGreaterThan(0, $data['matches'][0]['matchScore']);
}
public function test_it_returns_empty_matches_when_no_manga_found(): void
public function testItReturnsEmptyMatchesWhenNoMangaFound(): void
{
// Given - no manga in database
@@ -48,8 +47,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'unknown-manga_vol1_ch1.cbz'
]
'filename' => 'unknown-manga_vol1_ch1.cbz',
],
]);
// Then
@@ -60,7 +59,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertCount(0, $data['matches']);
}
public function test_it_returns_bad_request_when_filename_is_missing(): void
public function testItReturnsBadRequestWhenFilenameIsMissing(): void
{
// When
$client = static::createClient();
@@ -70,7 +69,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(400);
}
public function test_it_extracts_chapter_and_volume_correctly(): void
public function testItExtractsChapterAndVolumeCorrectly(): void
{
// Given
$this->createManga('Attack on Titan', 'attack-on-titan');
@@ -79,8 +78,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'attack-on-titan_vol32_ch130.cbz'
]
'filename' => 'attack-on-titan_vol32_ch130.cbz',
],
]);
// Then
@@ -90,7 +89,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertNotEmpty($data['matches']);
}
public function test_it_handles_filename_with_only_volume(): void
public function testItHandlesFilenameWithOnlyVolume(): void
{
// Given
$this->createManga('Naruto', 'naruto');
@@ -99,8 +98,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'naruto_vol50.cbz'
]
'filename' => 'naruto_vol50.cbz',
],
]);
// Then
@@ -111,7 +110,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertEquals('Naruto', $data['matches'][0]['title']);
}
public function test_it_handles_filename_with_only_chapter(): void
public function testItHandlesFilenameWithOnlyChapter(): void
{
// Given
$this->createManga('Bleach', 'bleach');
@@ -120,8 +119,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'bleach_ch200.cbz'
]
'filename' => 'bleach_ch200.cbz',
],
]);
// Then
@@ -132,7 +131,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertEquals('Bleach', $data['matches'][0]['title']);
}
public function test_it_sorts_matches_by_score(): void
public function testItSortsMatchesByScore(): void
{
// Given
$this->createManga('One Piece', 'one-piece');
@@ -143,8 +142,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'one-piece_vol108_ch1094.cbz'
]
'filename' => 'one-piece_vol108_ch1094.cbz',
],
]);
// Then
@@ -158,13 +157,13 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertEquals('One Piece', $data['matches'][0]['title']);
// Vérifier que les scores sont triés par ordre décroissant
$scores = array_map(fn($match) => $match['matchScore'], $data['matches']);
$scores = array_map(fn ($match) => $match['matchScore'], $data['matches']);
$sortedScores = $scores;
rsort($sortedScores);
$this->assertEquals($sortedScores, $scores);
}
public function test_it_handles_alternative_slugs(): void
public function testItHandlesAlternativeSlugs(): void
{
// Given
$manga = $this->createManga('Shingeki no Kyojin', 'shingeki-no-kyojin');
@@ -175,8 +174,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'attack-on-titan_vol1_ch1.cbz'
]
'filename' => 'attack-on-titan_vol1_ch1.cbz',
],
]);
// Then
@@ -189,7 +188,7 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$this->assertContains('attack-on-titan', $data['matches'][0]['alternativeSlugs']);
}
public function test_it_provides_possible_titles_variants(): void
public function testItProvidesPossibleTitlesVariants(): void
{
// Given
$this->createManga('Dragon Ball', 'dragon-ball');
@@ -198,8 +197,8 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-matches', [
'query' => [
'filename' => 'dragon-ball_vol1_ch5.cbz'
]
'filename' => 'dragon-ball_vol1_ch5.cbz',
],
]);
// Then
@@ -233,4 +232,3 @@ class FindMangaMatchByFilenameTest extends AbstractApiTestCase
return $manga;
}
}

View File

@@ -2,7 +2,6 @@
namespace App\Tests\Feature\Manga;
use App\Entity\Manga;
use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
@@ -11,7 +10,8 @@ use Zenstruck\Foundry\Test\ResetDatabase;
class GetMangaBySlugTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function testGetMangaBySlugReturnsCorrectManga(): void
{
@@ -27,7 +27,7 @@ class GetMangaBySlugTest extends AbstractApiTestCase
'imageUrl' => 'https://example.com/image.jpg',
'thumbnailUrl' => 'https://example.com/thumbnail.jpg',
'rating' => 4.5,
'monitored' => true
'monitored' => true,
]);
// Act
@@ -58,4 +58,4 @@ class GetMangaBySlugTest extends AbstractApiTestCase
// Assert
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
}
}
}

View File

@@ -28,7 +28,7 @@ class GetMangaChaptersTest extends AbstractApiTestCase
// When
$client = static::createClient();
$response = $client->request('GET', '/api/mangas/' . $manga->getId() . '/chapters');
$response = $client->request('GET', '/api/mangas/'.$manga->getId().'/chapters');
// Then
$this->assertResponseIsSuccessful();
@@ -38,7 +38,7 @@ class GetMangaChaptersTest extends AbstractApiTestCase
'limit' => 20,
'hasNextPage' => false,
'hasPreviousPage' => false,
'items' => []
'items' => [],
]);
}
@@ -50,18 +50,18 @@ class GetMangaChaptersTest extends AbstractApiTestCase
// When
$client = static::createClient();
$response = $client->request('GET', '/api/mangas/' . $manga->getId() . '/chapters', [
$response = $client->request('GET', '/api/mangas/'.$manga->getId().'/chapters', [
'query' => [
'page' => 2,
'limit' => 10,
'sortOrder' => 'desc'
]
'sortOrder' => 'desc',
],
]);
// Then
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertCount(10, $data['items']);
$this->assertEquals(25, $data['total']);
$this->assertEquals(2, $data['page']);
@@ -69,7 +69,7 @@ class GetMangaChaptersTest extends AbstractApiTestCase
$this->assertTrue($data['hasNextPage']);
$this->assertTrue($data['hasPreviousPage']);
$numbers = array_map(fn($item) => $item['number'], $data['items']);
$numbers = array_map(fn ($item) => $item['number'], $data['items']);
$expectedNumbers = $numbers;
rsort($expectedNumbers);
@@ -99,12 +99,12 @@ class GetMangaChaptersTest extends AbstractApiTestCase
{
$entityManager = static::getContainer()->get('doctrine')->getManager();
for ($i = 1; $i <= $count; $i++) {
for ($i = 1; $i <= $count; ++$i) {
$chapter = new Chapter();
$chapter->setManga($manga)
->setNumber($i)
->setTitle("Chapter $i")
->setVolume((int)ceil($i / 10))
->setVolume((int) ceil($i / 10))
->setVisible(true);
$entityManager->persist($chapter);
@@ -112,4 +112,4 @@ class GetMangaChaptersTest extends AbstractApiTestCase
$entityManager->flush();
}
}
}

View File

@@ -11,7 +11,8 @@ use Zenstruck\Foundry\Test\ResetDatabase;
class GetMangaListTest extends AbstractApiTestCase
{
use ResetDatabase, Factories;
use ResetDatabase;
use Factories;
public function testGetEmptyMangaList(): void
{
@@ -27,7 +28,7 @@ class GetMangaListTest extends AbstractApiTestCase
'limit' => 20,
'hasNextPage' => false,
'hasPreviousPage' => false,
'items' => []
'items' => [],
]);
}
@@ -41,8 +42,8 @@ class GetMangaListTest extends AbstractApiTestCase
$response = $client->request('GET', '/api/mangas', [
'query' => [
'page' => 2,
'limit' => 10
]
'limit' => 10,
],
]);
// Then
@@ -69,8 +70,8 @@ class GetMangaListTest extends AbstractApiTestCase
$response = $client->request('GET', '/api/mangas', [
'query' => [
'sortBy' => 'title',
'sortOrder' => 'asc'
]
'sortOrder' => 'asc',
],
]);
// Then
@@ -113,7 +114,7 @@ class GetMangaListTest extends AbstractApiTestCase
private function createMangas(int $count): void
{
for ($i = 1; $i <= $count; $i++) {
for ($i = 1; $i <= $count; ++$i) {
$this->createManga("Manga $i");
}
}

View File

@@ -43,7 +43,7 @@ class GetMangaTest extends AbstractApiTestCase
// When
$client = static::createClient();
$response = $client->request('GET', '/api/mangas/by-id/' . $manga->getId());
$response = $client->request('GET', '/api/mangas/by-id/'.$manga->getId());
// Then
$this->assertResponseIsSuccessful();
@@ -58,7 +58,7 @@ class GetMangaTest extends AbstractApiTestCase
'status' => 'ongoing',
'externalId' => 'external-123',
'imageUrl' => 'http://example.com/image.jpg',
'rating' => 4.5
'rating' => 4.5,
]);
}
}
}

View File

@@ -9,7 +9,7 @@ class ImportChapterTest extends WebTestCase
{
private const API_ENDPOINT = '/api/chapters/import';
public function test_it_returns_404_when_manga_not_found(): void
public function testItReturns404WhenMangaNotFound(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -19,7 +19,7 @@ class ImportChapterTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'non-existent-manga-id',
'chapterNumber' => '1.5'
'chapterNumber' => '1.5',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -30,7 +30,7 @@ class ImportChapterTest extends WebTestCase
$this->assertEquals('Manga not found', $response['error']);
}
public function test_it_returns_422_when_manga_id_is_missing(): void
public function testItReturns422WhenMangaIdIsMissing(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -39,7 +39,7 @@ class ImportChapterTest extends WebTestCase
'POST',
self::API_ENDPOINT,
[
'chapterNumber' => '1.5'
'chapterNumber' => '1.5',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -50,7 +50,7 @@ class ImportChapterTest extends WebTestCase
$this->assertStringContainsString('mangaId is required', $response[0]['message']);
}
public function test_it_returns_422_when_chapter_number_is_missing(): void
public function testItReturns422WhenChapterNumberIsMissing(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -59,7 +59,7 @@ class ImportChapterTest extends WebTestCase
'POST',
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id'
'mangaId' => 'some-manga-id',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -70,7 +70,7 @@ class ImportChapterTest extends WebTestCase
$this->assertStringContainsString('chapterNumber is required', $response[0]['message']);
}
public function test_it_returns_422_when_file_is_missing(): void
public function testItReturns422WhenFileIsMissing(): void
{
$client = static::createClient();
@@ -79,7 +79,7 @@ class ImportChapterTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id',
'chapterNumber' => '1.5'
'chapterNumber' => '1.5',
],
[],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -90,7 +90,7 @@ class ImportChapterTest extends WebTestCase
$this->assertStringContainsString('Please upload a file', $response[0]['message']);
}
public function test_it_returns_422_when_file_is_not_cbz(): void
public function testItReturns422WhenFileIsNotCbz(): void
{
$client = static::createClient();
@@ -103,7 +103,7 @@ class ImportChapterTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id',
'chapterNumber' => '1.5'
'chapterNumber' => '1.5',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -120,7 +120,7 @@ class ImportChapterTest extends WebTestCase
unlink($tmpFile);
$zip = new \ZipArchive();
if ($zip->open($tmpFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
if (true !== $zip->open($tmpFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
throw new \RuntimeException('Cannot create test CBZ file');
}

View File

@@ -9,7 +9,7 @@ class ImportVolumeTest extends WebTestCase
{
private const API_ENDPOINT = '/api/volumes/import';
public function test_it_returns_404_when_manga_not_found(): void
public function testItReturns404WhenMangaNotFound(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -19,7 +19,7 @@ class ImportVolumeTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'non-existent-manga-id',
'volumeNumber' => '1'
'volumeNumber' => '1',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -30,7 +30,7 @@ class ImportVolumeTest extends WebTestCase
$this->assertEquals('Manga not found', $response['error']);
}
public function test_it_returns_422_when_manga_id_is_missing(): void
public function testItReturns422WhenMangaIdIsMissing(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -39,7 +39,7 @@ class ImportVolumeTest extends WebTestCase
'POST',
self::API_ENDPOINT,
[
'volumeNumber' => '1'
'volumeNumber' => '1',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -50,7 +50,7 @@ class ImportVolumeTest extends WebTestCase
$this->assertStringContainsString('mangaId is required', $response[0]['message']);
}
public function test_it_returns_422_when_volume_number_is_missing(): void
public function testItReturns422WhenVolumeNumberIsMissing(): void
{
$client = static::createClient();
$file = $this->createValidCbzFile();
@@ -59,7 +59,7 @@ class ImportVolumeTest extends WebTestCase
'POST',
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id'
'mangaId' => 'some-manga-id',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -70,7 +70,7 @@ class ImportVolumeTest extends WebTestCase
$this->assertStringContainsString('volumeNumber is required', $response[0]['message']);
}
public function test_it_returns_422_when_file_is_missing(): void
public function testItReturns422WhenFileIsMissing(): void
{
$client = static::createClient();
@@ -79,7 +79,7 @@ class ImportVolumeTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id',
'volumeNumber' => '1'
'volumeNumber' => '1',
],
[],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -90,7 +90,7 @@ class ImportVolumeTest extends WebTestCase
$this->assertStringContainsString('Please upload a file', $response[0]['message']);
}
public function test_it_returns_422_when_file_is_not_cbz(): void
public function testItReturns422WhenFileIsNotCbz(): void
{
$client = static::createClient();
@@ -103,7 +103,7 @@ class ImportVolumeTest extends WebTestCase
self::API_ENDPOINT,
[
'mangaId' => 'some-manga-id',
'volumeNumber' => '1'
'volumeNumber' => '1',
],
['file' => $file],
['CONTENT_TYPE' => 'multipart/form-data']
@@ -120,7 +120,7 @@ class ImportVolumeTest extends WebTestCase
unlink($tmpFile);
$zip = new \ZipArchive();
if ($zip->open($tmpFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) !== true) {
if (true !== $zip->open($tmpFile, \ZipArchive::CREATE | \ZipArchive::OVERWRITE)) {
throw new \RuntimeException('Cannot create test CBZ file');
}

View File

@@ -16,15 +16,15 @@ class SearchMangaTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-search', [
'query' => [
'q' => ''
]
'q' => '',
],
]);
// Then
$this->assertResponseStatusCodeSame(400);
$this->assertJsonContains([
'hydra:title' => 'An error occurred',
'hydra:description' => 'Le terme de recherche doit contenir au moins 3 caractères'
'title' => 'An error occurred',
'detail' => 'Le terme de recherche doit contenir au moins 3 caractères',
]);
}
@@ -34,15 +34,15 @@ class SearchMangaTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-search', [
'query' => [
'q' => 'on'
]
'q' => 'on',
],
]);
// Then
$this->assertResponseStatusCodeSame(400);
$this->assertJsonContains([
'hydra:title' => 'An error occurred',
'hydra:description' => 'Le terme de recherche doit contenir au moins 3 caractères'
'title' => 'An error occurred',
'detail' => 'Le terme de recherche doit contenir au moins 3 caractères',
]);
}
@@ -57,8 +57,8 @@ class SearchMangaTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-search', [
'query' => [
'q' => 'one'
]
'q' => 'one',
],
]);
// Then
@@ -66,9 +66,8 @@ class SearchMangaTest extends AbstractApiTestCase
$data = $response->toArray();
$this->assertCount(2, $data['items']['hydra:member']);
$titles = array_map(fn($item) => $item['title'], $data['items']['hydra:member']);
$this->assertCount(2, $data['items']['member']);
$titles = array_map(fn ($item) => $item['title'], $data['items']['member']);
$this->assertContains('One Piece', $titles);
$this->assertContains('One Punch Man', $titles);
}
@@ -83,17 +82,17 @@ class SearchMangaTest extends AbstractApiTestCase
$client = static::createClient();
$response = $client->request('GET', '/api/manga-search', [
'query' => [
'q' => 'dragon'
]
'q' => 'dragon',
],
]);
// Then
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertCount(1, $data['items']['hydra:member']);
$this->assertEquals('Dragon Ball', $data['items']['hydra:member'][0]['title']);
$this->assertEquals('dragon-ball', $data['items']['hydra:member'][0]['slug']);
$this->assertCount(1, $data['items']['member']);
$this->assertEquals('Dragon Ball', $data['items']['member'][0]['title']);
$this->assertEquals('dragon-ball', $data['items']['member'][0]['slug']);
}
// public function testSearchMangaWithPagination(): void

View File

@@ -39,8 +39,8 @@ class ToggleMonitoringTest extends AbstractApiTestCase
// Act
static::createClient()->request('POST', "/api/manga/{$mangaId}/monitoring/toggle", [
'json' => [
'enabled' => true
]
'enabled' => true,
],
]);
// Assert
@@ -78,8 +78,8 @@ class ToggleMonitoringTest extends AbstractApiTestCase
// Act
static::createClient()->request('POST', "/api/manga/{$mangaId}/monitoring/toggle", [
'json' => [
'enabled' => false
]
'enabled' => false,
],
]);
// Assert
@@ -96,8 +96,8 @@ class ToggleMonitoringTest extends AbstractApiTestCase
// Act & Assert
static::createClient()->request('POST', '/api/manga/99999/monitoring/toggle', [
'json' => [
'enabled' => true
]
'enabled' => true,
],
]);
$this->assertResponseStatusCodeSame(404);
@@ -127,7 +127,7 @@ class ToggleMonitoringTest extends AbstractApiTestCase
// Act & Assert
static::createClient()->request('POST', "/api/manga/{$mangaId}/monitoring/toggle", [
'json' => []
'json' => [],
]);
$this->assertResponseStatusCodeSame(422);
@@ -135,9 +135,9 @@ class ToggleMonitoringTest extends AbstractApiTestCase
'violations' => [
[
'propertyPath' => 'enabled',
'message' => 'Le champ enabled est obligatoire'
]
]
'message' => 'Le champ enabled est obligatoire',
],
],
]);
}
@@ -166,8 +166,8 @@ class ToggleMonitoringTest extends AbstractApiTestCase
// Act & Assert
static::createClient()->request('POST', "/api/manga/{$mangaId}/monitoring/toggle", [
'json' => [
'enabled' => 'invalid'
]
'enabled' => 'invalid',
],
]);
$this->assertResponseStatusCodeSame(422);
@@ -175,9 +175,9 @@ class ToggleMonitoringTest extends AbstractApiTestCase
'violations' => [
[
'propertyPath' => 'enabled',
'message' => 'Cette valeur doit être de type bool.'
]
]
'message' => 'Cette valeur doit être de type bool.',
],
],
]);
}

View File

@@ -45,23 +45,23 @@ final class GetChapterContextTest extends AbstractApiTestCase
]);
// Act
static::createClient()->request('GET', '/api/reader/chapter/' . $chapter1->getId());
static::createClient()->request('GET', '/api/reader/chapter/'.$chapter1->getId());
// Assert
$this->assertResponseIsSuccessful();
$this->assertResponseHeaderSame('content-type', 'application/ld+json; charset=utf-8');
$this->assertJsonContains([
'id' => (string)$chapter1->getId(),
'mangaId' => (string)$manga->getId(),
'id' => (string) $chapter1->getId(),
'mangaId' => (string) $manga->getId(),
'title' => 'Chapter 1',
'number' => 1,
'totalPages' => 0,
'navigation' => [
'hydra:member' => [
null, (string)$chapter2->getId(),
'member' => [
null, (string) $chapter2->getId(),
],
]
],
]);
}
@@ -75,8 +75,8 @@ final class GetChapterContextTest extends AbstractApiTestCase
$this->assertResponseHeaderSame('content-type', 'application/problem+json; charset=utf-8');
$this->assertJsonContains([
'hydra:title' => 'An error occurred',
'hydra:description' => 'Le chapitre 0 n\'existe pas',
'title' => 'An error occurred',
'detail' => 'Le chapitre 0 n\'existe pas',
]);
}
}

View File

@@ -9,7 +9,6 @@ use App\Tests\Factory\MangaFactory;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\Foundry\Test\ResetDatabase;
use ZipArchive;
final class GetChapterPagesTest extends AbstractApiTestCase
{
@@ -23,16 +22,16 @@ final class GetChapterPagesTest extends AbstractApiTestCase
parent::setUp();
// Extraire quelques images du CBZ dans un dossier temporaire
$this->pagesDirectory = sys_get_temp_dir() . '/mangarr-test-pages-' . uniqid();
$this->pagesDirectory = sys_get_temp_dir().'/mangarr-test-pages-'.uniqid();
mkdir($this->pagesDirectory);
$zip = new ZipArchive();
$zip->open(__DIR__ . '/../../Fixtures/chapter.cbz');
$zip = new \ZipArchive();
$zip->open(__DIR__.'/../../Fixtures/chapter.cbz');
$zip->extractTo($this->pagesDirectory, ['007.jpg', '008.jpg']);
$zip->close();
$manga = MangaFactory::createOne([
'title' => 'Test Manga',
'slug' => 'test-manga'
'slug' => 'test-manga',
]);
$chapter = ChapterFactory::createOne([
@@ -41,7 +40,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
'number' => 1.0,
'volume' => 1,
'visible' => true,
'pagesDirectory' => $this->pagesDirectory
'pagesDirectory' => $this->pagesDirectory,
]);
$this->chapterId = $chapter->getId();
@@ -51,7 +50,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
{
parent::tearDown();
foreach (glob($this->pagesDirectory . '/*') as $file) {
foreach (glob($this->pagesDirectory.'/*') as $file) {
unlink($file);
}
rmdir($this->pagesDirectory);
@@ -63,7 +62,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
$this->assertJsonContains([
'detail' => 'Le chapitre 999 n\'existe pas'
'detail' => 'Le chapitre 999 n\'existe pas',
]);
}
@@ -99,8 +98,8 @@ final class GetChapterPagesTest extends AbstractApiTestCase
$response = static::createClient()->request('GET', "/api/reader/chapter/{$this->chapterId}/pages", [
'query' => [
'page' => 1,
'itemsPerPage' => 5
]
'itemsPerPage' => 5,
],
]);
$this->assertResponseIsSuccessful();
@@ -133,7 +132,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
// Créer un chapitre sans fichier CBZ
$manga = MangaFactory::createOne([
'title' => 'Empty Manga',
'slug' => 'empty-manga'
'slug' => 'empty-manga',
]);
$emptyChapter = ChapterFactory::createOne([
@@ -142,7 +141,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
'number' => 1.0,
'volume' => 1,
'visible' => true,
'cbzPath' => null
'cbzPath' => null,
]);
$response = static::createClient()->request('GET', "/api/reader/chapter/{$emptyChapter->getId()}/pages");
@@ -155,8 +154,8 @@ final class GetChapterPagesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('GET', "/api/reader/chapter/{$this->chapterId}/pages", [
'query' => [
'page' => -1
]
'page' => -1,
],
]);
$this->assertResponseIsSuccessful();
@@ -167,11 +166,11 @@ final class GetChapterPagesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('GET', "/api/reader/chapter/{$this->chapterId}/pages", [
'query' => [
'itemsPerPage' => 0
]
'itemsPerPage' => 0,
],
]);
//TODO: Corriger la fonctionnalité de pagination pour que l'endpoint retourne une erreur 400 quand itemsPerPage est 0 (division par zéro)
// TODO: Corriger la fonctionnalité de pagination pour que l'endpoint retourne une erreur 400 quand itemsPerPage est 0 (division par zéro)
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
// L'endpoint retourne une erreur 500 quand itemsPerPage est 0 (division par zéro)
}
@@ -180,7 +179,7 @@ final class GetChapterPagesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('GET', '/api/reader/chapter/invalid-id/pages');
//TODO: Corriger le cas où l'ID est invalide
// TODO: Corriger le cas où l'ID est invalide
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
// L'endpoint retourne une erreur 500 quand l'ID est invalide
}

View File

@@ -12,8 +12,9 @@ use Ramsey\Uuid\Uuid;
class ScrapingJobFactory
{
public function __construct(
private readonly ScrapingJobRepositoryInterface $repository
) {}
private readonly ScrapingJobRepositoryInterface $repository,
) {
}
public function createJob(array $attributes = []): ScrapingJob
{
@@ -48,4 +49,4 @@ class ScrapingJobFactory
$reflection->setAccessible(true);
$reflection->setValue($job, $status);
}
}
}

View File

@@ -70,7 +70,7 @@ final class GetMangaPreferredSourcesTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
$this->assertJsonContains([
'detail' => 'Manga not found with ID: 999999'
'detail' => 'Manga not found with ID: 999999',
]);
}

View File

@@ -4,13 +4,10 @@ namespace App\Tests\Feature\Scraping;
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
use App\Domain\Scraping\Domain\Model\ScrapingJob;
use App\Domain\Scraping\Domain\Model\ScrapingStatus;
use App\Domain\Scraping\Domain\Model\ValueObject\ImageUrl;
use App\Domain\Scraping\Domain\Model\ValueObject\PageNumber;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Messenger\MessageBusInterface;
use App\Domain\Shared\Domain\Contract\JobRepositoryInterface;
use App\Domain\Shared\Domain\Model\JobStatus;
use Ramsey\Uuid\Uuid;
use Symfony\Component\Messenger\MessageBusInterface;
class ScrapingStatusTest extends ApiTestCase
{
@@ -45,12 +42,12 @@ class ScrapingStatusTest extends ApiTestCase
$responseData = $response->toArray();
$this->assertArrayHasKey('hydra:member', $responseData);
$this->assertIsArray($responseData['hydra:member']);
$this->assertCount(1, $responseData['hydra:member']);
$this->assertArrayHasKey('member', $responseData);
$this->assertIsArray($responseData['member']);
$this->assertCount(1, $responseData['member']);
$jobData = $responseData['hydra:member'][0];
$this->assertEquals('/api/jobs/' . $jobId, $jobData['@id']);
$jobData = $responseData['member'][0];
$this->assertEquals('/api/jobs/'.$jobId, $jobData['@id']);
$this->assertEquals('Job', $jobData['@type']);
$this->assertEquals($jobId, $jobData['id']);
$this->assertEquals('scraping_job', $jobData['type']);
@@ -58,7 +55,7 @@ class ScrapingStatusTest extends ApiTestCase
$this->assertEquals([
'mangaId' => 'manga-123',
'chapterNumber' => 1,
'sourceId' => 'source-789'
'sourceId' => 'source-789',
], $jobData['context']);
}
@@ -66,7 +63,7 @@ class ScrapingStatusTest extends ApiTestCase
{
// When
$response = static::createClient()->request('GET', '/api/jobs/non-existent-id?status=in_progress', [
'headers' => ['Accept' => 'application/json']
'headers' => ['Accept' => 'application/json'],
]);
// Then

View File

@@ -4,9 +4,9 @@ declare(strict_types=1);
namespace App\Tests\Feature\Scraping;
use App\Domain\Scraping\Domain\Contract\Repository\MangaRepositoryInterface;
use App\Entity\ContentSource;
use App\Entity\Manga;
use App\Domain\Scraping\Domain\Contract\Repository\MangaRepositoryInterface;
use App\Tests\Feature\AbstractApiTestCase;
use Symfony\Component\HttpFoundation\Response;
use Zenstruck\Foundry\Test\ResetDatabase;
@@ -72,13 +72,13 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/mangas/999999/preferred-sources', [
'json' => [
'sourceIds' => [(string) $this->source1Id]
]
'sourceIds' => [(string) $this->source1Id],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
$this->assertJsonContains([
'detail' => 'Manga not found with ID: 999999'
'detail' => 'Manga not found with ID: 999999',
]);
}
@@ -86,13 +86,13 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'sourceIds' => ['999999']
]
'sourceIds' => ['999999'],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
$this->assertJsonContains([
'detail' => 'One or more sources do not exist or are not active'
'detail' => 'One or more sources do not exist or are not active',
]);
}
@@ -100,8 +100,8 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'sourceIds' => [(string) $this->source1Id, (string) $this->source2Id]
]
'sourceIds' => [(string) $this->source1Id, (string) $this->source2Id],
],
]);
$this->assertResponseIsSuccessful();
@@ -127,8 +127,8 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
// Modifier les sources préférées
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'sourceIds' => [(string) $this->source2Id]
]
'sourceIds' => [(string) $this->source2Id],
],
]);
$this->assertResponseIsSuccessful();
@@ -143,8 +143,8 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'sourceIds' => []
]
'sourceIds' => [],
],
]);
$this->assertResponseIsSuccessful();
@@ -159,11 +159,11 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'sourceIds' => ['invalid-id', '123']
]
'sourceIds' => ['invalid-id', '123'],
],
]);
//TODO: Corriger le cas où l'ID est invalide
// TODO: Corriger le cas où l'ID est invalide
$this->assertResponseStatusCodeSame(Response::HTTP_INTERNAL_SERVER_ERROR);
}
@@ -171,11 +171,11 @@ final class SetMangaPreferredSourcesTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', "/api/mangas/{$this->mangaId}/preferred-sources", [
'json' => [
'invalidField' => 'value'
]
'invalidField' => 'value',
],
]);
//TODO: Corriger le cas où le format de la requête est invalide
// TODO: Corriger le cas où le format de la requête est invalide
$this->assertResponseStatusCodeSame(Response::HTTP_OK);
}
}

View File

@@ -77,7 +77,7 @@ class TestScraperConfigurationTest extends AbstractApiTestCase
$this->assertGreaterThan(0, count($responseData['errors']));
}
public function testTestScraperConfigurationWithInvalidSelector(): void
public function testTestScraperConfigurationWithInvalidSelector(): void
{
// Given - Configuration avec un sélecteur CSS qui ne trouvera rien
$payload = [
@@ -165,7 +165,7 @@ class TestScraperConfigurationTest extends AbstractApiTestCase
]);
}
public function testTestScraperConfigurationWithUnsupportedScrapingType(): void
public function testTestScraperConfigurationWithUnsupportedScrapingType(): void
{
// Given - Type de scraping non supporté
$payload = [

View File

@@ -26,11 +26,11 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.chapter-image img',
'nextPageSelector' => '.next-page',
'chapterSelector' => '.chapter-list a'
'chapterSelector' => '.chapter-list a',
];
$response = static::createClient()->request('POST', '/api/content-sources', [
'json' => $sourceData
'json' => $sourceData,
]);
$this->assertResponseIsSuccessful();
@@ -44,12 +44,14 @@ final class CreateContentSourceTest extends AbstractApiTestCase
// Vérifier que la source a été sauvegardée en base
$source = $this->entityManager->find(ContentSource::class, $sourceId);
if ($source === null) {
if (null === $source) {
// L'ID peut ne pas correspondre, vérifions juste que l'opération s'est bien passée
$this->assertIsNumeric($responseContent);
return;
}
$this->assertEquals($sourceData['baseUrl'], $source->getBaseUrl());
return;
}
@@ -74,8 +76,8 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => '',
'chapterUrlFormat' => '',
'scrapingType' => ''
]
'scrapingType' => '',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -87,8 +89,8 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'invalid-url',
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
'scrapingType' => 'html'
]
'scrapingType' => 'html',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -100,8 +102,8 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'https://mangadex.org',
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
'scrapingType' => 'invalid-type'
]
'scrapingType' => 'invalid-type',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -115,11 +117,11 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.chapter-image img',
'nextPageSelector' => '.next-page',
'chapterSelector' => '.chapter-list a'
'chapterSelector' => '.chapter-list a',
];
$response = static::createClient()->request('POST', '/api/content-sources', [
'json' => $sourceData
'json' => $sourceData,
]);
$this->assertResponseIsSuccessful();
@@ -129,6 +131,7 @@ final class CreateContentSourceTest extends AbstractApiTestCase
$responseContent = $response->getContent();
if (is_numeric($responseContent)) {
$this->assertIsNumeric($responseContent);
return;
}
@@ -146,11 +149,11 @@ final class CreateContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'javascript',
'imageSelector' => '.page-image img',
'nextPageSelector' => '.next-button',
'chapterSelector' => '.chapter-link'
'chapterSelector' => '.chapter-link',
];
$response = static::createClient()->request('POST', '/api/content-sources', [
'json' => $sourceData
'json' => $sourceData,
]);
$this->assertResponseIsSuccessful();
@@ -160,6 +163,7 @@ final class CreateContentSourceTest extends AbstractApiTestCase
$responseContent = $response->getContent();
if (is_numeric($responseContent)) {
$this->assertIsNumeric($responseContent);
return;
}
@@ -171,8 +175,8 @@ final class CreateContentSourceTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/content-sources', [
'json' => [
'invalidField' => 'value'
]
'invalidField' => 'value',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);

View File

@@ -24,8 +24,6 @@ final class ExportContentSourceTest extends AbstractApiTestCase
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertIsArray($data);
// L'endpoint retourne un format Hydra mais les données semblent vides
// Pour l'instant, vérifions juste que la réponse est un tableau
@@ -63,7 +61,7 @@ final class ExportContentSourceTest extends AbstractApiTestCase
// L'endpoint retourne un format Hydra mais les données semblent vides
// Pour l'instant, vérifions juste que la réponse est un tableau
$this->assertArrayHasKey('@type', $data);
$this->assertEquals('hydra:Collection', $data['@type']);
$this->assertEquals('Collection', $data['@type']);
}
public function testItExportsSourcesWithNullOptionalFields(): void
@@ -89,13 +87,13 @@ final class ExportContentSourceTest extends AbstractApiTestCase
// L'endpoint retourne un format Hydra mais les données semblent vides
// Pour l'instant, vérifions juste que la réponse est un tableau
$this->assertArrayHasKey('@type', $data);
$this->assertEquals('hydra:Collection', $data['@type']);
$this->assertEquals('Collection', $data['@type']);
}
public function testItExportsLargeNumberOfSources(): void
{
// Création de plusieurs sources
for ($i = 1; $i <= 25; $i++) {
for ($i = 1; $i <= 25; ++$i) {
$source = new ContentSource();
$source->setBaseUrl("https://source{$i}.com")
->setChapterUrlFormat("https://source{$i}.com/chapter/{id}")
@@ -117,7 +115,7 @@ final class ExportContentSourceTest extends AbstractApiTestCase
// L'endpoint retourne un format Hydra mais les données semblent vides
// Pour l'instant, vérifions juste que la réponse est un tableau
$this->assertArrayHasKey('@type', $data);
$this->assertEquals('hydra:Collection', $data['@type']);
$this->assertEquals('Collection', $data['@type']);
}
public function testItExportsSourcesInCorrectFormat(): void
@@ -152,6 +150,6 @@ final class ExportContentSourceTest extends AbstractApiTestCase
// L'endpoint retourne un format Hydra mais les données semblent vides
// Pour l'instant, vérifions juste que la réponse est un tableau
$this->assertArrayHasKey('@type', $data);
$this->assertEquals('hydra:Collection', $data['@type']);
$this->assertEquals('Collection', $data['@type']);
}
}

View File

@@ -40,7 +40,7 @@ final class GetContentSourceTest extends AbstractApiTestCase
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
$this->assertJsonContains([
'detail' => 'ContentSource with id 999999 not found'
'detail' => 'ContentSource with id 999999 not found',
]);
}

View File

@@ -28,7 +28,7 @@ final class ImportContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.chapter-image img',
'nextPageSelector' => '.next-page',
'chapterSelector' => '.chapter-list a'
'chapterSelector' => '.chapter-list a',
],
[
'baseUrl' => 'https://mangakakalot.com',
@@ -36,13 +36,13 @@ final class ImportContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'javascript',
'imageSelector' => '.page-image img',
'nextPageSelector' => '.next-button',
'chapterSelector' => '.chapter-link'
]
]
'chapterSelector' => '.chapter-link',
],
],
];
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => $importData
'json' => $importData,
]);
$this->assertResponseIsSuccessful();
@@ -52,7 +52,7 @@ final class ImportContentSourceTest extends AbstractApiTestCase
$sources = $this->entityManager->getRepository(ContentSource::class)->findAll();
$this->assertCount(2, $sources);
$baseUrls = array_map(fn($source) => $source->getBaseUrl(), $sources);
$baseUrls = array_map(fn ($source) => $source->getBaseUrl(), $sources);
$this->assertContains('https://mangadex.org', $baseUrls);
$this->assertContains('https://mangakakalot.com', $baseUrls);
}
@@ -65,10 +65,10 @@ final class ImportContentSourceTest extends AbstractApiTestCase
[
'baseUrl' => '',
'chapterUrlFormat' => '',
'scrapingType' => ''
]
]
]
'scrapingType' => '',
],
],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_BAD_REQUEST);
@@ -85,10 +85,10 @@ final class ImportContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.image',
'nextPageSelector' => '.next',
'chapterSelector' => '.chapter'
]
]
]
'chapterSelector' => '.chapter',
],
],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_CREATED);
@@ -105,10 +105,10 @@ final class ImportContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'invalid-type',
'imageSelector' => '.image',
'nextPageSelector' => '.next',
'chapterSelector' => '.chapter'
]
]
]
'chapterSelector' => '.chapter',
],
],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_CREATED);
@@ -118,8 +118,8 @@ final class ImportContentSourceTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => [
'contentSources' => 'not-an-array'
]
'contentSources' => 'not-an-array',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_BAD_REQUEST);
@@ -129,8 +129,8 @@ final class ImportContentSourceTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => [
'contentSources' => []
]
'contentSources' => [],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -140,8 +140,8 @@ final class ImportContentSourceTest extends AbstractApiTestCase
{
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => [
'invalidField' => []
]
'invalidField' => [],
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -157,13 +157,13 @@ final class ImportContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.simple-image',
'nextPageSelector' => '.simple-next',
'chapterSelector' => '.simple-chapter'
]
]
'chapterSelector' => '.simple-chapter',
],
],
];
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => $importData
'json' => $importData,
]);
$this->assertResponseIsSuccessful();
@@ -171,7 +171,7 @@ final class ImportContentSourceTest extends AbstractApiTestCase
// Vérifier que la source a été créée
$source = $this->entityManager->getRepository(ContentSource::class)->findOneBy([
'baseUrl' => 'https://simple-source.com'
'baseUrl' => 'https://simple-source.com',
]);
$this->assertNotNull($source);
$this->assertEquals('html', $source->getScrapingType());
@@ -183,21 +183,21 @@ final class ImportContentSourceTest extends AbstractApiTestCase
public function testItHandlesLargeImport(): void
{
$contentSources = [];
for ($i = 1; $i <= 10; $i++) {
for ($i = 1; $i <= 10; ++$i) {
$contentSources[] = [
'baseUrl' => "https://source{$i}.com",
'chapterUrlFormat' => "https://source{$i}.com/chapter/{id}",
'scrapingType' => 'html',
'imageSelector' => ".source{$i}-image img",
'nextPageSelector' => ".source{$i}-next",
'chapterSelector' => ".source{$i}-chapter a"
'chapterSelector' => ".source{$i}-chapter a",
];
}
$response = static::createClient()->request('POST', '/api/content-sources/import', [
'json' => [
'contentSources' => $contentSources
]
'contentSources' => $contentSources,
],
]);
$this->assertResponseIsSuccessful();

View File

@@ -24,10 +24,10 @@ final class ListContentSourceTest extends AbstractApiTestCase
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertArrayHasKey('hydra:member', $data);
$this->assertCount(0, $data['hydra:member']);
$this->assertArrayHasKey('hydra:totalItems', $data);
$this->assertEquals(0, $data['hydra:totalItems']);
$this->assertArrayHasKey('member', $data);
$this->assertCount(0, $data['member']);
$this->assertArrayHasKey('totalItems', $data);
$this->assertEquals(0, $data['totalItems']);
}
public function testItReturnsAllSources(): void
@@ -58,13 +58,13 @@ final class ListContentSourceTest extends AbstractApiTestCase
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertArrayHasKey('hydra:member', $data);
$this->assertCount(2, $data['hydra:member']);
$this->assertArrayHasKey('hydra:totalItems', $data);
$this->assertEquals(2, $data['hydra:totalItems']);
$this->assertArrayHasKey('member', $data);
$this->assertCount(2, $data['member']);
$this->assertArrayHasKey('totalItems', $data);
$this->assertEquals(2, $data['totalItems']);
// Vérifier la structure d'une source
$firstSource = $data['hydra:member'][0];
$firstSource = $data['member'][0];
$this->assertArrayHasKey('id', $firstSource);
$this->assertArrayHasKey('baseUrl', $firstSource);
$this->assertArrayHasKey('chapterUrlFormat', $firstSource);
@@ -75,7 +75,7 @@ final class ListContentSourceTest extends AbstractApiTestCase
$this->assertArrayHasKey('cleanBaseUrl', $firstSource);
// Vérifier que les URLs sont bien présentes
$baseUrls = array_column($data['hydra:member'], 'baseUrl');
$baseUrls = array_column($data['member'], 'baseUrl');
$this->assertContains('https://mangadex.org', $baseUrls);
$this->assertContains('https://mangakakalot.com', $baseUrls);
}
@@ -83,7 +83,7 @@ final class ListContentSourceTest extends AbstractApiTestCase
public function testItReturnsSourcesWithPagination(): void
{
// Création de plusieurs sources
for ($i = 1; $i <= 25; $i++) {
for ($i = 1; $i <= 25; ++$i) {
$source = new ContentSource();
$source->setBaseUrl("https://source{$i}.com")
->setChapterUrlFormat("https://source{$i}.com/chapter/{id}")
@@ -99,20 +99,20 @@ final class ListContentSourceTest extends AbstractApiTestCase
$response = static::createClient()->request('GET', '/api/content-sources', [
'query' => [
'page' => 2,
'itemsPerPage' => 10
]
'itemsPerPage' => 10,
],
]);
$this->assertResponseIsSuccessful();
$data = $response->toArray();
$this->assertArrayHasKey('hydra:member', $data);
$this->assertArrayHasKey('hydra:totalItems', $data);
$this->assertEquals(25, $data['hydra:totalItems']);
$this->assertArrayHasKey('member', $data);
$this->assertArrayHasKey('totalItems', $data);
$this->assertEquals(25, $data['totalItems']);
// Vérifier la pagination - l'endpoint peut retourner toutes les sources
// même avec des paramètres de pagination
$this->assertGreaterThanOrEqual(10, count($data['hydra:member']));
$this->assertLessThanOrEqual(25, count($data['hydra:member']));
$this->assertGreaterThanOrEqual(10, count($data['member']));
$this->assertLessThanOrEqual(25, count($data['member']));
}
}

View File

@@ -40,13 +40,13 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'https://updated.com',
'chapterUrlFormat' => 'https://updated.com/chapter/{id}',
'scrapingType' => 'html'
]
'scrapingType' => 'html',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
$this->assertJsonContains([
'detail' => 'ContentSource with id 999999 not found'
'detail' => 'ContentSource with id 999999 not found',
]);
}
@@ -58,11 +58,11 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'javascript',
'imageSelector' => '.updated-image img',
'nextPageSelector' => '.updated-next',
'chapterSelector' => '.updated-chapter a'
'chapterSelector' => '.updated-chapter a',
];
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
'json' => $updatedData
'json' => $updatedData,
]);
$this->assertResponseIsSuccessful();
@@ -72,6 +72,7 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
$responseContent = $response->getContent();
if (is_numeric($responseContent)) {
$this->assertIsNumeric($responseContent);
return;
}
@@ -96,8 +97,8 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => '',
'chapterUrlFormat' => '',
'scrapingType' => ''
]
'scrapingType' => '',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -109,8 +110,8 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'invalid-url',
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
'scrapingType' => 'html'
]
'scrapingType' => 'html',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -122,8 +123,8 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'https://mangadex.org',
'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}',
'scrapingType' => 'invalid-type'
]
'scrapingType' => 'invalid-type',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);
@@ -137,11 +138,11 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'scrapingType' => 'html',
'imageSelector' => '.updated-image img',
'nextPageSelector' => '.updated-next-page',
'chapterSelector' => '.updated-chapter-list a'
'chapterSelector' => '.updated-chapter-list a',
];
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
'json' => $updatedData
'json' => $updatedData,
]);
$this->assertResponseIsSuccessful();
@@ -150,6 +151,7 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
$responseContent = $response->getContent();
if (is_numeric($responseContent)) {
$this->assertIsNumeric($responseContent);
return;
}
@@ -169,8 +171,8 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
'json' => [
'baseUrl' => 'https://test.com',
'chapterUrlFormat' => 'https://test.com/chapter/{id}',
'scrapingType' => 'html'
]
'scrapingType' => 'html',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND);
@@ -180,8 +182,8 @@ final class UpdateContentSourceTest extends AbstractApiTestCase
{
$response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [
'json' => [
'invalidField' => 'value'
]
'invalidField' => 'value',
],
]);
$this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY);