Replaces every raw GuzzleHttp\Client usage (Nominatim, web.archive.org, webmention fetch/discover/send, Bridgy syndication, IndieAuth client_id lookup, contact avatar/h-card fetch, profile image download, and the CloudConvert screenshot pipeline) with Illuminate\Support\Facades\Http, and enables Http::preventStrayRequests() globally in tests so any un-faked outbound call now fails loudly instead of silently hitting the network. The CloudConvert retry-until-finished middleware in AppServiceProvider is replaced by a plain polling loop in SaveScreenshot, which also fixes a latent bug where the old middleware decoded a response object instead of its body. Bridgy syndication jobs keep their tries=1/no-retry semantics unchanged to avoid duplicate publishes. Guzzle's PSR-7 helpers (Header, UriResolver, Utils) stay in SendWebMentions since Http has no equivalent for them. Every affected test file's Guzzle MockHandler/HandlerStack boilerplate is replaced with Http::fake()/Http::sequence(). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P8j7cJhCiYDsGUgB7obKNQ
112 lines
4.7 KiB
PHP
112 lines
4.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Unit\Jobs;
|
|
|
|
use App\Jobs\SaveScreenshot;
|
|
use App\Models\Bookmark;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Http;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use PHPUnit\Framework\Attributes\Test;
|
|
use Tests\TestCase;
|
|
|
|
class SaveScreenshotJobTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
#[Test]
|
|
public function screenshot_is_saved_by_job(): void
|
|
{
|
|
Storage::fake('public');
|
|
|
|
Http::fake([
|
|
'api.cloudconvert.com/v2/capture-website' => Http::response([
|
|
'data' => ['id' => '68d52633-e170-465e-b13e-746c97d01ffb', 'status' => 'finished'],
|
|
], 201),
|
|
'api.cloudconvert.com/v2/tasks/68d52633-e170-465e-b13e-746c97d01ffb*' => Http::response([
|
|
'data' => ['id' => '68d52633-e170-465e-b13e-746c97d01ffb', 'status' => 'finished'],
|
|
], 200),
|
|
'api.cloudconvert.com/v2/export/url' => Http::response([
|
|
'data' => ['id' => '27f33137-cc03-4468-aba4-1e1aa8c096fb', 'status' => 'finished'],
|
|
], 201),
|
|
'api.cloudconvert.com/v2/tasks/27f33137-cc03-4468-aba4-1e1aa8c096fb*' => Http::response([
|
|
'data' => [
|
|
'id' => '27f33137-cc03-4468-aba4-1e1aa8c096fb',
|
|
'status' => 'finished',
|
|
'result' => [
|
|
'files' => [[
|
|
'url' => 'https://storage.cloudconvert.com/tasks/27f33137-cc03-4468-aba4-1e1aa8c096fb/theverge.com.png',
|
|
]],
|
|
],
|
|
],
|
|
], 200),
|
|
'storage.cloudconvert.com/*' => Http::response(
|
|
file_get_contents(__DIR__.'/../../theverge.com.png'),
|
|
200,
|
|
['Content-Type' => 'image/png']
|
|
),
|
|
]);
|
|
|
|
$bookmark = Bookmark::factory()->create();
|
|
$job = new SaveScreenshot($bookmark);
|
|
$job->handle();
|
|
$bookmark->refresh();
|
|
|
|
$this->assertEquals('68d52633-e170-465e-b13e-746c97d01ffb', $bookmark->screenshot);
|
|
Storage::disk('public')->assertExists('/assets/img/bookmarks/'.$bookmark->screenshot.'.png');
|
|
|
|
// capture-website, 1x poll (finished immediately), export/url, 1x poll (finished immediately), download
|
|
Http::assertSentCount(5);
|
|
}
|
|
|
|
#[Test]
|
|
public function screenshot_job_handles_unfinished_tasks(): void
|
|
{
|
|
Storage::fake('public');
|
|
|
|
Http::fake([
|
|
'api.cloudconvert.com/v2/capture-website' => Http::response([
|
|
'data' => ['id' => '68d52633-e170-465e-b13e-746c97d01ffb', 'status' => 'waiting'],
|
|
], 201),
|
|
'api.cloudconvert.com/v2/tasks/68d52633-e170-465e-b13e-746c97d01ffb*' => Http::sequence()
|
|
->push(['data' => ['id' => '68d52633-e170-465e-b13e-746c97d01ffb', 'status' => 'waiting']], 200)
|
|
->push(['data' => ['id' => '68d52633-e170-465e-b13e-746c97d01ffb', 'status' => 'finished']], 200),
|
|
'api.cloudconvert.com/v2/export/url' => Http::response([
|
|
'data' => ['id' => '27f33137-cc03-4468-aba4-1e1aa8c096fb', 'status' => 'waiting'],
|
|
], 201),
|
|
'api.cloudconvert.com/v2/tasks/27f33137-cc03-4468-aba4-1e1aa8c096fb*' => Http::sequence()
|
|
->push(['data' => ['id' => '27f33137-cc03-4468-aba4-1e1aa8c096fb', 'status' => 'waiting']], 200)
|
|
->push([
|
|
'data' => [
|
|
'id' => '27f33137-cc03-4468-aba4-1e1aa8c096fb',
|
|
'status' => 'finished',
|
|
'result' => [
|
|
'files' => [[
|
|
'url' => 'https://storage.cloudconvert.com/tasks/27f33137-cc03-4468-aba4-1e1aa8c096fb/theverge.com.png',
|
|
]],
|
|
],
|
|
],
|
|
], 200),
|
|
'storage.cloudconvert.com/*' => Http::response(
|
|
file_get_contents(__DIR__.'/../../theverge.com.png'),
|
|
200,
|
|
['Content-Type' => 'image/png']
|
|
),
|
|
]);
|
|
|
|
$bookmark = Bookmark::factory()->create();
|
|
$job = new SaveScreenshot($bookmark);
|
|
$job->handle();
|
|
$bookmark->refresh();
|
|
|
|
$this->assertEquals('68d52633-e170-465e-b13e-746c97d01ffb', $bookmark->screenshot);
|
|
Storage::disk('public')->assertExists('/assets/img/bookmarks/'.$bookmark->screenshot.'.png');
|
|
|
|
// capture-website, 2x poll (waiting then finished), export/url, 2x poll (waiting then finished), download
|
|
Http::assertSentCount(7);
|
|
// Also assert every queued response in each sequence was consumed, no more no less
|
|
Http::assertSequencesAreEmpty();
|
|
}
|
|
}
|