211 lines
6.8 KiB
PHP
211 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Services;
|
|
|
|
use App\Models\Article;
|
|
use App\Models\Feed;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Collection;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Mockery;
|
|
use Tests\TestCase;
|
|
use Tests\Traits\CreatesArticleFetcher;
|
|
|
|
class ArticleFetcherRssTest extends TestCase
|
|
{
|
|
use CreatesArticleFetcher, RefreshDatabase;
|
|
|
|
private string $sampleRss;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->sampleRss = <<<'XML'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<rss version="2.0">
|
|
<channel>
|
|
<title>The Guardian - International</title>
|
|
<link>https://www.theguardian.com/international</link>
|
|
<item>
|
|
<title>First Article Title</title>
|
|
<link>https://www.theguardian.com/world/2026/mar/08/first-article</link>
|
|
<description>First article description</description>
|
|
<pubDate>Sun, 08 Mar 2026 12:00:00 GMT</pubDate>
|
|
</item>
|
|
<item>
|
|
<title>Second Article Title</title>
|
|
<link>https://www.theguardian.com/world/2026/mar/08/second-article</link>
|
|
<description>Second article description</description>
|
|
<pubDate>Sun, 08 Mar 2026 11:00:00 GMT</pubDate>
|
|
</item>
|
|
</channel>
|
|
</rss>
|
|
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(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(Collection::class, $result);
|
|
$this->assertEmpty($result);
|
|
}
|
|
|
|
public function test_get_articles_from_rss_feed_handles_empty_channel(): void
|
|
{
|
|
Http::fake([
|
|
'*' => Http::response('<?xml version="1.0"?><rss><channel><title>Empty</title></channel></rss>', 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);
|
|
}
|
|
|
|
public function test_get_articles_from_belga_rss_feed_creates_articles(): void
|
|
{
|
|
$belgaRss = <<<'XML'
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<rss version="2.0">
|
|
<channel>
|
|
<title>Belga News Agency</title>
|
|
<link>https://www.belganewsagency.eu</link>
|
|
<item>
|
|
<title>Belgium announces new climate plan</title>
|
|
<link>https://www.belganewsagency.eu/belgium-announces-new-climate-plan</link>
|
|
<description>Belgium has unveiled a comprehensive climate strategy.</description>
|
|
<pubDate>Sun, 08 Mar 2026 10:00:00 GMT</pubDate>
|
|
</item>
|
|
<item>
|
|
<title>EU summit concludes in Brussels</title>
|
|
<link>https://www.belganewsagency.eu/eu-summit-concludes-in-brussels</link>
|
|
<description>European leaders reached agreement on key issues.</description>
|
|
<pubDate>Sun, 08 Mar 2026 09:00:00 GMT</pubDate>
|
|
</item>
|
|
</channel>
|
|
</rss>
|
|
XML;
|
|
|
|
Http::fake(['*' => Http::response($belgaRss, 200)]);
|
|
|
|
$feed = Feed::factory()->create([
|
|
'type' => 'rss',
|
|
'provider' => 'belga',
|
|
'url' => 'https://www.belganewsagency.eu/feed',
|
|
]);
|
|
|
|
$fetcher = $this->createArticleFetcher();
|
|
$result = $fetcher->getArticlesFromFeed($feed);
|
|
|
|
$this->assertCount(2, $result);
|
|
$this->assertDatabaseHas('articles', [
|
|
'url' => 'https://www.belganewsagency.eu/belgium-announces-new-climate-plan',
|
|
'feed_id' => $feed->id,
|
|
]);
|
|
$this->assertDatabaseHas('articles', [
|
|
'url' => 'https://www.belganewsagency.eu/eu-summit-concludes-in-brussels',
|
|
'feed_id' => $feed->id,
|
|
]);
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Mockery::close();
|
|
parent::tearDown();
|
|
}
|
|
}
|