sampleRss = <<<'XML'
The Guardian - International
https://www.theguardian.com/international
-
First Article Title
https://www.theguardian.com/world/2026/mar/08/first-article
First article description
Sun, 08 Mar 2026 12:00:00 GMT
-
Second Article Title
https://www.theguardian.com/world/2026/mar/08/second-article
Second article description
Sun, 08 Mar 2026 11:00:00 GMT
XML;
}
public function test_get_articles_from_rss_feed_returns_collection(): void
{
Http::fake(['*' => Http::response($this->sampleRss, 200)]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertInstanceOf(\Illuminate\Support\Collection::class, $result);
}
public function test_get_articles_from_rss_feed_creates_articles(): void
{
Http::fake(['*' => Http::response($this->sampleRss, 200)]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertCount(2, $result);
$this->assertDatabaseHas('articles', [
'url' => 'https://www.theguardian.com/world/2026/mar/08/first-article',
'feed_id' => $feed->id,
]);
$this->assertDatabaseHas('articles', [
'url' => 'https://www.theguardian.com/world/2026/mar/08/second-article',
'feed_id' => $feed->id,
]);
}
public function test_get_articles_from_rss_feed_does_not_duplicate_existing(): void
{
Http::fake(['*' => Http::response($this->sampleRss, 200)]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
Article::factory()->create([
'url' => 'https://www.theguardian.com/world/2026/mar/08/first-article',
'feed_id' => $feed->id,
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertCount(2, $result);
$this->assertEquals(1, Article::where('url', 'https://www.theguardian.com/world/2026/mar/08/first-article')->count());
}
public function test_get_articles_from_rss_feed_handles_invalid_xml(): void
{
Http::fake(['*' => Http::response('this is not xml', 200)]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertInstanceOf(\Illuminate\Support\Collection::class, $result);
$this->assertEmpty($result);
}
public function test_get_articles_from_rss_feed_handles_empty_channel(): void
{
Http::fake([
'*' => Http::response('Empty', 200),
]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertEmpty($result);
}
public function test_get_articles_from_rss_feed_handles_http_failure(): void
{
Http::fake(['*' => Http::response('Server Error', 500)]);
$feed = Feed::factory()->create([
'type' => 'rss',
'provider' => 'guardian',
'url' => 'https://www.theguardian.com/international/rss',
]);
$fetcher = $this->createArticleFetcher();
$result = $fetcher->getArticlesFromFeed($feed);
$this->assertEmpty($result);
}
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
}