2025-08-03 20:59:09 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
namespace Tests\Feature\Http\Controllers\Api\V1;
|
|
|
|
|
|
2025-08-15 16:39:18 +02:00
|
|
|
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;
|
2025-08-16 09:00:46 +02:00
|
|
|
use Domains\Article\Services\DashboardStatsService;
|
2025-08-03 20:59:09 +02:00
|
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
|
|
|
use Tests\TestCase;
|
2025-08-16 09:00:46 +02:00
|
|
|
use Mockery;
|
2025-08-03 20:59:09 +02:00
|
|
|
|
|
|
|
|
class DashboardControllerTest extends TestCase
|
|
|
|
|
{
|
|
|
|
|
use RefreshDatabase;
|
|
|
|
|
|
2025-08-16 09:00:46 +02:00
|
|
|
protected function tearDown(): void
|
|
|
|
|
{
|
|
|
|
|
Mockery::close();
|
|
|
|
|
parent::tearDown();
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-03 20:59:09 +02:00
|
|
|
public function test_stats_returns_successful_response(): void
|
|
|
|
|
{
|
2025-08-06 21:49:13 +02:00
|
|
|
$this
|
|
|
|
|
->getJson('/api/v1/dashboard/stats')
|
|
|
|
|
->assertStatus(200)
|
2025-08-03 20:59:09 +02:00
|
|
|
->assertJsonStructure([
|
|
|
|
|
'success',
|
|
|
|
|
'data' => [
|
|
|
|
|
'article_stats' => [
|
|
|
|
|
'articles_fetched',
|
|
|
|
|
'articles_published',
|
|
|
|
|
'published_percentage',
|
|
|
|
|
],
|
|
|
|
|
'system_stats' => [
|
|
|
|
|
'total_feeds',
|
|
|
|
|
'active_feeds',
|
2025-08-10 01:26:56 +02:00
|
|
|
'total_platform_channels',
|
|
|
|
|
'active_platform_channels',
|
2025-08-03 20:59:09 +02:00
|
|
|
'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) {
|
2025-08-06 21:49:13 +02:00
|
|
|
$this
|
|
|
|
|
->getJson("/api/v1/dashboard/stats?period={$period}")
|
|
|
|
|
->assertStatus(200)
|
2025-08-03 20:59:09 +02:00
|
|
|
->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();
|
2025-08-06 21:49:13 +02:00
|
|
|
|
2025-08-03 20:59:09 +02:00
|
|
|
// Create test data
|
|
|
|
|
$feed = Feed::factory()->create(['is_active' => true]);
|
|
|
|
|
$channel = PlatformChannel::factory()->create(['is_active' => true]);
|
|
|
|
|
$route = Route::factory()->create(['is_active' => true]);
|
2025-08-06 21:49:13 +02:00
|
|
|
|
2025-08-03 20:59:09 +02:00
|
|
|
// Create articles
|
|
|
|
|
$articles = Article::factory()->count(3)->create(['feed_id' => $feed->id]);
|
2025-08-06 21:49:13 +02:00
|
|
|
|
2025-08-03 20:59:09 +02:00
|
|
|
// 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,
|
|
|
|
|
],
|
|
|
|
|
]
|
|
|
|
|
]);
|
2025-08-06 21:49:13 +02:00
|
|
|
|
2025-08-03 20:59:09 +02:00
|
|
|
// 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']);
|
2025-08-10 01:26:56 +02:00
|
|
|
$this->assertGreaterThanOrEqual($initialChannels + 1, $responseData['system_stats']['total_platform_channels']);
|
2025-08-03 20:59:09 +02:00
|
|
|
$this->assertGreaterThanOrEqual($initialRoutes + 1, $responseData['system_stats']['total_routes']);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function test_stats_returns_empty_data_with_no_records(): void
|
|
|
|
|
{
|
2025-08-06 21:49:13 +02:00
|
|
|
$this
|
|
|
|
|
->getJson('/api/v1/dashboard/stats')
|
|
|
|
|
->assertStatus(200)
|
2025-08-03 20:59:09 +02:00
|
|
|
->assertJson([
|
|
|
|
|
'success' => true,
|
|
|
|
|
'data' => [
|
|
|
|
|
'article_stats' => [
|
|
|
|
|
'articles_fetched' => 0,
|
|
|
|
|
'articles_published' => 0,
|
|
|
|
|
'published_percentage' => 0.0,
|
|
|
|
|
],
|
|
|
|
|
'system_stats' => [
|
|
|
|
|
'total_feeds' => 0,
|
|
|
|
|
'active_feeds' => 0,
|
2025-08-10 01:26:56 +02:00
|
|
|
'total_platform_accounts' => 0,
|
|
|
|
|
'active_platform_accounts' => 0,
|
|
|
|
|
'total_platform_channels' => 0,
|
|
|
|
|
'active_platform_channels' => 0,
|
2025-08-03 20:59:09 +02:00
|
|
|
'total_routes' => 0,
|
|
|
|
|
'active_routes' => 0,
|
|
|
|
|
],
|
|
|
|
|
]
|
|
|
|
|
]);
|
|
|
|
|
}
|
2025-08-16 09:00:46 +02:00
|
|
|
|
|
|
|
|
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'
|
|
|
|
|
]);
|
|
|
|
|
}
|
2025-08-06 21:49:13 +02:00
|
|
|
}
|