Fix failing tests

This commit is contained in:
myrmidex 2025-08-14 22:01:15 +02:00
parent 7d4aa3da83
commit 65cb836b51
7 changed files with 85 additions and 345 deletions

View file

@ -1,177 +0,0 @@
<?php
namespace Tests\Feature;
use App\Events\ArticleReadyToPublish;
use App\Jobs\PublishToLemmyJob;
use App\Listeners\PublishArticle;
use App\Models\Article;
use App\Models\ArticlePublication;
use App\Models\Feed;
use App\Services\Publishing\ArticlePublishingService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Queue;
use Tests\TestCase;
class ArticlePublishingTest extends TestCase
{
use RefreshDatabase;
public function test_publish_article_listener_queues_publish_job(): void
{
Queue::fake();
$feed = Feed::factory()->create();
$article = Article::factory()->create([
'feed_id' => $feed->id,
'url' => 'https://example.com/article',
'approval_status' => 'approved',
]);
$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',
'approval_status' => 'approved',
]);
// 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',
'approval_status' => 'approved',
]);
$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',
'approval_status' => 'approved',
]);
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',
'approval_status' => 'approved',
]);
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',
'approval_status' => 'approved',
]);
$article2 = Article::factory()->create([
'feed_id' => $feed->id,
'url' => 'https://example.com/article2',
'approval_status' => 'approved',
]);
$listener = new PublishArticle();
$listener->handle(new ArticleReadyToPublish($article1));
$listener->handle(new ArticleReadyToPublish($article2));
Queue::assertPushed(PublishToLemmyJob::class, 2);
}
}

View file

@ -11,6 +11,13 @@ class LogsControllerTest extends TestCase
{ {
use RefreshDatabase; use RefreshDatabase;
protected function setUp(): void
{
parent::setUp();
// Clear any logs that may have been created during application startup
Log::query()->delete();
}
public function test_index_returns_successful_response(): void public function test_index_returns_successful_response(): void
{ {
Log::factory()->count(5)->create(); Log::factory()->count(5)->create();

View file

@ -285,11 +285,18 @@ public function test_create_channel_validates_required_fields()
public function test_create_channel_creates_channel_successfully() public function test_create_channel_creates_channel_successfully()
{ {
$platformInstance = PlatformInstance::factory()->create(); $platformInstance = PlatformInstance::factory()->create();
$language = Language::factory()->create();
// Create a platform account for this instance first
PlatformAccount::factory()->create([
'instance_url' => $platformInstance->url,
'is_active' => true
]);
$channelData = [ $channelData = [
'name' => 'test_community', 'name' => 'test_community',
'platform_instance_id' => $platformInstance->id, 'platform_instance_id' => $platformInstance->id,
'language_id' => 1, 'language_id' => $language->id,
'description' => 'Test community description', 'description' => 'Test community description',
]; ];
@ -310,7 +317,7 @@ public function test_create_channel_creates_channel_successfully()
'name' => 'test_community', 'name' => 'test_community',
'channel_id' => 'test_community', 'channel_id' => 'test_community',
'platform_instance_id' => $platformInstance->id, 'platform_instance_id' => $platformInstance->id,
'language_id' => 1, 'language_id' => $language->id,
'is_active' => true, 'is_active' => true,
]); ]);
} }

View file

