180 lines
6 KiB
PHP
180 lines
6 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_rejects_a_from_without_a_to(): void
|
|
{
|
|
$this
|
|
->getJson('/api/v1/dashboard/stats?from=2026-07-01')
|
|
->assertStatus(422)
|
|
->assertJsonValidationErrors('to');
|
|
}
|
|
|
|
public function test_stats_rejects_a_to_without_a_from(): void
|
|
{
|
|
$this
|
|
->getJson('/api/v1/dashboard/stats?to=2026-07-31')
|
|
->assertStatus(422)
|
|
->assertJsonValidationErrors('from');
|
|
}
|
|
|
|
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,
|
|
],
|
|
],
|
|
]);
|
|
}
|
|
}
|