fedi-feed-router/backend/tests/Feature/Http/Controllers/Api/V1/DashboardControllerTest.php
2025-08-16 09:43:38 +02:00

233 lines
8.1 KiB
PHP

<?php
namespace Tests\Feature\Http\Controllers\Api\V1;
use Domains\Article\Models\Article;
use Domains\Article\Models\ArticlePublication;
use Domains\Feed\Models\Feed;
use Domains\Platform\Models\PlatformChannel;
use Domains\Feed\Models\Route;
use Domains\Article\Services\DashboardStatsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use Mockery;
class DashboardControllerTest extends TestCase
{
use RefreshDatabase;
protected function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
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',
],
'available_periods',
'current_period',
],
'message'
]);
}
public function test_stats_with_different_periods(): void
{
$periods = ['today', 'week', 'month', 'year', 'all'];
foreach ($periods as $period) {
$this
->getJson("/api/v1/dashboard/stats?period={$period}")
->assertStatus(200)
->assertJson([
'success' => true,
'data' => [
'current_period' => $period,
]
]);
}
}
public function test_stats_with_sample_data(): void
{
// Get initial counts
$initialArticles = Article::count();
$initialFeeds = Feed::count();
$initialChannels = PlatformChannel::count();
$initialRoutes = Route::count();
$initialPublications = ArticlePublication::count();
// Create test data
$feed = Feed::factory()->create(['is_active' => true]);
$channel = PlatformChannel::factory()->create(['is_active' => true]);
$route = Route::factory()->create(['is_active' => true]);
// Create articles
$articles = Article::factory()->count(3)->create(['feed_id' => $feed->id]);
// Publish one article
ArticlePublication::factory()->create([
'article_id' => $articles->first()->id,
'platform_channel_id' => $channel->id,
'published_at' => now()
]);
$response = $this->getJson('/api/v1/dashboard/stats?period=all');
$response->assertStatus(200)
->assertJson([
'success' => true,
'data' => [
'article_stats' => [
'articles_fetched' => $initialArticles + 3,
'articles_published' => $initialPublications + 1,
],
]
]);
// Just verify structure and that we have more items than we started with
$responseData = $response->json('data');
$this->assertGreaterThanOrEqual($initialFeeds + 1, $responseData['system_stats']['total_feeds']);
$this->assertGreaterThanOrEqual($initialChannels + 1, $responseData['system_stats']['total_platform_channels']);
$this->assertGreaterThanOrEqual($initialRoutes + 1, $responseData['system_stats']['total_routes']);
}
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,
],
]
]);
}
public function test_stats_handles_service_exception(): void
{
// Mock the DashboardStatsService to throw an exception
$mockService = Mockery::mock(DashboardStatsService::class);
$mockService->shouldReceive('getStats')
->andThrow(new \Exception('Database connection failed'));
$this->app->instance(DashboardStatsService::class, $mockService);
$response = $this->getJson('/api/v1/dashboard/stats');
$response->assertStatus(500)
->assertJson([
'success' => false,
'message' => 'Failed to fetch dashboard stats: Database connection failed'
]);
}
public function test_stats_handles_invalid_period_gracefully(): void
{
// The service should handle invalid periods, but let's test it
$response = $this->getJson('/api/v1/dashboard/stats?period=invalid_period');
// Should still return 200 as the service handles this gracefully
$response->assertStatus(200)
->assertJsonStructure([
'success',
'data' => [
'article_stats',
'system_stats',
'available_periods',
'current_period',
],
]);
}
public function test_stats_handles_system_stats_exception(): void
{
// Mock the DashboardStatsService with partial failure
$mockService = Mockery::mock(DashboardStatsService::class);
$mockService->shouldReceive('getStats')
->andReturn([
'articles_fetched' => 10,
'articles_published' => 5,
'published_percentage' => 50.0,
]);
$mockService->shouldReceive('getSystemStats')
->andThrow(new \Exception('Failed to fetch system stats'));
$this->app->instance(DashboardStatsService::class, $mockService);
$response = $this->getJson('/api/v1/dashboard/stats');
$response->assertStatus(500)
->assertJson([
'success' => false,
'message' => 'Failed to fetch dashboard stats: Failed to fetch system stats'
]);
}
public function test_stats_handles_available_periods_exception(): void
{
// Mock the DashboardStatsService with partial failure
$mockService = Mockery::mock(DashboardStatsService::class);
$mockService->shouldReceive('getStats')
->andReturn([
'articles_fetched' => 10,
'articles_published' => 5,
'published_percentage' => 50.0,
]);
$mockService->shouldReceive('getSystemStats')
->andReturn([
'total_feeds' => 5,
'active_feeds' => 3,
'total_platform_channels' => 10,
'active_platform_channels' => 8,
'total_routes' => 15,
'active_routes' => 12,
]);
$mockService->shouldReceive('getAvailablePeriods')
->andThrow(new \Exception('Failed to get available periods'));
$this->app->instance(DashboardStatsService::class, $mockService);
$response = $this->getJson('/api/v1/dashboard/stats');
$response->assertStatus(500)
->assertJson([
'success' => false,
'message' => 'Failed to fetch dashboard stats: Failed to get available periods'
]);
}
}