144 lines
4.4 KiB
PHP
144 lines
4.4 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Feature\Jobs;
|
||
|
|
|
||
|
|
use App\Enums\NotificationSeverityEnum;
|
||
|
|
use App\Enums\NotificationTypeEnum;
|
||
|
|
use App\Jobs\ArticleDiscoveryForFeedJob;
|
||
|
|
use App\Models\Article;
|
||
|
|
use App\Models\Feed;
|
||
|
|
use App\Models\Notification;
|
||
|
|
use App\Services\Article\ArticleFetcher;
|
||
|
|
use App\Services\Log\LogSaver;
|
||
|
|
use App\Services\Notification\NotificationService;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Illuminate\Support\Collection;
|
||
|
|
use Mockery;
|
||
|
|
use Tests\TestCase;
|
||
|
|
|
||
|
|
class ArticleDiscoveryForFeedJobEmptyFetchTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Collection<int, Article>|null $articles
|
||
|
|
*/
|
||
|
|
private function runJobForFeed(Feed $feed, ?Collection $articles = null): void
|
||
|
|
{
|
||
|
|
$fetcher = Mockery::mock(ArticleFetcher::class);
|
||
|
|
$fetcher->shouldReceive('getArticlesFromFeed')
|
||
|
|
->andReturn($articles ?? collect());
|
||
|
|
|
||
|
|
(new ArticleDiscoveryForFeedJob($feed))->handle(
|
||
|
|
app(LogSaver::class),
|
||
|
|
$fetcher,
|
||
|
|
app(NotificationService::class)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_empty_fetch_creates_notification(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create(['is_active' => true]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed);
|
||
|
|
|
||
|
|
$this->assertDatabaseHas('notifications', [
|
||
|
|
'type' => NotificationTypeEnum::FEED_EMPTY->value,
|
||
|
|
'severity' => NotificationSeverityEnum::WARNING->value,
|
||
|
|
'notifiable_type' => $feed->getMorphClass(),
|
||
|
|
'notifiable_id' => $feed->id,
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_fetch_with_articles_does_not_create_notification(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create(['is_active' => true]);
|
||
|
|
$articles = Article::factory()->count(2)->create(['feed_id' => $feed->id]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed, $articles);
|
||
|
|
|
||
|
|
$this->assertDatabaseCount('notifications', 0);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_notification_message_names_the_feed_url(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create([
|
||
|
|
'is_active' => true,
|
||
|
|
'name' => 'Belga',
|
||
|
|
'url' => 'https://example.test/retired-feed.xml',
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed);
|
||
|
|
|
||
|
|
$notification = Notification::first();
|
||
|
|
|
||
|
|
$this->assertStringContainsString('Belga', $notification->title);
|
||
|
|
$this->assertStringContainsString('https://example.test/retired-feed.xml', $notification->message);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_empty_fetch_still_updates_last_fetched_at(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create(['is_active' => true, 'last_fetched_at' => null]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed);
|
||
|
|
|
||
|
|
$this->assertNotNull($feed->fresh()->last_fetched_at);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_does_not_create_duplicate_notification_when_unread_exists(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create(['is_active' => true]);
|
||
|
|
|
||
|
|
Notification::factory()
|
||
|
|
->type(NotificationTypeEnum::FEED_EMPTY)
|
||
|
|
->unread()
|
||
|
|
->create([
|
||
|
|
'notifiable_type' => $feed->getMorphClass(),
|
||
|
|
'notifiable_id' => $feed->id,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed);
|
||
|
|
|
||
|
|
$this->assertDatabaseCount('notifications', 1);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_creates_new_notification_when_previous_is_read(): void
|
||
|
|
{
|
||
|
|
$feed = Feed::factory()->create(['is_active' => true]);
|
||
|
|
|
||
|
|
Notification::factory()
|
||
|
|
->type(NotificationTypeEnum::FEED_EMPTY)
|
||
|
|
->read()
|
||
|
|
->create([
|
||
|
|
'notifiable_type' => $feed->getMorphClass(),
|
||
|
|
'notifiable_id' => $feed->id,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($feed);
|
||
|
|
|
||
|
|
$this->assertDatabaseCount('notifications', 2);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_notification_for_one_feed_does_not_suppress_another(): void
|
||
|
|
{
|
||
|
|
$notified = Feed::factory()->create(['is_active' => true]);
|
||
|
|
$other = Feed::factory()->create(['is_active' => true]);
|
||
|
|
|
||
|
|
Notification::factory()
|
||
|
|
->type(NotificationTypeEnum::FEED_EMPTY)
|
||
|
|
->unread()
|
||
|
|
->create([
|
||
|
|
'notifiable_type' => $notified->getMorphClass(),
|
||
|
|
'notifiable_id' => $notified->id,
|
||
|
|
]);
|
||
|
|
|
||
|
|
$this->runJobForFeed($other);
|
||
|
|
|
||
|
|
$this->assertDatabaseHas('notifications', [
|
||
|
|
'type' => NotificationTypeEnum::FEED_EMPTY->value,
|
||
|
|
'notifiable_id' => $other->id,
|
||
|
|
]);
|
||
|
|
$this->assertDatabaseCount('notifications', 2);
|
||
|
|
}
|
||
|
|
}
|