Files
2026-10-09 08:21:06 +02:00

355 lines
13 KiB
PHP

<?php
use App\Models\User;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;
use Tests\UpdatesSettings;
use Tests\Visual\Gallery;
use Vanguard\Announcements\Database\Seeders\AnnouncementsDatabaseSeeder;
uses(UpdatesSettings::class);
/*
* Captures every page across three viewports, for whichever engine the run was
* started with. Nothing here diffs: these are for looking at. Each capture
* still asserts on content first, because a silent screenshot would happily
* photograph the blank page a broken route() leaves behind.
*/
dataset('viewports', Gallery::VIEWPORTS);
/*
* The default assertion timeout is tuned for Chromium. Firefox and WebKit are
* several times slower to settle here, and a tab transition that misses the
* window fails a capture that is otherwise fine.
*/
pest()->browser()->timeout(15_000);
beforeEach(function () {
// The session pages sit behind session.database, and the users row menu
// hides its first item without it. Set once here so every capture agrees.
config(['session.driver' => 'database']);
$this->artisan('db:seed');
$this->artisan('db:seed', ['--class' => AnnouncementsDatabaseSeeder::class]);
$this->setSettings([
'reg_enabled' => true,
'registration.captcha.enabled' => false,
'forgot_password' => true,
'tos' => true,
'2fa.enabled' => true,
]);
seedGalleryUsers();
});
afterAll(function () {
Gallery::collect();
});
/**
* A fixed cast, so tables and the dashboard look populated without the names,
* emails or dates changing between runs.
*/
function seedGalleryUsers(): void
{
$people = [
['Ada', 'Lovelace', 'ada@vanguard.test', 'ada'],
['Grace', 'Hopper', 'grace@vanguard.test', 'grace'],
['Alan', 'Turing', 'alan@vanguard.test', 'alan'],
['Katherine', 'Johnson', 'katherine@vanguard.test', 'katherine'],
];
foreach ($people as $index => [$first, $last, $email, $username]) {
User::factory()->create([
'first_name' => $first,
'last_name' => $last,
'email' => $email,
'username' => $username,
'phone' => '+1 555 0100',
'address' => '1 Analytical Engine Way',
'birthday' => '1950-01-01',
'password' => 'password',
'country_id' => null,
'created_at' => Carbon::parse('2026-01-0'.($index + 1).' 09:00:00'),
]);
}
}
it('captures the login page', function (string $device, string $viewport) {
visit('/login')->on()->{$device}()
->assertSee('Login')
->screenshot(true, Gallery::filename('login', $viewport));
})->with('viewports');
it('captures the registration page', function (string $device, string $viewport) {
visit('/register')->on()->{$device}()
->assertSee('Register')
->screenshot(true, Gallery::filename('register', $viewport));
})->with('viewports');
it('captures the forgot password page', function (string $device, string $viewport) {
visit('/password/reset')->on()->{$device}()
->assertSee('Forgot Your Password?')
->screenshot(true, Gallery::filename('password-forgot', $viewport));
})->with('viewports');
it('captures the reset password page', function (string $device, string $viewport) {
$token = Password::broker()->createToken(
User::where('username', 'ada')->firstOrFail()
);
visit("/password/reset/{$token}?email=ada@vanguard.test")->on()->{$device}()
->assertSee('Reset Your Password')
->screenshot(true, Gallery::filename('password-reset', $viewport));
})->with('viewports');
it('captures the terms of service dialog', function (string $device, string $viewport) {
visit('/register')->on()->{$device}()
->assertSee('I accept')
->click('Terms of Service')
->assertSee('Close')
->screenshot(true, Gallery::filename('dialog-terms', $viewport));
})->with('viewports');
it('captures registration validation errors', function (string $device, string $viewport) {
// A malformed address would be rejected by the browser's own type="email"
// check and never reach Laravel, so this submits a well formed one that is
// already taken.
visit('/register')->on()->{$device}()
->assertSee('Register')
->fill('#email', 'ada@vanguard.test')
->fill('#username', 'ada')
->click('button[type="submit"]')
->assertSee('The email has already been taken.')
->screenshot(true, Gallery::filename('state-validation-errors', $viewport));
})->with('viewports');
it('captures the dashboard', function (string $device, string $viewport) {
visualLogin();
visit('/')->on()->{$device}()
->assertSee('Total Users')
->screenshot(true, Gallery::filename('dashboard', $viewport));
})->with('viewports');
it('captures the users index', function (string $device, string $viewport) {
visualLogin();
visit('/users')->on()->{$device}()
->assertSee('Registration Date')
->assertSee('ada@vanguard.test')
->screenshot(true, Gallery::filename('users-index', $viewport));
})->with('viewports');
it('captures the open row menu', function (string $device, string $viewport) {
visualLogin();
visit('/users')->on()->{$device}()
->assertSee('ada@vanguard.test')
->click('tr:has-text("ada@vanguard.test") [aria-label="Action"]')
->assertSee('View User')
->screenshot(true, Gallery::filename('state-row-menu', $viewport));
})->with('viewports');
it('captures the delete confirmation dialog', function (string $device, string $viewport) {
visualLogin();
visit('/users')->on()->{$device}()
->assertSee('ada@vanguard.test')
->click('tr:has-text("ada@vanguard.test") [aria-label="Delete User"]')
->assertSee('Are you sure that you want to delete this user?')
->screenshot(true, Gallery::filename('dialog-delete', $viewport));
})->with('viewports');
it('captures the create user page', function (string $device, string $viewport) {
visualLogin();
visit('/users/create')->on()->{$device}()
->assertSee('Create New User')
->screenshot(true, Gallery::filename('users-create', $viewport));
})->with('viewports');
it('captures the user detail page', function (string $device, string $viewport) {
visualLogin();
$user = User::where('username', 'ada')->firstOrFail();
visit("/users/{$user->id}")->on()->{$device}()
->assertSee('ada@vanguard.test')
->screenshot(true, Gallery::filename('users-show', $viewport));
})->with('viewports');
it('captures the edit user page', function (string $device, string $viewport) {
visualLogin();
$user = User::where('username', 'ada')->firstOrFail();
visit("/users/{$user->id}/edit")->on()->{$device}()
->assertSee('User Details')
->screenshot(true, Gallery::filename('users-edit', $viewport));
})->with('viewports');
it('captures the user sessions page', function (string $device, string $viewport) {
visualLogin();
$user = User::where('username', 'ada')->firstOrFail();
DB::table('sessions')->insert([
'id' => Str::random(),
'user_id' => $user->id,
'ip_address' => '203.0.113.7',
'user_agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari/605.1.15',
'payload' => 'foo',
'last_activity' => Carbon::now()->subMinutes(12)->timestamp,
]);
visit("/users/{$user->id}/sessions")->on()->{$device}()
->assertSee('203.0.113.7')
->screenshot(true, Gallery::filename('users-sessions', $viewport));
})->with('viewports');
it('captures the profile details tab', function (string $device, string $viewport) {
visualLogin();
visit('/profile')->on()->{$device}()
->assertSee('My Profile')
->screenshot(true, Gallery::filename('profile-details', $viewport));
})->with('viewports');
it('captures the profile login details tab', function (string $device, string $viewport) {
visualLogin();
visit('/profile')->on()->{$device}()
->assertSee('My Profile')
->click('Login Details')
->assertSee('New Password')
->screenshot(true, Gallery::filename('profile-login', $viewport));
})->with('viewports');
it('captures the roles index', function (string $device, string $viewport) {
visualLogin();
visit('/roles')->on()->{$device}()
->assertSee('Add Role')
->screenshot(true, Gallery::filename('roles-index', $viewport));
})->with('viewports');
it('captures the role form', function (string $device, string $viewport) {
visualLogin();
visit('/roles/create')->on()->{$device}()
->assertSee('Create New Role')
->screenshot(true, Gallery::filename('roles-create', $viewport));
})->with('viewports');
it('captures the permission matrix', function (string $device, string $viewport) {
visualLogin();
visit('/permissions')->on()->{$device}()
->assertSee('Save Permissions')
->screenshot(true, Gallery::filename('permissions-index', $viewport));
})->with('viewports');
it('captures the permission form', function (string $device, string $viewport) {
visualLogin();
visit('/permissions/create')->on()->{$device}()
->assertSee('Create New Permission')
->screenshot(true, Gallery::filename('permissions-create', $viewport));
})->with('viewports');
it('captures the general settings page', function (string $device, string $viewport) {
visualLogin();
visit('/settings')->on()->{$device}()
->assertSee('General Settings')
->screenshot(true, Gallery::filename('settings-general', $viewport));
})->with('viewports');
it('captures a success flash', function (string $device, string $viewport) {
visualLogin();
visit('/settings')->on()->{$device}()
->assertSee('General Settings')
->click('Update')
->assertSee('Settings updated successfully.')
->screenshot(true, Gallery::filename('state-success-flash', $viewport));
})->with('viewports');
it('captures the authentication settings tab', function (string $device, string $viewport) {
visualLogin();
visit('/settings/auth')->on()->{$device}()
->assertSee('Authentication Throttling')
->screenshot(true, Gallery::filename('settings-auth', $viewport));
})->with('viewports');
it('captures the registration settings tab', function (string $device, string $viewport) {
visualLogin();
visit('/settings/auth')->on()->{$device}()
->assertSee('Authentication Throttling')
->click('Registration')
->assertSee('Allow Registration')
->screenshot(true, Gallery::filename('settings-registration', $viewport));
})->with('viewports');
it('captures the notification settings page', function (string $device, string $viewport) {
visualLogin();
visit('/settings/notifications')->on()->{$device}()
->assertSee('Sign-Up Notification')
->screenshot(true, Gallery::filename('settings-notifications', $viewport));
})->with('viewports');
it('captures the announcements page', function (string $device, string $viewport) {
visualLogin();
visit('/announcements')->on()->{$device}()
->assertSee('Create Announcement')
->screenshot(true, Gallery::filename('plugin-announcements', $viewport));
})->with('viewports');
it('captures the announcement form', function (string $device, string $viewport) {
visualLogin();
visit('/announcements/create')->on()->{$device}()
->assertSee('New Announcement')
->screenshot(true, Gallery::filename('plugin-announcement-form', $viewport));
})->with('viewports');
it('captures the activity log', function (string $device, string $viewport) {
visualLogin();
visit('/activity')->on()->{$device}()
->assertSee('Search for Action')
->screenshot(true, Gallery::filename('plugin-activity', $viewport));
})->with('viewports');
it('captures the approval notice', function (string $device, string $viewport) {
visualLogin();
visit('/approval-notice')->on()->{$device}()
->assertSee('Waiting Approval')
->screenshot(true, Gallery::filename('gate-approval', $viewport));
})->with('viewports');
it('captures the verify email notice', function (string $device, string $viewport) {
$user = User::where('username', 'ada')->firstOrFail();
$user->forceFill(['email_verified_at' => null])->save();
visit('/login')
->fill('#username', 'ada')
->fill('#password', 'password')
->click('Log In')
->assertSee('Verify Your Email Address');
visit('/email/verify')->on()->{$device}()
->assertSee('Verify Your Email Address')
->screenshot(true, Gallery::filename('gate-verify-email', $viewport));
})->with('viewports');