diff --git a/backend/tests/Feature/Http/Controllers/Api/V1/OnboardingControllerTest.php b/backend/tests/Feature/Http/Controllers/Api/V1/OnboardingControllerTest.php index 7c6ebee..994b509 100644 --- a/backend/tests/Feature/Http/Controllers/Api/V1/OnboardingControllerTest.php +++ b/backend/tests/Feature/Http/Controllers/Api/V1/OnboardingControllerTest.php @@ -325,7 +325,7 @@ public function test_create_route_validates_required_fields() public function test_create_route_creates_route_successfully() { - $language = Language::first() ?? Language::factory()->create(); + $language = Language::first(); $feed = Feed::factory()->language($language)->create(); $platformChannel = PlatformChannel::factory()->create(); diff --git a/backend/tests/Unit/Modules/Lemmy/Services/LemmyApiServiceTest.php b/backend/tests/Unit/Modules/Lemmy/Services/LemmyApiServiceTest.php index 33debfa..784b633 100644 --- a/backend/tests/Unit/Modules/Lemmy/Services/LemmyApiServiceTest.php +++ b/backend/tests/Unit/Modules/Lemmy/Services/LemmyApiServiceTest.php @@ -3,10 +3,8 @@ namespace Tests\Unit\Modules\Lemmy\Services; use App\Modules\Lemmy\Services\LemmyApiService; -use App\Modules\Lemmy\LemmyRequest; use App\Models\PlatformChannelPost; use App\Enums\PlatformEnum; -use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Log; use Tests\TestCase; @@ -23,11 +21,11 @@ protected function tearDown(): void public function test_constructor_sets_instance(): void { $service = new LemmyApiService('lemmy.world'); - + $reflection = new \ReflectionClass($service); $property = $reflection->getProperty('instance'); $property->setAccessible(true); - + $this->assertEquals('lemmy.world', $property->getValue($service)); } @@ -119,13 +117,13 @@ public function test_login_handles_rate_limit_error(): void // Expecting 4 error logs: // 1. 'Lemmy login failed' for HTTPS attempt // 2. 'Lemmy login exception' for catching the rate limit exception on HTTPS - // 3. 'Lemmy login failed' for HTTP attempt + // 3. 'Lemmy login failed' for HTTP attempt // 4. 'Lemmy login exception' for catching the rate limit exception on HTTP Log::shouldReceive('error')->times(4); $service = new LemmyApiService('lemmy.world'); $result = $service->login('user', 'pass'); - + // Since the exception is caught and HTTP is tried, then that also fails, // the method returns null instead of throwing $this->assertNull($result); @@ -286,7 +284,7 @@ public function test_sync_channel_posts_handles_exception(): void $service = new LemmyApiService('lemmy.world'); $service->syncChannelPosts('token', 42, 'test-community'); - + // Assert that the method completes without throwing $this->assertTrue(true); } @@ -428,4 +426,4 @@ public function test_get_languages_returns_empty_when_all_languages_missing(): v $this->assertEquals([], $languages); } -} \ No newline at end of file +} diff --git a/backend/tests/Unit/Services/ArticleFetcherTest.php b/backend/tests/Unit/Services/ArticleFetcherTest.php index 42aa881..fd5998c 100644 --- a/backend/tests/Unit/Services/ArticleFetcherTest.php +++ b/backend/tests/Unit/Services/ArticleFetcherTest.php @@ -5,10 +5,6 @@ use App\Services\Article\ArticleFetcher; use App\Models\Feed; use App\Models\Article; -use App\Services\Http\HttpFetcher; -use App\Services\Factories\HomepageParserFactory; -use App\Services\Factories\ArticleParserFactory; -use App\Services\Log\LogSaver; use Tests\TestCase; use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Support\Facades\Http; @@ -21,10 +17,10 @@ class ArticleFetcherTest extends TestCase protected function setUp(): void { parent::setUp(); - + // Mock all HTTP requests by default to prevent external calls Http::fake([ - '*' => Http::response('', 500) + '*' => Http::response('Mock HTML content', 200) ]); } @@ -36,7 +32,7 @@ public function test_get_articles_from_feed_returns_collection(): void ]); $result = ArticleFetcher::getArticlesFromFeed($feed); - + $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); } @@ -48,7 +44,7 @@ public function test_get_articles_from_rss_feed_returns_empty_collection(): void ]); $result = ArticleFetcher::getArticlesFromFeed($feed); - + // RSS parsing is not implemented yet, should return empty collection $this->assertEmpty($result); } @@ -61,7 +57,7 @@ public function test_get_articles_from_website_feed_handles_no_parser(): void ]); $result = ArticleFetcher::getArticlesFromFeed($feed); - + // Should return empty collection when no parser is available $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); $this->assertEmpty($result); @@ -75,7 +71,7 @@ public function test_get_articles_from_unsupported_feed_type(): void ]); $result = ArticleFetcher::getArticlesFromFeed($feed); - + $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); $this->assertEmpty($result); } @@ -87,7 +83,7 @@ public function test_fetch_article_data_returns_array(): void ]); $result = ArticleFetcher::fetchArticleData($article); - + $this->assertIsArray($result); // Will be empty array due to unsupported URL in test $this->assertEmpty($result); @@ -100,7 +96,7 @@ public function test_fetch_article_data_handles_invalid_url(): void ]); $result = ArticleFetcher::fetchArticleData($article); - + $this->assertIsArray($result); $this->assertEmpty($result); } @@ -112,7 +108,7 @@ public function test_get_articles_from_feed_with_null_feed_type(): void 'type' => 'website', 'url' => 'https://example.com/feed' ]); - + // Use reflection to set an invalid type that bypasses enum validation $reflection = new \ReflectionClass($feed); $property = $reflection->getProperty('attributes'); @@ -122,7 +118,7 @@ public function test_get_articles_from_feed_with_null_feed_type(): void $property->setValue($feed, $attributes); $result = ArticleFetcher::getArticlesFromFeed($feed); - + $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); $this->assertEmpty($result); } @@ -141,22 +137,22 @@ public function test_get_articles_from_website_feed_with_supported_parser(): voi // Test actual behavior - VRT parser should be available $result = ArticleFetcher::getArticlesFromFeed($feed); - + $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); // VRT parser will process the mocked HTML response } public function test_get_articles_from_website_feed_handles_invalid_url(): void { - // HTTP mock already set in setUp() to return 500 for all requests - + // HTTP mock already set in setUp() to return mock HTML for all requests + $feed = Feed::factory()->create([ 'type' => 'website', 'url' => 'https://invalid-domain-that-does-not-exist-12345.com/' ]); $result = ArticleFetcher::getArticlesFromFeed($feed); - + $this->assertInstanceOf(\Illuminate\Support\Collection::class, $result); $this->assertEmpty($result); } @@ -174,7 +170,7 @@ public function test_fetch_article_data_with_supported_parser(): void // Test actual behavior - VRT parser should be available $result = ArticleFetcher::fetchArticleData($article); - + $this->assertIsArray($result); // VRT parser will process the mocked HTML response } @@ -186,7 +182,7 @@ public function test_fetch_article_data_handles_unsupported_domain(): void ]); $result = ArticleFetcher::fetchArticleData($article); - + $this->assertIsArray($result); $this->assertEmpty($result); } @@ -195,17 +191,17 @@ public function test_save_article_creates_new_article_when_not_exists(): void { $feed = Feed::factory()->create(); $url = 'https://example.com/unique-article'; - + // Ensure article doesn't exist $this->assertDatabaseMissing('articles', ['url' => $url]); - + // Use reflection to access private method for testing $reflection = new \ReflectionClass(ArticleFetcher::class); $saveArticleMethod = $reflection->getMethod('saveArticle'); $saveArticleMethod->setAccessible(true); - + $article = $saveArticleMethod->invoke(null, $url, $feed->id); - + $this->assertInstanceOf(Article::class, $article); $this->assertEquals($url, $article->url); $this->assertEquals($feed->id, $article->feed_id); @@ -219,17 +215,17 @@ public function test_save_article_returns_existing_article_when_exists(): void 'url' => 'https://example.com/existing-article', 'feed_id' => $feed->id ]); - + // Use reflection to access private method for testing $reflection = new \ReflectionClass(ArticleFetcher::class); $saveArticleMethod = $reflection->getMethod('saveArticle'); $saveArticleMethod->setAccessible(true); - + $article = $saveArticleMethod->invoke(null, $existingArticle->url, $feed->id); - + $this->assertEquals($existingArticle->id, $article->id); $this->assertEquals($existingArticle->url, $article->url); - + // Ensure no duplicate was created $this->assertEquals(1, Article::where('url', $existingArticle->url)->count()); } @@ -237,14 +233,14 @@ public function test_save_article_returns_existing_article_when_exists(): void public function test_save_article_without_feed_id(): void { $url = 'https://example.com/article-without-feed'; - + // Use reflection to access private method for testing $reflection = new \ReflectionClass(ArticleFetcher::class); $saveArticleMethod = $reflection->getMethod('saveArticle'); $saveArticleMethod->setAccessible(true); - + $article = $saveArticleMethod->invoke(null, $url, null); - + $this->assertInstanceOf(Article::class, $article); $this->assertEquals($url, $article->url); $this->assertNull($article->feed_id); @@ -256,4 +252,4 @@ protected function tearDown(): void Mockery::close(); parent::tearDown(); } -} \ No newline at end of file +} diff --git a/backend/tests/Unit/Services/ValidationServiceTest.php b/backend/tests/Unit/Services/ValidationServiceTest.php index 4c4e71f..543b8c4 100644 --- a/backend/tests/Unit/Services/ValidationServiceTest.php +++ b/backend/tests/Unit/Services/ValidationServiceTest.php @@ -28,7 +28,7 @@ public function test_validate_returns_article_with_validation_status(): void ]); $result = ValidationService::validate($article); - + $this->assertInstanceOf(Article::class, $result); $this->assertContains($result->approval_status, ['pending', 'approved', 'rejected']); } @@ -48,7 +48,7 @@ public function test_validate_marks_article_invalid_when_missing_data(): void ]); $result = ValidationService::validate($article); - + $this->assertEquals('rejected', $result->approval_status); } @@ -67,7 +67,7 @@ public function test_validate_with_supported_article_content(): void ]); $result = ValidationService::validate($article); - + // Since we can't fetch real content in tests, it should be marked rejected $this->assertEquals('rejected', $result->approval_status); } @@ -87,9 +87,9 @@ public function test_validate_updates_article_in_database(): void ]); $originalId = $article->id; - + ValidationService::validate($article); - + // Check that the article was updated in the database $updatedArticle = Article::find($originalId); $this->assertContains($updatedArticle->approval_status, ['pending', 'approved', 'rejected']); @@ -110,9 +110,9 @@ public function test_validate_handles_article_with_existing_validation(): void ]); $originalApprovalStatus = $article->approval_status; - + $result = ValidationService::validate($article); - + // Should re-validate - status may change based on content validation $this->assertContains($result->approval_status, ['pending', 'approved', 'rejected']); } @@ -128,7 +128,7 @@ public function test_validate_keyword_checking_logic(): void ]); $feed = Feed::factory()->create(); - + // Create an article that would match the validation keywords if content was available $article = Article::factory()->create([ 'feed_id' => $feed->id, @@ -137,9 +137,9 @@ public function test_validate_keyword_checking_logic(): void ]); $result = ValidationService::validate($article); - + // The service looks for keywords in the full_article content // Since we can't fetch real content, it will be marked rejected $this->assertEquals('rejected', $result->approval_status); } -} \ No newline at end of file +}