sourceRepo = new InMemoryContentSourceForHealthCheckRepository(); $this->healthRepo = new InMemoryContentSourceHealthRepository(); $this->scraperFactory = new InMemoryScraperFactory(); $this->scraperFactory->addScraper('html', new InMemoryScraperAdapter()); $testScraperHandler = new TestScraperConfigurationHandler($this->scraperFactory); $this->handler = new CheckAllScrapersHealthHandler( $this->sourceRepo, $this->healthRepo, $testScraperHandler, new NullLogger(), ); } public function testSourceWithoutTestSlugIsSkipped(): void { $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 1, baseUrl: 'https://example.com', chapterUrlFormat: 'https://example.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: null, testChapterNumber: null, )); $this->handler->handle(new CheckAllScrapersHealth()); $this->assertNull($this->healthRepo->getStatus(1)); } public function testSourceWithTestSlugIsMarkedAsHealthyOnSuccess(): void { $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 2, baseUrl: 'https://example.com', chapterUrlFormat: 'https://example.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: 'one-piece', testChapterNumber: 1.0, )); $this->handler->handle(new CheckAllScrapersHealth()); $this->assertSame('ok', $this->healthRepo->getStatus(2)); $this->assertNull($this->healthRepo->getError(2)); } public function testSourceIsMarkedAsUnhealthyWhenScraperThrows(): void { $failingScraper = new InMemoryScraperAdapter(); $failingScraper->simulateError(new \RuntimeException('Connexion refusée')); $this->scraperFactory->addScraper('html', $failingScraper); $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 3, baseUrl: 'https://example.com', chapterUrlFormat: 'https://example.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: 'one-piece', testChapterNumber: 1.0, )); $this->handler->handle(new CheckAllScrapersHealth()); $this->assertSame('ko', $this->healthRepo->getStatus(3)); $this->assertNotNull($this->healthRepo->getError(3)); } public function testMultipleSourcesAreAllProcessed(): void { $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 10, baseUrl: 'https://siteA.com', chapterUrlFormat: 'https://siteA.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: 'manga-a', testChapterNumber: 1.0, )); $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 11, baseUrl: 'https://siteB.com', chapterUrlFormat: 'https://siteB.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: null, testChapterNumber: null, )); $this->sourceRepo->add(new ContentSourceHealthCheckData( id: 12, baseUrl: 'https://siteC.com', chapterUrlFormat: 'https://siteC.com/{slug}/{chapterNumber}', scrapingType: 'html', imageSelector: 'img', nextPageSelector: null, chapterSelector: null, testSlug: 'manga-c', testChapterNumber: 3.0, )); $this->handler->handle(new CheckAllScrapersHealth()); $this->assertSame('ok', $this->healthRepo->getStatus(10)); $this->assertNull($this->healthRepo->getStatus(11)); // skippée $this->assertSame('ok', $this->healthRepo->getStatus(12)); } protected function tearDown(): void { $this->sourceRepo->clear(); $this->healthRepo->clear(); $this->scraperFactory->clear(); } }