*/ 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); } }