@ -2,6 +2,7 @@
namespace Tests\Feature\Http\Controllers\Api\V1; namespace Tests\Feature\Http\Controllers\Api\V1;
use App\Models\PlatformAccount;
use App\Models\PlatformChannel; use App\Models\PlatformChannel;
use App\Models\PlatformInstance; use App\Models\PlatformInstance;
use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\RefreshDatabase;
@ -47,6 +48,12 @@ public function test_store_creates_platform_channel_successfully(): void
{ {
$instance = PlatformInstance::factory()->create(); $instance = PlatformInstance::factory()->create();
// Create a platform account for this instance first
PlatformAccount::factory()->create([
'instance_url' => $instance->url,
'is_active' => true
]);
$data = [ $data = [
'platform_instance_id' => $instance->id, 'platform_instance_id' => $instance->id,
'channel_id' => 'test_channel', 'channel_id' => 'test_channel',
@ -76,7 +83,7 @@ public function test_store_creates_platform_channel_successfully(): void
]) ])
->assertJson([ ->assertJson([
'success' => true, 'success' => true,
'message' => 'Platform channel created successfully!' 'message' => 'Platform channel created successfully and linked to platform account!'
]); ]);
$this->assertDatabaseHas('platform_channels', [ $this->assertDatabaseHas('platform_channels', [

View file

@ -3,17 +3,17 @@
namespace Tests\Feature; namespace Tests\Feature;
use App\Events\ArticleApproved; use App\Events\ArticleApproved;
use App\Events\ArticleReadyToPublish; // use App\Events\ArticleReadyToPublish; // Class no longer exists
use App\Events\ExceptionLogged; use App\Events\ExceptionLogged;
use App\Events\ExceptionOccurred; use App\Events\ExceptionOccurred;
use App\Events\NewArticleFetched; use App\Events\NewArticleFetched;
use App\Jobs\ArticleDiscoveryForFeedJob; use App\Jobs\ArticleDiscoveryForFeedJob;
use App\Jobs\ArticleDiscoveryJob; use App\Jobs\ArticleDiscoveryJob;
use App\Jobs\PublishToLemmyJob; use App\Jobs\PublishNextArticleJob;
use App\Jobs\SyncChannelPostsJob; use App\Jobs\SyncChannelPostsJob;
use App\Listeners\LogExceptionToDatabase; use App\Listeners\LogExceptionToDatabase;
use App\Listeners\PublishApprovedArticle; // use App\Listeners\PublishApprovedArticle; // Class no longer exists
use App\Listeners\PublishArticle; // use App\Listeners\PublishArticle; // Class no longer exists
use App\Listeners\ValidateArticleListener; use App\Listeners\ValidateArticleListener;
use App\Models\Article; use App\Models\Article;
use App\Models\Feed; use App\Models\Feed;
@ -83,14 +83,12 @@ public function test_sync_channel_posts_job_processes_successfully(): void
} }
public function test_publish_to_lemmy_job_has_correct_configuration(): void public function test_publish_next_article_job_has_correct_configuration(): void
{ {
$article = Article::factory()->create(); $job = new PublishNextArticleJob();
$job = new PublishToLemmyJob($article); $this->assertEquals('publishing', $job->queue);
$this->assertInstanceOf(PublishNextArticleJob::class, $job);
$this->assertEquals('lemmy-posts', $job->queue);
$this->assertInstanceOf(PublishToLemmyJob::class, $job);
} }
public function test_new_article_fetched_event_is_dispatched(): void public function test_new_article_fetched_event_is_dispatched(): void
@ -120,18 +118,19 @@ public function test_article_approved_event_is_dispatched(): void
}); });
} }
public function test_article_ready_to_publish_event_is_dispatched(): void // Test removed - ArticleReadyToPublish class no longer exists
{ // public function test_article_ready_to_publish_event_is_dispatched(): void
Event::fake(); // {
// Event::fake();
$article = Article::factory()->create(); // $article = Article::factory()->create();
event(new ArticleReadyToPublish($article)); // event(new ArticleReadyToPublish($article));
Event::assertDispatched(ArticleReadyToPublish::class, function (ArticleReadyToPublish $event) use ($article) { // Event::assertDispatched(ArticleReadyToPublish::class, function (ArticleReadyToPublish $event) use ($article) {
return $event->article->id === $article->id; // return $event->article->id === $article->id;
}); // });
} // }
public function test_exception_occurred_event_is_dispatched(): void public function test_exception_occurred_event_is_dispatched(): void
{ {
@ -192,38 +191,40 @@ public function test_validate_article_listener_processes_new_article(): void
$this->assertContains($article->approval_status, ['approved', 'rejected']); $this->assertContains($article->approval_status, ['approved', 'rejected']);
} }
public function test_publish_approved_article_listener_queues_job(): void // Test removed - PublishApprovedArticle and ArticleReadyToPublish classes no longer exist
{ // public function test_publish_approved_article_listener_queues_job(): void
Event::fake(); // {
// Event::fake();
$article = Article::factory()->create([ // $article = Article::factory()->create([
'approval_status' => 'approved', // 'approval_status' => 'approved',
'approval_status' => 'approved', // 'approval_status' => 'approved',
]); // ]);
$listener = new PublishApprovedArticle(); // $listener = new PublishApprovedArticle();
$event = new ArticleApproved($article); // $event = new ArticleApproved($article);
$listener->handle($event); // $listener->handle($event);
Event::assertDispatched(ArticleReadyToPublish::class); // Event::assertDispatched(ArticleReadyToPublish::class);
} // }
public function test_publish_article_listener_queues_publish_job(): void // Test removed - PublishArticle and ArticleReadyToPublish classes no longer exist
{ // public function test_publish_article_listener_queues_publish_job(): void
Queue::fake(); // {
// Queue::fake();
$article = Article::factory()->create([ // $article = Article::factory()->create([
'approval_status' => 'approved', // 'approval_status' => 'approved',
]); // ]);
$listener = new PublishArticle(); // $listener = new PublishArticle();
$event = new ArticleReadyToPublish($article); // $event = new ArticleReadyToPublish($article);
$listener->handle($event); // $listener->handle($event);
Queue::assertPushed(PublishToLemmyJob::class); // Queue::assertPushed(PublishNextArticleJob::class);
} // }
public function test_log_exception_to_database_listener_creates_log(): void public function test_log_exception_to_database_listener_creates_log(): void
{ {
@ -255,11 +256,13 @@ public function test_event_listener_registration_works(): void
$listeners = Event::getListeners(NewArticleFetched::class); $listeners = Event::getListeners(NewArticleFetched::class);
$this->assertNotEmpty($listeners); $this->assertNotEmpty($listeners);
$listeners = Event::getListeners(ArticleApproved::class); // ArticleApproved event exists but has no listeners after publishing redesign
$this->assertNotEmpty($listeners); // $listeners = Event::getListeners(ArticleApproved::class);
// $this->assertNotEmpty($listeners);
$listeners = Event::getListeners(ArticleReadyToPublish::class); // ArticleReadyToPublish no longer exists - removed this check
$this->assertNotEmpty($listeners); // $listeners = Event::getListeners(ArticleReadyToPublish::class);
// $this->assertNotEmpty($listeners);
$listeners = Event::getListeners(ExceptionOccurred::class); $listeners = Event::getListeners(ExceptionOccurred::class);
$this->assertNotEmpty($listeners); $this->assertNotEmpty($listeners);
@ -267,13 +270,11 @@ public function test_event_listener_registration_works(): void
public function test_job_retry_configuration(): void public function test_job_retry_configuration(): void
{ {
$article = Article::factory()->create(); $job = new PublishNextArticleJob();
$job = new PublishToLemmyJob($article); // Test that job has unique configuration
$this->assertObjectHasProperty('uniqueFor', $job);
// Test that job has retry configuration $this->assertEquals(300, $job->uniqueFor);
$this->assertObjectHasProperty('tries', $job);
$this->assertObjectHasProperty('backoff', $job);
} }
public function test_job_queue_configuration(): void public function test_job_queue_configuration(): void
@ -284,13 +285,13 @@ public function test_job_queue_configuration(): void
$discoveryJob = new ArticleDiscoveryJob(); $discoveryJob = new ArticleDiscoveryJob();
$feedJob = new ArticleDiscoveryForFeedJob($feed); $feedJob = new ArticleDiscoveryForFeedJob($feed);
$publishJob = new PublishToLemmyJob($article); $publishJob = new PublishNextArticleJob();
$syncJob = new SyncChannelPostsJob($channel); $syncJob = new SyncChannelPostsJob($channel);
// Test queue assignments // Test queue assignments
$this->assertEquals('feed-discovery', $discoveryJob->queue ?? 'default'); $this->assertEquals('feed-discovery', $discoveryJob->queue ?? 'default');
$this->assertEquals('feed-discovery', $feedJob->queue ?? 'discovery'); $this->assertEquals('feed-discovery', $feedJob->queue ?? 'discovery');
$this->assertEquals('lemmy-posts', $publishJob->queue); $this->assertEquals('publishing', $publishJob->queue);
$this->assertEquals('sync', $syncJob->queue ?? 'sync'); $this->assertEquals('sync', $syncJob->queue ?? 'sync');
} }

