257 lines
8.2 KiB
PHP
257 lines
8.2 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit\Dashboard\Stats;
|
|
|
|
use App\Dashboard\Stats\ArticlesTrend;
|
|
use App\Dashboard\Stats\DailySeriesStat;
|
|
use App\Dashboard\Stats\Series;
|
|
use App\Dashboard\Stats\SeriesResult;
|
|
use App\Enums\PublishStatusEnum;
|
|
use App\Models\Article;
|
|
use App\Models\ArticlePublication;
|
|
use App\Models\PlatformChannel;
|
|
use App\Models\RouteArticle;
|
|
use App\Support\DateRange;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Tests\TestCase;
|
|
|
|
class ArticlesTrendTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
Carbon::setTestNow(Carbon::parse('2026-07-15 12:00:00'));
|
|
}
|
|
|
|
protected function tearDown(): void
|
|
{
|
|
Carbon::setTestNow();
|
|
|
|
parent::tearDown();
|
|
}
|
|
|
|
private function range(): DateRange
|
|
{
|
|
return new DateRange(
|
|
Carbon::parse('2026-07-01 00:00:00'),
|
|
Carbon::parse('2026-07-31 23:59:59'),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, Series>
|
|
*/
|
|
private function seriesByName(SeriesResult $result): array
|
|
{
|
|
$out = [];
|
|
|
|
foreach ($result->series as $one) {
|
|
$out[$one->name] = $one;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
public function test_it_counts_articles_fetched_per_day(): void
|
|
{
|
|
Article::factory()->count(2)->create([
|
|
'created_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-11 09:00:00'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$days = $result->labels;
|
|
$fetched = $this->seriesByName($result)['Fetched'];
|
|
|
|
$this->assertSame(2, $fetched->values[array_search('2026-07-10', $days, true)]);
|
|
$this->assertSame(1, $fetched->values[array_search('2026-07-11', $days, true)]);
|
|
}
|
|
|
|
public function test_it_zero_fills_days_with_no_articles(): void
|
|
{
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-12 09:00:00'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$days = $result->labels;
|
|
$fetched = $this->seriesByName($result)['Fetched'];
|
|
|
|
$this->assertSame(0, $fetched->values[array_search('2026-07-11', $days, true)]);
|
|
$this->assertSame(1, $fetched->values[array_search('2026-07-10', $days, true)]);
|
|
$this->assertSame(1, $fetched->values[array_search('2026-07-12', $days, true)]);
|
|
}
|
|
|
|
public function test_it_excludes_articles_outside_the_range(): void
|
|
{
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-01 00:00:00'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-31 23:59:59'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-06-30 23:59:59'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-08-01 00:00:00'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$fetched = $this->seriesByName($result)['Fetched'];
|
|
|
|
$this->assertSame(2, array_sum($fetched->values));
|
|
}
|
|
|
|
public function test_it_counts_publications_per_day_from_article_publications(): void
|
|
{
|
|
$article = Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-01-01 00:00:00'),
|
|
]);
|
|
|
|
ArticlePublication::factory()->create([
|
|
'article_id' => $article->id,
|
|
'published_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
ArticlePublication::factory()->count(2)->create([
|
|
'article_id' => $article->id,
|
|
'published_at' => Carbon::parse('2026-07-11 09:00:00'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$days = $result->labels;
|
|
$published = $this->seriesByName($result)['Published'];
|
|
|
|
$this->assertSame(1, $published->values[array_search('2026-07-10', $days, true)]);
|
|
$this->assertSame(2, $published->values[array_search('2026-07-11', $days, true)]);
|
|
}
|
|
|
|
public function test_it_does_not_source_the_published_series_from_route_article_publish_status(): void
|
|
{
|
|
$article = Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
|
|
RouteArticle::factory()->create([
|
|
'article_id' => $article->id,
|
|
'publish_status' => PublishStatusEnum::PUBLISHED,
|
|
'created_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$published = $this->seriesByName($result)['Published'];
|
|
|
|
$this->assertSame(0, array_sum($published->values));
|
|
}
|
|
|
|
public function test_it_counts_each_channel_publication_of_one_article_separately(): void
|
|
{
|
|
$article = Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-01-01 00:00:00'),
|
|
]);
|
|
|
|
$channels = PlatformChannel::factory()->count(3)->create();
|
|
|
|
foreach ($channels as $channel) {
|
|
ArticlePublication::factory()->create([
|
|
'article_id' => $article->id,
|
|
'platform_channel_id' => $channel->id,
|
|
'published_at' => Carbon::parse('2026-07-10 09:00:00'),
|
|
]);
|
|
}
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$published = $this->seriesByName($result)['Published'];
|
|
|
|
$this->assertSame(3, array_sum($published->values));
|
|
}
|
|
|
|
public function test_it_returns_both_series_over_one_shared_label_axis(): void
|
|
{
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$this->assertCount(count($this->range()->days()), $result->labels);
|
|
$this->assertCount(2, $result->series);
|
|
|
|
$names = array_map(fn ($series) => $series->name, $result->series);
|
|
$this->assertSame(['Fetched', 'Published'], $names);
|
|
|
|
foreach ($result->series as $series) {
|
|
$this->assertCount(count($result->labels), $series->values);
|
|
}
|
|
}
|
|
|
|
public function test_it_splits_days_at_midnight(): void
|
|
{
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-10 23:59:59'),
|
|
]);
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-07-11 00:00:01'),
|
|
]);
|
|
|
|
$publishedArticle = Article::factory()->create([
|
|
'created_at' => Carbon::parse('2026-01-01 00:00:00'),
|
|
]);
|
|
|
|
ArticlePublication::factory()->create([
|
|
'article_id' => $publishedArticle->id,
|
|
'published_at' => Carbon::parse('2026-07-10 23:59:59'),
|
|
]);
|
|
ArticlePublication::factory()->create([
|
|
'article_id' => $publishedArticle->id,
|
|
'published_at' => Carbon::parse('2026-07-11 00:00:01'),
|
|
]);
|
|
|
|
$result = (new ArticlesTrend)->for($this->range());
|
|
|
|
$days = $result->labels;
|
|
$fetched = $this->seriesByName($result)['Fetched'];
|
|
$published = $this->seriesByName($result)['Published'];
|
|
|
|
$this->assertSame(1, $fetched->values[array_search('2026-07-10', $days, true)]);
|
|
$this->assertSame(1, $fetched->values[array_search('2026-07-11', $days, true)]);
|
|
$this->assertSame(2, array_sum($fetched->values));
|
|
|
|
$this->assertSame(1, $published->values[array_search('2026-07-10', $days, true)]);
|
|
$this->assertSame(1, $published->values[array_search('2026-07-11', $days, true)]);
|
|
$this->assertSame(2, array_sum($published->values));
|
|
}
|
|
|
|
public function test_it_is_a_daily_series_stat_and_reports_too_wide_without_querying(): void
|
|
{
|
|
$stat = new ArticlesTrend;
|
|
|
|
$this->assertInstanceOf(DailySeriesStat::class, $stat);
|
|
|
|
Article::factory()->create([
|
|
'created_at' => Carbon::now(),
|
|
]);
|
|
|
|
$queries = 0;
|
|
DB::listen(function () use (&$queries) {
|
|
$queries++;
|
|
});
|
|
|
|
$result = $stat->for(DateRange::preset('all'));
|
|
|
|
$this->assertTrue($result->isTooWide());
|
|
$this->assertSame(0, $queries);
|
|
}
|
|
}
|