355 lines
13 KiB
PHP
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');
|