scraperFactory = new InMemoryScraperFactory(); $this->imageDownloader = new InMemoryImageDownloader(); $this->imageStorage = new InMemoryImageStorage(); $this->jobRepository = new InMemoryJobRepository(); $this->chapterRepository = new InMemoryChapterRepository(); $this->mangaRepository = new InMemoryMangaRepository(); $this->sourceRepository = new InMemorySourceRepository(); $this->eventBus = new InMemoryEventBus(); $this->entityManager = $this->createMock(EntityManagerInterface::class); $this->entityManager->method('beginTransaction')->willReturn(null); $this->entityManager->method('commit')->willReturn(null); $this->entityManager->method('rollback')->willReturn(null); $this->chapterRepository->save(new Chapter( id: '1', mangaId: 'test-manga', chapterNumber: 2, volumeNumber: 1, )); $this->handler = new ScrapeChapterHandler( $this->scraperFactory, $this->imageDownloader, $this->imageStorage, $this->jobRepository, $this->chapterRepository, $this->mangaRepository, $this->sourceRepository, $this->eventBus, $this->entityManager ); } public function testHandleSuccessfully(): void { $command = new ScrapeChapter( chapterId: '1' ); $this->handler->handle($command); $job = $this->jobRepository->findByType('scraping_job'); $this->assertCount(1, $job); $job = array_values($job)[0]; $dispatchedMessages = $this->eventBus->getDispatchedMessages(); $this->assertCount(1, $dispatchedMessages); $this->assertInstanceOf(ChapterScraped::class, $dispatchedMessages[0]); $this->assertEquals($job->id, $dispatchedMessages[0]->getJobId()); $this->assertEquals('1', $dispatchedMessages[0]->chapterId); $this->assertEquals('/fake/pages/1', $dispatchedMessages[0]->pagesDirectory); $this->assertNotNull($this->imageStorage->stored['1'] ?? null); } protected function tearDown(): void { $this->jobRepository->clear(); $this->chapterRepository->clear(); $this->mangaRepository->clear(); $this->sourceRepository->clear(); } }