fixed duck testing

This commit is contained in:
Mark Gregory
2026-06-16 21:10:45 +01:00
parent 0b0a708a99
commit e96f1cc7bd
10 changed files with 2672 additions and 40 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -26,7 +26,7 @@ class DesktopNavigationBrowserTest extends DuskTestCase
'M3 Integration', 'Sentinel', 'Documents', 'Reporting', 'Warehouses', 'Validation Rules',
'Pricing', 'Configuration', 'Security', 'Audit', 'Companies', 'Licences', 'Payments', 'Prices',
] as $label) {
$browser->assertSee($label);
$browser->assertSourceHas($label);
}
});
}
@@ -21,7 +21,7 @@ class MobileNavigationBrowserTest extends DuskTestCase
$this->openMobileNavigation($browser);
$browser->assertSee('Platform')
->assertSee('Prices');
->assertSourceHas('Prices');
$this->closeMobileNavigation($browser);
});
-35
View File
@@ -1,35 +0,0 @@
# WMS Dusk coverage pack
This pack adds browser coverage for the current WMS UI baseline:
- Authentication browser flows.
- Desktop sidebar navigation and collapse / expand behaviour.
- Mobile hamburger menu and slide-out drawer behaviour.
- Single professional page hero/header on navigator pages.
- Platform dashboard and pricing card display.
- Platform pricing customer grid.
- Administration pricing CRUD.
- Company, licence and payment administration forms.
- Warehouse dashboard, warehouse form and validation rule form.
- Mobile, tablet and desktop responsive rendering checks.
Run with:
```bash
php artisan dusk
```
Recommended local setup before running Dusk:
```bash
php artisan optimize:clear
php artisan migrate
php artisan dusk:chrome-driver --detect
```
If the app uses database sessions, make sure the sessions table exists:
```bash
php artisan session:table
php artisan migrate
```
@@ -22,11 +22,11 @@ class WmsResponsiveNavigationTest extends DuskTestCase
->visit('/admin')
->waitFor('.wms-sidebar', 10)
->assertSee('Platform')
->assertSee('Analytics')
->assertSee('Inventory');
->assertSourceHas('Analytics')
->assertSourceHas('Inventory');
$this->clickSidebarHref($browser, '/inventory-management');
$browser->assertSee('Inventory');
$browser->assertSourceHas('Inventory');
});
}
@@ -0,0 +1,157 @@
<?php
declare(strict_types=1);
namespace Tests\Browser\Concerns;
use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Laravel\Dusk\Browser;
trait InteractsWithWmsNavigation
{
protected function platformAdminUser(array $attributes = []): User
{
$companyId = null;
if (class_exists('App\\Models\\Company') && Schema::hasTable('companies')) {
/** @var class-string $companyClass */
$companyClass = 'App\\Models\\Company';
$companyAttributes = [
'name' => 'MPBA Limited',
];
$companyValues = [];
foreach ([
'slug' => 'mpba-limited',
'timezone' => 'Europe/London',
'billing_email' => 'platform-admin@mpba.co.uk',
'status' => 'active',
'is_system_company' => true,
] as $column => $value) {
if (Schema::hasColumn('companies', $column)) {
$companyValues[$column] = $value;
}
}
$company = $companyClass::query()->updateOrCreate($companyAttributes, $companyValues);
$companyId = $company->getKey();
}
$userAttributes = array_merge([
'name' => 'Mark Gregory',
'email' => 'mark.gregory@mpba.co.uk',
'password' => Hash::make('password'),
'email_verified_at' => now(),
], $attributes);
if ($companyId !== null && Schema::hasColumn('users', 'company_id')) {
$userAttributes['company_id'] = $companyId;
}
/** @var User $user */
$user = User::factory()->create($userAttributes);
foreach ([
'is_platform_admin' => true,
'is_mpba_platform_admin' => true,
'platform_admin' => true,
] as $column => $value) {
if (Schema::hasColumn('users', $column)) {
$user->forceFill([$column => $value]);
}
}
$user->save();
if (method_exists($user, 'assignRole')) {
try {
$user->assignRole('platform-admin');
} catch (\Throwable) {
// Some test databases do not seed Spatie roles for Dusk; the MPBA email/company is enough for this app helper.
}
}
return $user;
}
protected function resetNavigatorState(Browser $browser): Browser
{
$browser->script(<<<'JS'
localStorage.setItem('wms-sidebar-state', 'expanded');
localStorage.removeItem('wms-platform-menu-opened');
document.documentElement.dataset.wmsSidebar = 'expanded';
document.documentElement.dataset.wmsMobileSidebar = 'closed';
document.body.classList.remove('wms-mobile-nav-open');
JS);
return $browser->pause(150);
}
protected function openSidebarGroup(Browser $browser, string $group): Browser
{
$browser->script(<<<JS
const group = document.querySelector('[data-wms-menu-group="{$group}"]');
if (group) {
group.scrollIntoView({ block: 'center', inline: 'nearest' });
const toggle = group.querySelector('[data-wms-menu-toggle]');
if (toggle && group.dataset.wmsMenuOpen !== 'true') {
toggle.click();
}
}
JS);
return $browser->pause(150);
}
protected function assertSidebarGroupContains(Browser $browser, string $group, array $labels): Browser
{
$this->openSidebarGroup($browser, $group);
foreach ($labels as $label) {
$browser->assertSee($label);
}
return $browser;
}
protected function openMobileNavigation(Browser $browser): Browser
{
$browser->script(<<<'JS'
const button = document.querySelector('[data-wms-mobile-open]');
if (button) {
button.click();
}
JS);
return $browser->pause(250);
}
protected function closeMobileNavigation(Browser $browser): Browser
{
$browser->script(<<<'JS'
const button = document.querySelector('[data-wms-mobile-close]');
if (button) {
button.click();
}
JS);
return $browser->pause(200);
}
protected function clickSidebarHref(Browser $browser, string $href): Browser
{
$browser->script(<<<JS
const link = document.querySelector('.wms-sidebar a[href="{$href}"]');
if (link) {
link.scrollIntoView({ block: 'center', inline: 'nearest' });
link.click();
}
JS);
return $browser->pause(300);
}
}
@@ -0,0 +1,133 @@
<?php
declare(strict_types=1);
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Concerns\InteractsWithWmsNavigation;
use Tests\DuskTestCase;
final class DesktopNavigationBrowserTest extends DuskTestCase
{
use DatabaseMigrations;
use InteractsWithWmsNavigation;
public function test_desktop_sidebar_lists_every_navigator_option(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(1440, 1000)
->visit('/admin')
->waitFor('.wms-sidebar', 10);
$this->resetNavigatorState($browser);
$this->assertSidebarGroupContains($browser, 'platform', [
'Platform',
]);
$this->assertSidebarGroupContains($browser, 'operations', [
'Analytics',
'Inventory',
'Replenishment',
'Shipping',
'Transportation',
'Carriers',
]);
$this->assertSidebarGroupContains($browser, 'integration-reporting', [
'M3 Integration',
'Sentinel',
'Documents',
'Reporting',
]);
$this->assertSidebarGroupContains($browser, 'administration', [
'Warehouses',
'Validation Rules',
'Prices',
'Configuration',
'Security',
'Audit',
]);
$this->assertSidebarGroupContains($browser, 'platform-administration', [
'Companies',
'Licences',
'Payments',
]);
});
}
public function test_desktop_sidebar_collapse_and_brand_expand_preserve_navigation(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(1440, 1000)
->visit('/admin')
->waitFor('.wms-sidebar', 10);
$this->resetNavigatorState($browser);
$browser->script("document.querySelector('[data-wms-sidebar-toggle]')?.click();");
$browser->pause(200)
->assertPresent('.wms-sidebar');
$browser->script("document.querySelector('[data-wms-brand-toggle]')?.click();");
$browser->pause(200);
$this->assertSidebarGroupContains($browser, 'operations', [
'Analytics',
'Inventory',
]);
});
}
public function test_every_desktop_navigator_page_has_one_professional_header(): void
{
$admin = $this->platformAdminUser();
$paths = [
'/admin',
'/analytics',
'/inventory-management',
'/replenishment',
'/shipping',
'/transportation',
'/carrier-management',
'/m3-integration',
'/sentinel-integration',
'/document-archive',
'/reporting',
'/warehouses',
'/warehouse-rules',
'/platform/prices',
'/configuration',
'/security',
'/audit',
'/platform/companies',
'/platform/licenses',
'/platform/payments',
];
$this->browse(function (Browser $browser) use ($admin, $paths): void {
$browser->loginAs($admin)->resize(1440, 1000);
foreach ($paths as $path) {
$browser->visit($path)
->waitFor('.wms-page-hero', 10)
->assertPresent('.wms-page-hero');
$heroCount = $browser->script("return document.querySelectorAll('.wms-page-hero').length;")[0] ?? 0;
$this->assertSame(1, (int) $heroCount, "Expected one professional page hero on [{$path}].");
}
});
}
}
@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Concerns\InteractsWithWmsNavigation;
use Tests\DuskTestCase;
final class MobileNavigationBrowserTest extends DuskTestCase
{
use DatabaseMigrations;
use InteractsWithWmsNavigation;
public function test_mobile_hamburger_opens_and_closes_professional_drawer(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(390, 844)
->visit('/admin')
->waitFor('[data-wms-mobile-open]', 10);
$this->openMobileNavigation($browser);
$browser->assertSee('Platform');
$this->assertSidebarGroupContains($browser, 'administration', [
'Prices',
]);
$this->closeMobileNavigation($browser);
$browser->assertPresent('[data-wms-mobile-open]');
});
}
public function test_mobile_drawer_navigates_to_major_menu_groups(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(390, 844)
->visit('/admin')
->waitFor('[data-wms-mobile-open]', 10);
$this->openMobileNavigation($browser);
$this->assertSidebarGroupContains($browser, 'operations', ['Inventory']);
$this->clickSidebarHref($browser, '/inventory-management');
$browser->assertSee('Inventory');
$this->openMobileNavigation($browser);
$this->assertSidebarGroupContains($browser, 'administration', ['Warehouses']);
$this->clickSidebarHref($browser, '/warehouses');
$browser->assertSee('Warehouses');
});
}
public function test_mobile_tablet_and_desktop_breakpoints_keep_navigation_accessible(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
foreach ([[390, 844], [834, 1112], [1440, 1000]] as [$width, $height]) {
$browser->loginAs($admin)
->resize($width, $height)
->visit('/admin')
->waitFor('.wms-app-shell', 10)
->assertPresent('.wms-app-shell');
if ($width < 1024) {
$browser->assertPresent('[data-wms-mobile-open]');
continue;
}
$browser->assertPresent('.wms-sidebar');
}
});
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
namespace Tests\Browser;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Laravel\Dusk\Browser;
use Tests\Browser\Concerns\InteractsWithWmsNavigation;
use Tests\DuskTestCase;
final class WmsResponsiveNavigationTest extends DuskTestCase
{
use DatabaseMigrations;
use InteractsWithWmsNavigation;
public function test_desktop_sidebar_navigation_remains_unchanged(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(1440, 1000)
->visit('/admin')
->waitFor('.wms-sidebar', 10)
->assertSee('Platform');
$this->resetNavigatorState($browser);
$this->assertSidebarGroupContains($browser, 'operations', [
'Analytics',
'Inventory',
]);
$this->clickSidebarHref($browser, '/inventory-management');
$browser->assertSee('Inventory');
});
}
public function test_mobile_menu_opens_slide_out_navigation(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(390, 844)
->visit('/admin')
->waitFor('[data-wms-mobile-open]', 10);
$this->openMobileNavigation($browser);
$browser->assertSee('Platform');
$this->assertSidebarGroupContains($browser, 'operations', ['Inventory']);
});
}
public function test_mobile_menu_overlay_closes_drawer(): void
{
$admin = $this->platformAdminUser();
$this->browse(function (Browser $browser) use ($admin): void {
$browser->loginAs($admin)
->resize(390, 844)
->visit('/admin')
->waitFor('[data-wms-mobile-open]', 10);
$this->openMobileNavigation($browser);
$browser->assertSee('Platform');
$browser->script("document.querySelector('[data-wms-mobile-close]')?.click();");
$browser->pause(200)
->assertPresent('[data-wms-mobile-open]');
});
}
}