-
Notifications
You must be signed in to change notification settings - Fork 0
Feature: Add Tests for Scrape Action #177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
a52e2db
Add tests for Scrape Action
128na 3d23b19
[rector] Rector fixes
actions-user 7c5b019
Refactor ScrapeActionTest to assert side-effects (Http requests) inst…
128na 13206cd
Resolve conflicts and update tests with side-effect assertions
128na cc764db
[rector] Rector fixes
actions-user 313b04f
Fix URL matching in ScrapeActionTest to pass CI (re-apply fix)
128na 1c8767a
[rector] Rector fixes
actions-user c548812
Mock PortalHandler in tests to avoid QueryException on unmigrated por…
128na fc82354
[rector] Rector fixes
actions-user e8cad84
[rector] Rector fixes
actions-user File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Tests\Feature\Actions\Scrape; | ||
|
|
||
| use App\Actions\Scrape\FetchHtml; | ||
| use App\Enums\Encoding; | ||
| use Illuminate\Support\Facades\Cache; | ||
| use Illuminate\Support\Facades\Http; | ||
| use Symfony\Component\DomCrawler\Crawler; | ||
| use Tests\Feature\TestCase; | ||
|
|
||
| final class FetchHtmlTest extends TestCase | ||
| { | ||
| public function test_invokes_http_and_returns_crawler(): void | ||
| { | ||
| $url = 'https://example.com/test'; | ||
| $htmlContent = '<html><body><h1>Test Content</h1><script>alert(1);</script></body></html>'; | ||
|
|
||
| Http::fake([ | ||
| $url => Http::response($htmlContent, 200), | ||
| ]); | ||
|
|
||
| $fetchHtml = new FetchHtml( | ||
| retryTimes: 1, | ||
| sleepMilliseconds: 10, | ||
| useCache: false | ||
| ); | ||
|
|
||
| $crawler = $fetchHtml($url, Encoding::UTF_8); | ||
|
|
||
| $this->assertInstanceOf(Crawler::class, $crawler); | ||
| $this->assertStringContainsString('Test Content', $crawler->html()); | ||
|
|
||
| Http::assertSentCount(1); | ||
| } | ||
|
|
||
| public function test_uses_cache_when_enabled(): void | ||
| { | ||
| $url = 'https://example.com/cached'; | ||
| $cachedHtml = '<html><body>Cached Content</body></html>'; | ||
|
|
||
| Cache::put('url:'.$url, $cachedHtml); | ||
|
|
||
| Http::fake(); | ||
|
|
||
| $fetchHtml = new FetchHtml( | ||
| retryTimes: 1, | ||
| sleepMilliseconds: 10, | ||
| useCache: true | ||
| ); | ||
|
|
||
| $crawler = $fetchHtml($url, Encoding::UTF_8); | ||
|
|
||
| $this->assertInstanceOf(Crawler::class, $crawler); | ||
| $this->assertStringContainsString('Cached Content', $crawler->html()); | ||
|
|
||
| Http::assertNothingSent(); | ||
| } | ||
|
|
||
| public function test_converts_encoding(): void | ||
| { | ||
| $url = 'https://example.com/euc-jp'; | ||
| // HTML content encoded in EUC-JP | ||
| $eucJpHtml = mb_convert_encoding('<html><body>日本語</body></html>', 'EUC-JP', 'UTF-8'); | ||
|
|
||
| Http::fake([ | ||
| $url => Http::response($eucJpHtml, 200), | ||
| ]); | ||
|
|
||
| $fetchHtml = new FetchHtml( | ||
| retryTimes: 1, | ||
| sleepMilliseconds: 10, | ||
| useCache: false | ||
| ); | ||
|
|
||
| $crawler = $fetchHtml($url, Encoding::EUC_JP); | ||
|
|
||
| $this->assertInstanceOf(Crawler::class, $crawler); | ||
| // After conversion, it should be readable as UTF-8 | ||
| $this->assertStringContainsString('日本語', $crawler->html()); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Tests\Feature\Actions\Scrape; | ||
|
|
||
| use App\Actions\Scrape\HandlerInterface; | ||
| use App\Actions\Scrape\Portal\Handler; | ||
| use App\Actions\Scrape\ScrapeAction; | ||
| use App\Enums\SiteName; | ||
| use Illuminate\Foundation\Testing\RefreshDatabase; | ||
| use Illuminate\Support\Facades\Http; | ||
| use Psr\Log\LoggerInterface; | ||
| use Psr\Log\NullLogger; | ||
| use Tests\Feature\TestCase; | ||
|
|
||
| final class ScrapeActionTest extends TestCase | ||
| { | ||
| use RefreshDatabase; | ||
|
|
||
| public function test_invokes_handlers_for_all_sites_when_null_provided(): void | ||
| { | ||
| Http::fake([ | ||
| '*' => Http::response('<html><body></body></html>', 200), | ||
| ]); | ||
|
|
||
| // Mock PortalHandler to avoid database queries in CI where the portal connection is unmigrated | ||
| $this->app->bind(Handler::class, fn (): HandlerInterface => new class implements HandlerInterface | ||
| { | ||
| public function __invoke(LoggerInterface $logger): void {} | ||
| }); | ||
|
|
||
| $scrapeAction = app(ScrapeAction::class); | ||
| $scrapeAction(null, new NullLogger); | ||
|
|
||
| // Verify JapanHandler was invoked by checking its specific HTTP request | ||
| Http::assertSent(fn ($request): bool => str_contains((string) $request->url(), 'japanese.simutrans.com')); | ||
| // Verify TwitransHandler was invoked | ||
| Http::assertSent(fn ($request): bool => str_contains((string) $request->url(), 'wikiwiki.jp/twitrans')); | ||
| } | ||
|
|
||
| public function test_invokes_specific_handler_when_site_provided(): void | ||
| { | ||
| Http::fake([ | ||
| '*' => Http::response('<html><body></body></html>', 200), | ||
| ]); | ||
|
|
||
| $scrapeAction = app(ScrapeAction::class); | ||
| $scrapeAction(SiteName::Japan, new NullLogger); | ||
|
|
||
| Http::assertSent(fn ($request): bool => str_contains((string) $request->url(), 'japanese.simutrans.com')); | ||
| Http::assertNotSent(fn ($request): bool => str_contains((string) $request->url(), 'wikiwiki.jp/twitrans')); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current tests use a dummy assertion (
$this->assertTrue(true)) and only verify that no exceptions are thrown. This is an assertionless test pattern that does not actually verify the behavior ofScrapeAction(i.e., that it resolves the correct handlers fromHandlerFactoryand executes them).\n\nBy mockingHandlerFactoryandHandlerInterface, we can assert that:\n1. The factory is called with the expected site names.\n2. The resolved handlers are actually invoked.\n\nThis also eliminates the need forHttp::fake()in this test, making it a true unit/feature test forScrapeActionin isolation.