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' ]); } }