setBaseUrl('https://mangadex.org') ->setChapterUrlFormat('https://mangadex.org/chapter/{id}') ->setScrapingType('html') ->setImageSelector('.chapter-image img') ->setNextPageSelector('.next-page') ->setChapterSelector('.chapter-list a'); $this->entityManager->persist($source); $this->entityManager->flush(); $this->sourceId = $source->getId(); } public function testItReturnsNotFoundWhenSourceDoesNotExist(): void { $response = static::createClient()->request('PUT', '/api/content-sources/999999', [ 'json' => [ 'baseUrl' => 'https://updated.com', 'chapterUrlFormat' => 'https://updated.com/chapter/{id}', 'scrapingType' => 'html', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); $this->assertJsonContains([ 'detail' => 'ContentSource with id 999999 not found', ]); } public function testItUpdatesSourceSuccessfully(): void { $updatedData = [ 'baseUrl' => 'https://updated-mangadex.org', 'chapterUrlFormat' => 'https://updated-mangadex.org/chapter/{id}', 'scrapingType' => 'javascript', 'imageSelector' => '.updated-image img', 'nextPageSelector' => '.updated-next', 'chapterSelector' => '.updated-chapter a', ]; $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => $updatedData, ]); $this->assertResponseIsSuccessful(); $this->assertResponseStatusCodeSame(Response::HTTP_OK); // L'endpoint peut retourner un entier (ID) au lieu d'un objet JSON $responseContent = $response->getContent(); if (is_numeric($responseContent)) { $this->assertIsNumeric($responseContent); return; } $data = $response->toArray(); $this->assertEquals($this->sourceId, $data['id']); $this->assertEquals($updatedData['baseUrl'], $data['baseUrl']); $this->assertEquals($updatedData['chapterUrlFormat'], $data['chapterUrlFormat']); $this->assertEquals($updatedData['scrapingType'], $data['scrapingType']); $this->assertEquals($updatedData['imageSelector'], $data['imageSelector']); $this->assertEquals($updatedData['nextPageSelector'], $data['nextPageSelector']); $this->assertEquals($updatedData['chapterSelector'], $data['chapterSelector']); // Vérifier que la source a été mise à jour en base $source = $this->entityManager->find(ContentSource::class, $this->sourceId); $this->assertEquals($updatedData['baseUrl'], $source->getBaseUrl()); $this->assertEquals($updatedData['scrapingType'], $source->getScrapingType()); } public function testItValidatesRequiredFields(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => '', 'chapterUrlFormat' => '', 'scrapingType' => '', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); } public function testItValidatesBaseUrlFormat(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => 'invalid-url', 'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}', 'scrapingType' => 'html', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); } public function testItValidatesScrapingType(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => 'https://mangadex.org', 'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}', 'scrapingType' => 'invalid-type', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); } public function testItUpdatesOnlyProvidedFields(): void { $updatedData = [ 'baseUrl' => 'https://partially-updated.org', 'chapterUrlFormat' => 'https://partially-updated.org/chapter/{id}', 'scrapingType' => 'html', 'imageSelector' => '.updated-image img', 'nextPageSelector' => '.updated-next-page', 'chapterSelector' => '.updated-chapter-list a', ]; $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => $updatedData, ]); $this->assertResponseIsSuccessful(); // L'endpoint peut retourner un entier (ID) au lieu d'un objet JSON $responseContent = $response->getContent(); if (is_numeric($responseContent)) { $this->assertIsNumeric($responseContent); return; } $data = $response->toArray(); // Vérifier que les champs mis à jour ont changé $this->assertEquals($updatedData['baseUrl'], $data['baseUrl']); $this->assertEquals($updatedData['chapterUrlFormat'], $data['chapterUrlFormat']); $this->assertEquals($updatedData['imageSelector'], $data['imageSelector']); $this->assertEquals($updatedData['nextPageSelector'], $data['nextPageSelector']); $this->assertEquals($updatedData['chapterSelector'], $data['chapterSelector']); } public function testItValidatesIdFormat(): void { $response = static::createClient()->request('PUT', '/api/content-sources/invalid-id', [ 'json' => [ 'baseUrl' => 'https://test.com', 'chapterUrlFormat' => 'https://test.com/chapter/{id}', 'scrapingType' => 'html', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_NOT_FOUND); } public function testItValidatesRequestFormat(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'invalidField' => 'value', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); } public function testItAcceptsTestChapterNumberAsFloat(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => 'https://mangadex.org', 'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}', 'scrapingType' => 'html', 'testSlug' => 'one-piece', 'testChapterNumber' => 1.5, ], ]); $this->assertResponseIsSuccessful(); } public function testItAcceptsTestChapterNumberAsNull(): void { $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => 'https://mangadex.org', 'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}', 'scrapingType' => 'html', 'testChapterNumber' => null, ], ]); $this->assertResponseIsSuccessful(); } public function testItRejectsTestChapterNumberAsEmptyStringWith422(): void { // Cas réel du formulaire Vue : le champ vide envoie "" au lieu de null. // Doit retourner 422 (erreur de validation) et non 400 (données malformées). $response = static::createClient()->request('PUT', "/api/content-sources/{$this->sourceId}", [ 'json' => [ 'baseUrl' => 'https://mangadex.org', 'chapterUrlFormat' => 'https://mangadex.org/chapter/{id}', 'scrapingType' => 'html', 'testChapterNumber' => '', ], ]); $this->assertResponseStatusCodeSame(Response::HTTP_UNPROCESSABLE_ENTITY); } }