create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', 'validated_at' => now(), 'is_valid' => true, ]); $listener = new PublishArticle(); $event = new ArticleReadyToPublish($article); $listener->handle($event); Queue::assertPushed(PublishToLemmyJob::class); } public function test_publish_article_listener_skips_already_published_articles(): void { Queue::fake(); $feed = Feed::factory()->create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', 'validated_at' => now(), 'is_valid' => true, ]); // Create existing publication ArticlePublication::create([ 'article_id' => $article->id, 'post_id' => 'existing-post-id', 'platform_channel_id' => 1, 'published_at' => now(), 'published_by' => 'test-user', ]); $listener = new PublishArticle(); $event = new ArticleReadyToPublish($article); $listener->handle($event); Queue::assertNotPushed(PublishToLemmyJob::class); } public function test_publish_to_lemmy_job_calls_publishing_service(): void { $feed = Feed::factory()->create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', 'validated_at' => now(), 'is_valid' => true, ]); $job = new PublishToLemmyJob($article); $this->assertEquals('lemmy-posts', $job->queue); $this->assertInstanceOf(PublishToLemmyJob::class, $job); } public function test_article_ready_to_publish_event_integration(): void { Queue::fake(); Event::fake(); $feed = Feed::factory()->create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', 'validated_at' => now(), 'is_valid' => true, ]); event(new ArticleReadyToPublish($article)); Event::assertDispatched(ArticleReadyToPublish::class, function (ArticleReadyToPublish $event) use ($article) { return $event->article->id === $article->id; }); } public function test_publishing_prevents_duplicate_publications(): void { $feed = Feed::factory()->create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', 'validated_at' => now(), 'is_valid' => true, ]); ArticlePublication::create([ 'article_id' => $article->id, 'post_id' => 'first-post-id', 'platform_channel_id' => 1, 'published_at' => now(), 'published_by' => 'test-user', ]); $this->mock(ArticlePublishingService::class, function ($mock) { $mock->shouldNotReceive('publishToRoutedChannels'); }); $listener = new PublishArticle(); $event = new ArticleReadyToPublish($article); $listener->handle($event); $this->assertEquals(1, ArticlePublication::where('article_id', $article->id)->count()); } public function test_publish_article_listener_has_correct_queue_configuration(): void { $listener = new PublishArticle(); $this->assertEquals('lemmy-publish', $listener->queue); $this->assertEquals(300, $listener->delay); $this->assertEquals(3, $listener->tries); $this->assertEquals(300, $listener->backoff); } public function test_publish_to_lemmy_job_has_correct_queue_configuration(): void { $feed = Feed::factory()->create(); $article = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article', ]); $job = new PublishToLemmyJob($article); $this->assertEquals('lemmy-posts', $job->queue); } public function test_multiple_articles_can_be_queued_independently(): void { Queue::fake(); $feed = Feed::factory()->create(); $article1 = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article1', 'validated_at' => now(), 'is_valid' => true, ]); $article2 = Article::factory()->create([ 'feed_id' => $feed->id, 'url' => 'https://example.com/article2', 'validated_at' => now(), 'is_valid' => true, ]); $listener = new PublishArticle(); $listener->handle(new ArticleReadyToPublish($article1)); $listener->handle(new ArticleReadyToPublish($article2)); Queue::assertPushed(PublishToLemmyJob::class, 2); } }