From e96f1cc7bdc417e74b836363c19049095ff5a2e4 Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Tue, 16 Jun 2026 21:10:45 +0100 Subject: [PATCH] fixed duck testing --- .../views/components/layouts/app.blade.php | 1048 +++++++++++++++ .../views/layouts/app/sidebar.blade.php | 1171 +++++++++++++++++ .../Browser/DesktopNavigationBrowserTest.php | 2 +- tests/Browser/MobileNavigationBrowserTest.php | 2 +- tests/Browser/README_DUSK_WMS.md | 35 - tests/Browser/WmsResponsiveNavigationTest.php | 6 +- .../Concerns/InteractsWithWmsNavigation.php | 157 +++ .../Browser/DesktopNavigationBrowserTest.php | 133 ++ .../Browser/MobileNavigationBrowserTest.php | 84 ++ .../Browser/WmsResponsiveNavigationTest.php | 74 ++ 10 files changed, 2672 insertions(+), 40 deletions(-) create mode 100644 Modules/Helpdesk/Resources/views/components/layouts/app.blade.php create mode 100644 Modules/Helpdesk/Resources/views/layouts/app/sidebar.blade.php delete mode 100644 tests/Browser/README_DUSK_WMS.md create mode 100644 tests/tests/Browser/Concerns/InteractsWithWmsNavigation.php create mode 100644 tests/tests/Browser/DesktopNavigationBrowserTest.php create mode 100644 tests/tests/Browser/MobileNavigationBrowserTest.php create mode 100644 tests/tests/Browser/WmsResponsiveNavigationTest.php diff --git a/Modules/Helpdesk/Resources/views/components/layouts/app.blade.php b/Modules/Helpdesk/Resources/views/components/layouts/app.blade.php new file mode 100644 index 00000000..2e7ed892 --- /dev/null +++ b/Modules/Helpdesk/Resources/views/components/layouts/app.blade.php @@ -0,0 +1,1048 @@ + + +@include('partials.head') + + + + + + +
+ + + + +
+ + +
+ {{ $slot }} +
+
+
+ +@fluxScripts + + + + diff --git a/Modules/Helpdesk/Resources/views/layouts/app/sidebar.blade.php b/Modules/Helpdesk/Resources/views/layouts/app/sidebar.blade.php new file mode 100644 index 00000000..026260c3 --- /dev/null +++ b/Modules/Helpdesk/Resources/views/layouts/app/sidebar.blade.php @@ -0,0 +1,1171 @@ + + +@include('partials.head') + + + + + + +
+ + + + +
+ + +
+ {{ $slot }} +
+
+
+ +
+ + + +@fluxScripts + + + + diff --git a/tests/Browser/DesktopNavigationBrowserTest.php b/tests/Browser/DesktopNavigationBrowserTest.php index 95a9209b..001e3b1d 100644 --- a/tests/Browser/DesktopNavigationBrowserTest.php +++ b/tests/Browser/DesktopNavigationBrowserTest.php @@ -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); } }); } diff --git a/tests/Browser/MobileNavigationBrowserTest.php b/tests/Browser/MobileNavigationBrowserTest.php index ffaf714f..0dff1ff0 100644 --- a/tests/Browser/MobileNavigationBrowserTest.php +++ b/tests/Browser/MobileNavigationBrowserTest.php @@ -21,7 +21,7 @@ class MobileNavigationBrowserTest extends DuskTestCase $this->openMobileNavigation($browser); $browser->assertSee('Platform') - ->assertSee('Prices'); + ->assertSourceHas('Prices'); $this->closeMobileNavigation($browser); }); diff --git a/tests/Browser/README_DUSK_WMS.md b/tests/Browser/README_DUSK_WMS.md deleted file mode 100644 index a976792b..00000000 --- a/tests/Browser/README_DUSK_WMS.md +++ /dev/null @@ -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 -``` diff --git a/tests/Browser/WmsResponsiveNavigationTest.php b/tests/Browser/WmsResponsiveNavigationTest.php index c62793db..0ea161ba 100644 --- a/tests/Browser/WmsResponsiveNavigationTest.php +++ b/tests/Browser/WmsResponsiveNavigationTest.php @@ -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'); }); } diff --git a/tests/tests/Browser/Concerns/InteractsWithWmsNavigation.php b/tests/tests/Browser/Concerns/InteractsWithWmsNavigation.php new file mode 100644 index 00000000..f9da0f4a --- /dev/null +++ b/tests/tests/Browser/Concerns/InteractsWithWmsNavigation.php @@ -0,0 +1,157 @@ + '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(<<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(<<pause(300); + } +} diff --git a/tests/tests/Browser/DesktopNavigationBrowserTest.php b/tests/tests/Browser/DesktopNavigationBrowserTest.php new file mode 100644 index 00000000..a30d58b0 --- /dev/null +++ b/tests/tests/Browser/DesktopNavigationBrowserTest.php @@ -0,0 +1,133 @@ +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}]."); + } + }); + } +} diff --git a/tests/tests/Browser/MobileNavigationBrowserTest.php b/tests/tests/Browser/MobileNavigationBrowserTest.php new file mode 100644 index 00000000..2bc6ff8c --- /dev/null +++ b/tests/tests/Browser/MobileNavigationBrowserTest.php @@ -0,0 +1,84 @@ +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'); + } + }); + } +} diff --git a/tests/tests/Browser/WmsResponsiveNavigationTest.php b/tests/tests/Browser/WmsResponsiveNavigationTest.php new file mode 100644 index 00000000..b7dbeebe --- /dev/null +++ b/tests/tests/Browser/WmsResponsiveNavigationTest.php @@ -0,0 +1,74 @@ +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]'); + }); + } +}