composer screenshots runs Pest browser tests in tests/Screenshots, outside every test suite: fixed demo data under a frozen clock, desktop (MacBook 14, 2x) and phone (iPhone 15 Pro, 3x) in light and dark, each capture published at once as WebP at two widths into website/img/screenshots. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy
90 lines
4.3 KiB
PHP
90 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\Screenshots;
|
|
|
|
use App\Models\Share;
|
|
use App\Models\User;
|
|
use App\Services\ShareService;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* The shares and the admin every screenshot shows. Names, sizes, tokens, counts and dates are fixed
|
|
* (with the clock frozen by the caller), so a run only produces different images when the interface
|
|
* changed. Files go through ShareService, so they exist encrypted on the faked `shares` disk.
|
|
*/
|
|
final class DemoData
|
|
{
|
|
/** The share a customer receives: link, QR code and download page. */
|
|
public const DELIVERY_TOKEN = 'hG7kP2mXq9LrT4vB';
|
|
|
|
/** The password-protected share the phone's password prompt belongs to. */
|
|
public const PROTECTED_TOKEN = 'Wn3sD8fJ5cYa1ZeQ';
|
|
|
|
public const PROTECTED_PASSWORD = 'autumn-harbour-42';
|
|
|
|
public static function admin(): User
|
|
{
|
|
return User::factory()->admin()->create([
|
|
'name' => 'Alex Morgan',
|
|
'email' => 'alex.morgan@example.com',
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Eight shares of different ages, sizes and states: one expired, two password-protected, some
|
|
* with a download limit, some never expiring.
|
|
*/
|
|
public static function shares(): void
|
|
{
|
|
$shares = [
|
|
['token' => self::DELIVERY_TOKEN, 'daysAgo' => 0, 'expiresAfterDays' => 7, 'downloads' => 3, 'options' => [],
|
|
'files' => ['Q3 Report.pdf' => 2400, 'Contract 2026.pdf' => 380, 'Product photos/hero-shot.jpg' => 4800, 'Product photos/detail.jpg' => 3900]],
|
|
['token' => self::PROTECTED_TOKEN, 'daysAgo' => 1, 'expiresAfterDays' => 3, 'downloads' => 1, 'options' => ['password' => self::PROTECTED_PASSWORD, 'max_downloads' => 3],
|
|
'files' => ['Payroll September.xlsx' => 210, 'Tax statement 2025.pdf' => 640]],
|
|
['token' => 'Rt5uV6wX7yZ8aB9c', 'daysAgo' => 2, 'expiresAfterDays' => 30, 'downloads' => 7, 'options' => ['max_downloads' => 10],
|
|
'files' => ['Brand guidelines.pdf' => 8600]],
|
|
['token' => 'Kc2dE3fG4hJ5kL6m', 'daysAgo' => 5, 'expiresAfterDays' => 14, 'downloads' => 2, 'options' => [],
|
|
'files' => ['Site plan rev C.dwg' => 12400, 'Site plan rev C.pdf' => 3100]],
|
|
['token' => 'Np7qR8sT9uV1wX2y', 'daysAgo' => 9, 'expiresAfterDays' => null, 'downloads' => 0, 'options' => ['password' => 'demo-interview'],
|
|
'files' => ['Interview recording.m4a' => 18300]],
|
|
['token' => 'Zb4cD5eF6gH7jK8L', 'daysAgo' => 14, 'expiresAfterDays' => 30, 'downloads' => 0, 'options' => ['max_downloads' => 1],
|
|
'files' => ['Invoice 2026-0412.pdf' => 95]],
|
|
['token' => 'Mq1rS2tU3vW4xY5z', 'daysAgo' => 21, 'expiresAfterDays' => null, 'downloads' => 4, 'options' => [],
|
|
'files' => ['Onboarding/Welcome.pdf' => 520, 'Onboarding/Handbook.pdf' => 2900, 'Onboarding/IT checklist.docx' => 130]],
|
|
['token' => 'Ae6fG7hJ8kL9mN1p', 'daysAgo' => 40, 'expiresAfterDays' => 10, 'downloads' => 12, 'options' => [],
|
|
'files' => ['Event photos.zip' => 15700]],
|
|
];
|
|
|
|
foreach ($shares as $share) {
|
|
self::share(...$share);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array{password?: string, max_downloads?: int} $options
|
|
* @param array<string, int> $files relative path => size in kilobytes
|
|
*/
|
|
private static function share(string $token, int $daysAgo, ?int $expiresAfterDays, int $downloads, array $options, array $files): void
|
|
{
|
|
$createdAt = Carbon::now()->subDays($daysAgo)->subHours(2);
|
|
|
|
Str::createRandomStringsUsing(fn (): string => $token);
|
|
|
|
try {
|
|
$share = app(ShareService::class)->createShare(
|
|
collect($files)->map(fn (int $kilobytes, string $path): array => [
|
|
'file' => UploadedFile::fake()->create(basename($path), $kilobytes),
|
|
'relativePath' => str_contains($path, '/') ? $path : null,
|
|
])->values()->all(),
|
|
[...$options, 'expires_at' => $expiresAfterDays === null ? null : $createdAt->copy()->addDays($expiresAfterDays)],
|
|
);
|
|
} finally {
|
|
Str::createRandomStringsNormally();
|
|
}
|
|
|
|
$share->forceFill(['download_count' => $downloads, 'created_at' => $createdAt, 'updated_at' => $createdAt])->save();
|
|
}
|
|
}
|