View file

@ -1,109 +0,0 @@
<?php
namespace Tests\Unit\Jobs;
use App\Exceptions\PublishException;
use App\Jobs\PublishToLemmyJob;
use App\Models\Article;
use App\Models\Feed;
use App\Services\Article\ArticleFetcher;
use App\Services\Publishing\ArticlePublishingService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Mockery;
use Tests\TestCase;
class PublishToLemmyJobTest extends TestCase
{
use RefreshDatabase;
public function test_constructor_sets_correct_queue_and_properties(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
// Act
$job = new PublishToLemmyJob($article);
// Assert
$this->assertEquals('lemmy-posts', $job->queue);
$this->assertEquals(3, $job->tries);
$this->assertEquals([60, 120, 300], $job->backoff);
}
public function test_job_implements_should_queue(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert
$this->assertInstanceOf(\Illuminate\Contracts\Queue\ShouldQueue::class, $job);
}
public function test_job_uses_queueable_trait(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert
$this->assertTrue(method_exists($job, 'onQueue'));
$this->assertTrue(method_exists($job, 'onConnection'));
$this->assertTrue(method_exists($job, 'delay'));
$this->assertTrue(method_exists($job, 'fail'));
}
public function test_handle_method_exists(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert
$this->assertTrue(method_exists($job, 'handle'));
}
public function test_job_calls_article_fetcher_and_publishing_service(): void
{
// This is a structural test - we can't easily mock static methods
// But we can verify the job has the correct structure
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert - Job should have handle method that uses the required services
$this->assertTrue(method_exists($job, 'handle'));
$this->assertIsObject($job);
// We can't easily test the actual execution due to static method calls
// but we can verify the job structure is correct
$this->assertTrue(true);
}
public function test_job_properties_are_correct_type(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert
$this->assertIsInt($job->tries);
$this->assertIsArray($job->backoff);
$this->assertGreaterThan(0, $job->tries);
$this->assertNotEmpty($job->backoff);
}
public function test_job_backoff_increases_progressively(): void
{
// Arrange
$article = new Article(['title' => 'Test Article']);
$job = new PublishToLemmyJob($article);
// Assert - Backoff should increase with each attempt
$backoff = $job->backoff;
$this->assertCount(3, $backoff); // Should match tries
$this->assertLessThan($backoff[1], $backoff[0]); // Second attempt waits longer than first
$this->assertLessThan($backoff[2], $backoff[1]); // Third attempt waits longer than second
}
}

View file

@ -308,15 +308,19 @@ public function test_publish_to_channel_handles_string_channel_id(): void
->once() ->once()
->andReturn('token'); ->andReturn('token');
// Mock LemmyApiService - should receive integer conversion of channel_id // Mock LemmyApiService - should call getCommunityId for non-numeric channel_id
$apiMock = Mockery::mock(LemmyApiService::class); $apiMock = Mockery::mock(LemmyApiService::class);
$apiMock->shouldReceive('getCommunityId')
->once()
->with('string-42', 'token')
->andReturn(42);
$apiMock->shouldReceive('createPost') $apiMock->shouldReceive('createPost')
->once() ->once()
->with( ->with(
'token', 'token',
'Test Title', 'Test Title',
'', '',
0, // 'string-42' converts to 0 42, // resolved community ID
'https://example.com/article', 'https://example.com/article',
null, null,
null null