fedi-feed-router/tests/Feature/Http/Controllers/Api/V1/DashboardControllerTest.php

164 lines
5.5 KiB
PHP

<?php
namespace Tests\Feature\Http\Controllers\Api\V1;
use App\Models\Article;
use App\Models\ArticlePublication;
use App\Models\Feed;
use App\Models\PlatformChannel;
use App\Models\Route;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Carbon;
use Tests\TestCase;
class DashboardControllerTest extends TestCase
{
use RefreshDatabase;
public function test_stats_returns_successful_response(): void
{
$this
->getJson('/api/v1/dashboard/stats')
->assertStatus(200)
->assertJsonStructure([
'success',
'data' => [
'article_stats' => [
'articles_fetched',
'articles_published',
'published_percentage',
],
'system_stats' => [
'total_feeds',
'active_feeds',
'total_platform_channels',
'active_platform_channels',
'total_routes',
'active_routes',
],
'range' => ['from', 'to'],
],
'message',
]);
}
public function test_stats_no_longer_exposes_named_periods(): void
{
$this
->getJson('/api/v1/dashboard/stats')
->assertStatus(200)
->assertJsonMissingPath('data.available_periods')
->assertJsonMissingPath('data.current_period');
}
public function test_stats_honours_an_explicit_from_and_to_range(): void
{
Article::factory()->count(2)->create(['created_at' => Carbon::parse('2026-07-10 12:00:00')]);
Article::factory()->create(['created_at' => Carbon::parse('2026-08-05 12:00:00')]);
$this
->getJson('/api/v1/dashboard/stats?from=2026-07-01&to=2026-07-31')
->assertStatus(200)
->assertJson([
'data' => [
'article_stats' => ['articles_fetched' => 2],
'range' => ['from' => '2026-07-01', 'to' => '2026-07-31'],
],
]);
}
public function test_stats_defaults_to_the_current_day_without_params(): void
{
Carbon::setTestNow('2026-07-15 13:45:00');
Article::factory()->create(['created_at' => Carbon::parse('2026-07-15 09:00:00')]);
Article::factory()->create(['created_at' => Carbon::parse('2026-07-14 09:00:00')]);
$this
->getJson('/api/v1/dashboard/stats')
->assertStatus(200)
->assertJson([
'data' => [
'article_stats' => ['articles_fetched' => 1],
'range' => ['from' => '2026-07-15', 'to' => '2026-07-15'],
],
]);
}
public function test_stats_rejects_an_inverted_range(): void
{
$this
->getJson('/api/v1/dashboard/stats?from=2026-07-31&to=2026-07-01')
->assertStatus(422);
}
public function test_stats_rejects_a_malformed_date(): void
{
$this
->getJson('/api/v1/dashboard/stats?from=not-a-date&to=2026-07-01')
->assertStatus(422);
}
public function test_stats_with_sample_data(): void
{
$feed = Feed::factory()->create(['is_active' => true]);
$channel = PlatformChannel::factory()->create(['is_active' => true]);
Route::factory()->create(['is_active' => true]);
$articles = Article::factory()->count(3)->create([
'feed_id' => $feed->id,
'created_at' => Carbon::parse('2026-07-10 12:00:00'),
]);
ArticlePublication::factory()->create([
'article_id' => $articles->first()->id,
'platform_channel_id' => $channel->id,
'published_at' => Carbon::parse('2026-07-10 13:00:00'),
]);
$response = $this->getJson('/api/v1/dashboard/stats?from=2026-07-01&to=2026-07-31');
$response->assertStatus(200)
->assertJson([
'success' => true,
'data' => [
'article_stats' => [
'articles_fetched' => 3,
'articles_published' => 1,
],
'system_stats' => [
'total_feeds' => Feed::count(),
'total_platform_channels' => PlatformChannel::count(),
'total_routes' => Route::count(),
],
],
]);
}
public function test_stats_returns_empty_data_with_no_records(): void
{
$this
->getJson('/api/v1/dashboard/stats')
->assertStatus(200)
->assertJson([
'success' => true,
'data' => [
'article_stats' => [
'articles_fetched' => 0,
'articles_published' => 0,
'published_percentage' => 0.0,
],
'system_stats' => [
'total_feeds' => 0,
'active_feeds' => 0,
'total_platform_accounts' => 0,
'active_platform_accounts' => 0,
'total_platform_channels' => 0,
'active_platform_channels' => 0,
'total_routes' => 0,
'active_routes' => 0,
],
],
]);
}
}