127 lines
3.9 KiB
PHP
127 lines
3.9 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Tests\Unit\Dashboard\Stats;
|
||
|
|
|
||
|
|
use App\Dashboard\Stats\Breakdown;
|
||
|
|
use App\Dashboard\Stats\PublicationsPerChannel;
|
||
|
|
use App\Models\ArticlePublication;
|
||
|
|
use App\Models\PlatformChannel;
|
||
|
|
use App\Support\DateRange;
|
||
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||
|
|
use Illuminate\Support\Carbon;
|
||
|
|
use Tests\TestCase;
|
||
|
|
|
||
|
|
class PublicationsPerChannelTest extends TestCase
|
||
|
|
{
|
||
|
|
use RefreshDatabase;
|
||
|
|
|
||
|
|
private function range(): DateRange
|
||
|
|
{
|
||
|
|
return new DateRange(
|
||
|
|
Carbon::parse('2026-07-01 00:00:00'),
|
||
|
|
Carbon::parse('2026-07-31 23:59:59'),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
private function publish(PlatformChannel $channel, string $at): void
|
||
|
|
{
|
||
|
|
ArticlePublication::factory()->create([
|
||
|
|
'platform_channel_id' => $channel->id,
|
||
|
|
'published_at' => Carbon::parse($at),
|
||
|
|
]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_counts_publications_per_channel(): void
|
||
|
|
{
|
||
|
|
$busy = PlatformChannel::factory()->create(['display_name' => 'Busy Channel']);
|
||
|
|
$quiet = PlatformChannel::factory()->create(['display_name' => 'Quiet Channel']);
|
||
|
|
|
||
|
|
$this->publish($busy, '2026-07-10 12:00:00');
|
||
|
|
$this->publish($busy, '2026-07-11 12:00:00');
|
||
|
|
$this->publish($quiet, '2026-07-12 12:00:00');
|
||
|
|
|
||
|
|
$rows = (new PublicationsPerChannel)->for($this->range())->rows;
|
||
|
|
|
||
|
|
$this->assertSame(2, $this->pluck($rows)['Busy Channel']);
|
||
|
|
$this->assertSame(1, $this->pluck($rows)['Quiet Channel']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_reports_zero_for_a_channel_with_no_publications(): void
|
||
|
|
{
|
||
|
|
PlatformChannel::factory()->create(['display_name' => 'Silent Channel']);
|
||
|
|
|
||
|
|
$rows = (new PublicationsPerChannel)->for($this->range())->rows;
|
||
|
|
|
||
|
|
$this->assertSame(['Silent Channel' => 0], $this->pluck($rows));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_excludes_publications_outside_the_range(): void
|
||
|
|
{
|
||
|
|
$channel = PlatformChannel::factory()->create(['display_name' => 'Channel']);
|
||
|
|
|
||
|
|
$this->publish($channel, '2026-06-30 23:59:59');
|
||
|
|
$this->publish($channel, '2026-08-01 00:00:00');
|
||
|
|
|
||
|
|
$rows = (new PublicationsPerChannel)->for($this->range())->rows;
|
||
|
|
|
||
|
|
$this->assertSame(0, $this->pluck($rows)['Channel']);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_breaks_ties_alphabetically(): void
|
||
|
|
{
|
||
|
|
foreach (['Zulu', 'Alpha'] as $name) {
|
||
|
|
$channel = PlatformChannel::factory()->create(['display_name' => $name]);
|
||
|
|
$this->publish($channel, '2026-07-10 12:00:00');
|
||
|
|
}
|
||
|
|
|
||
|
|
$labels = array_map(
|
||
|
|
fn (Breakdown $row): string => $row->label,
|
||
|
|
(new PublicationsPerChannel)->for($this->range())->rows,
|
||
|
|
);
|
||
|
|
|
||
|
|
$this->assertSame(['Alpha', 'Zulu'], array_slice($labels, 0, 2));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_labels_channels_by_display_name(): void
|
||
|
|
{
|
||
|
|
PlatformChannel::factory()->create(['name' => 'raw-name', 'display_name' => 'Friendly Name']);
|
||
|
|
|
||
|
|
$rows = (new PublicationsPerChannel)->for($this->range())->rows;
|
||
|
|
|
||
|
|
$this->assertArrayHasKey('Friendly Name', $this->pluck($rows));
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_reports_the_range_total(): void
|
||
|
|
{
|
||
|
|
$channel = PlatformChannel::factory()->create();
|
||
|
|
|
||
|
|
$this->publish($channel, '2026-07-10 12:00:00');
|
||
|
|
$this->publish($channel, '2026-07-11 12:00:00');
|
||
|
|
|
||
|
|
$this->assertSame(2, (new PublicationsPerChannel)->for($this->range())->total());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function test_it_exposes_a_stable_key_and_label(): void
|
||
|
|
{
|
||
|
|
$stat = new PublicationsPerChannel;
|
||
|
|
|
||
|
|
$this->assertSame('publications-per-channel', $stat->key());
|
||
|
|
$this->assertSame('Publications per Channel', $stat->label());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array<int, Breakdown> $rows
|
||
|
|
* @return array<string, int>
|
||
|
|
*/
|
||
|
|
private function pluck(array $rows): array
|
||
|
|
{
|
||
|
|
$out = [];
|
||
|
|
|
||
|
|
foreach ($rows as $row) {
|
||
|
|
$out[$row->label] = $row->count;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $out;
|
||
|
|
}
|
||
|
|
}
|