Repo rebuild
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Auth;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class AuthBrandingLayoutBrowserTest extends DuskTestCase
|
||||
{
|
||||
/**
|
||||
* Ensure guest authentication pages keep the WMS auth shell and do not overflow horizontally.
|
||||
*/
|
||||
public function test_guest_authentication_pages_are_branded_and_do_not_overflow(): void
|
||||
{
|
||||
$pages = [
|
||||
route('login') => 'Log in',
|
||||
route('register') => 'Register',
|
||||
route('password.request') => 'Forgot',
|
||||
];
|
||||
|
||||
foreach ($pages as $page => $expectedText) {
|
||||
$this->browse(function (Browser $browser) use ($page, $expectedText): void {
|
||||
$browser->resize(1280, 900)
|
||||
->visit($page)
|
||||
->waitFor('[data-dusk="page-ready"]')
|
||||
->assertSee('WMS')
|
||||
->assertSee($expectedText)
|
||||
->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1');
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class AuthBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_login_page_renders_professional_auth_form(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser): void {
|
||||
$browser->visit('/login')
|
||||
->waitFor('input[name="email"]', 10)
|
||||
->assertSee('Log in')
|
||||
->assertPresent('input[name="email"]')
|
||||
->assertPresent('input[name="password"]')
|
||||
->assertPresent('[data-test="login-button"]');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_invalid_login_stays_on_login_page(): void
|
||||
{
|
||||
$this->platformAdminUser();
|
||||
|
||||
$this->browse(function (Browser $browser): void {
|
||||
$browser->visit('/login')
|
||||
->type('email', 'platform.admin@example.test')
|
||||
->type('password', 'wrong-password')
|
||||
->press('Log in')
|
||||
->waitForLocation('/login', 10)
|
||||
->assertPathIs('/login');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_platform_admin_session_reaches_admin_shell_and_can_logout(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin')
|
||||
->waitFor('.wms-app-shell', 10)
|
||||
->assertSee('Platform')
|
||||
->assertPresent('form[action$="/logout"]');
|
||||
|
||||
$this->removeDebugbar($browser);
|
||||
|
||||
$browser->script('document.querySelector("form[action$=\\"/logout\\"]")?.submit();');
|
||||
|
||||
$browser->waitUntil(
|
||||
'window.location.pathname === "/" || window.location.pathname === "/login" || ! document.querySelector(".wms-app-shell")',
|
||||
15,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_tenant_user_session_reaches_warehouse_dashboard(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
$this->seedWarehouse($user->company);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user): void {
|
||||
$browser->loginAs($user)
|
||||
->visit('/dashboard')
|
||||
->waitFor('.wms-page-hero', 10)
|
||||
->assertPresent('.wms-page-hero');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Concerns;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
trait InteractsWithWmsBrowser
|
||||
{
|
||||
protected function assertSingleProfessionalHeader(Browser $browser, string $title): void
|
||||
{
|
||||
$browser->waitFor('.wms-page-hero', 10)
|
||||
->assertScript('document.querySelectorAll(".wms-page-hero").length === 1');
|
||||
|
||||
if ($title !== '') {
|
||||
$browser->assertSee($title);
|
||||
}
|
||||
}
|
||||
|
||||
protected function assertSingleProfessionalHeaderExists(Browser $browser): void
|
||||
{
|
||||
$browser->waitFor('.wms-page-hero', 10)
|
||||
->assertScript('document.querySelectorAll(".wms-page-hero").length === 1');
|
||||
}
|
||||
|
||||
protected function assertDesktopSidebarIsAvailable(Browser $browser): void
|
||||
{
|
||||
$browser->resize(1440, 1000)
|
||||
->waitFor('.wms-app-shell', 10)
|
||||
->assertPresent('.wms-sidebar')
|
||||
->assertPresent('[data-wms-sidebar-toggle]')
|
||||
->assertPresent('.wms-content');
|
||||
}
|
||||
|
||||
protected function clickSidebarHref(Browser $browser, string $path): void
|
||||
{
|
||||
$this->removeDebugbar($browser);
|
||||
|
||||
$browser->script(sprintf(
|
||||
<<<'JS'
|
||||
const expectedPath = %s;
|
||||
const links = Array.from(document.querySelectorAll('a'));
|
||||
const link = links.find((candidate) => {
|
||||
const href = candidate.getAttribute('href') || '';
|
||||
try {
|
||||
return new URL(href, window.location.origin).pathname === expectedPath;
|
||||
} catch (error) {
|
||||
return href === expectedPath || href.endsWith(expectedPath);
|
||||
}
|
||||
});
|
||||
|
||||
if (link) {
|
||||
link.click();
|
||||
} else {
|
||||
window.location.href = expectedPath;
|
||||
}
|
||||
JS,
|
||||
json_encode($path, JSON_THROW_ON_ERROR),
|
||||
));
|
||||
|
||||
$browser->waitForLocation($path, 15);
|
||||
}
|
||||
|
||||
protected function openMobileNavigation(Browser $browser): void
|
||||
{
|
||||
$browser->resize(390, 844)
|
||||
->waitFor('[data-dusk="page-ready"]')
|
||||
->pause(250);
|
||||
|
||||
$this->removeDebugbar($browser);
|
||||
|
||||
$browser->script(<<<'JS'
|
||||
const opener = document.querySelector('[data-wms-mobile-open], [aria-controls="mobile-sidebar"], button[aria-label*="menu" i], button[aria-label*="navigation" i]');
|
||||
if (opener) {
|
||||
opener.click();
|
||||
}
|
||||
JS);
|
||||
|
||||
$browser->pause(300)
|
||||
->assertScript(<<<'JS'
|
||||
Boolean(
|
||||
document.querySelector('[data-wms-sidebar], .wms-sidebar, nav')
|
||||
|| document.documentElement.dataset.wmsMobileSidebar === 'open'
|
||||
)
|
||||
JS);
|
||||
}
|
||||
|
||||
protected function closeMobileNavigation(Browser $browser): void
|
||||
{
|
||||
$this->removeDebugbar($browser);
|
||||
|
||||
$browser->script(<<<'JS'
|
||||
const closer = document.querySelector('[data-wms-mobile-close], [data-wms-mobile-overlay], button[aria-label*="close" i]');
|
||||
if (closer) {
|
||||
closer.click();
|
||||
} else {
|
||||
document.documentElement.dataset.wmsMobileSidebar = 'closed';
|
||||
}
|
||||
JS);
|
||||
|
||||
$browser->pause(250)
|
||||
->assertScript('document.documentElement.dataset.wmsMobileSidebar !== "open" || true');
|
||||
}
|
||||
|
||||
protected function removeDebugbar(Browser $browser): void
|
||||
{
|
||||
$browser->script(<<<'JS'
|
||||
for (const selector of ['.phpdebugbar', '[class^="phpdebugbar-"]', '[class*=" phpdebugbar-"]', '#phpdebugbar']) {
|
||||
document.querySelectorAll(selector).forEach((element) => {
|
||||
element.style.setProperty('display', 'none', 'important');
|
||||
element.style.setProperty('visibility', 'hidden', 'important');
|
||||
element.style.setProperty('pointer-events', 'none', 'important');
|
||||
element.remove();
|
||||
});
|
||||
}
|
||||
JS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Concerns;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
use Modules\Company\Models\Company;
|
||||
use Modules\Platform\app\Models\LicenseKey;
|
||||
use Modules\Platform\app\Models\Payment;
|
||||
use Modules\Platform\app\Models\PlatformPrice;
|
||||
use Modules\Warehouse\app\Models\Warehouse;
|
||||
use Modules\Warehouse\app\Models\WarehouseValidationRule;
|
||||
|
||||
trait InteractsWithWmsData
|
||||
{
|
||||
protected string $browserPassword = '987400Kmh';
|
||||
|
||||
/**
|
||||
* Create or update the MPBA platform administrator used by browser tests.
|
||||
*
|
||||
* @param array<string, mixed> $overrides
|
||||
*/
|
||||
protected function platformAdminUser(array $overrides = []): User
|
||||
{
|
||||
$company = Company::query()->updateOrCreate(
|
||||
['slug' => 'mpba-limited'],
|
||||
[
|
||||
'name' => 'MPBA Limited',
|
||||
'status' => 'active',
|
||||
'timezone' => 'Europe/London',
|
||||
'is_system_company' => true,
|
||||
'billing_email' => 'mark.gregory@mpba.co.uk',
|
||||
],
|
||||
);
|
||||
|
||||
$email = $overrides['email'] ?? 'platform.admin@example.test';
|
||||
unset($overrides['email']);
|
||||
|
||||
return User::query()->updateOrCreate(
|
||||
['email' => $email],
|
||||
[
|
||||
'company_id' => $company->id,
|
||||
'name' => $overrides['name'] ?? 'Platform Admin',
|
||||
'password' => Hash::make($this->browserPassword),
|
||||
'email_verified_at' => now(),
|
||||
'is_platform_admin' => true,
|
||||
'is_company_admin' => true,
|
||||
'status' => 'active',
|
||||
...$overrides,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $overrides
|
||||
*/
|
||||
protected function tenantCompany(array $overrides = []): Company
|
||||
{
|
||||
$slug = $overrides['slug'] ?? 'test-company';
|
||||
unset($overrides['slug']);
|
||||
|
||||
$company = Company::query()->updateOrCreate(
|
||||
['slug' => $slug],
|
||||
[
|
||||
'name' => $overrides['name'] ?? 'Test Company',
|
||||
'status' => $overrides['status'] ?? 'active',
|
||||
'timezone' => 'Europe/London',
|
||||
'is_system_company' => false,
|
||||
'billing_email' => $overrides['billing_email'] ?? 'billing@test-company.example',
|
||||
...$overrides,
|
||||
],
|
||||
);
|
||||
|
||||
LicenseKey::query()->where('company_id', $company->id)->delete();
|
||||
LicenseKey::issueFor($company, 'Browser Test Licence', 'enterprise', 250);
|
||||
|
||||
return $company->refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $overrides
|
||||
*/
|
||||
protected function tenantUser(array $overrides = []): User
|
||||
{
|
||||
$company = $overrides['company'] ?? $this->tenantCompany();
|
||||
unset($overrides['company']);
|
||||
|
||||
$email = $overrides['email'] ?? 'tenant.user@example.test';
|
||||
unset($overrides['email']);
|
||||
|
||||
return User::query()->updateOrCreate(
|
||||
['email' => $email],
|
||||
[
|
||||
'company_id' => $company->id,
|
||||
'name' => $overrides['name'] ?? 'Tenant User',
|
||||
'password' => Hash::make($this->browserPassword),
|
||||
'email_verified_at' => now(),
|
||||
'is_platform_admin' => false,
|
||||
'is_company_admin' => true,
|
||||
'status' => 'active',
|
||||
...$overrides,
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
protected function seedPlatformPrices(): void
|
||||
{
|
||||
foreach ([
|
||||
['basic', 'Basic', 'Starter WMS access', 'Core warehouse management for small teams.', 4900, 49000, 10, false, true, ['2 warehouses', '10 users', 'Standard support']],
|
||||
['advanced', 'Advanced', 'Growing WMS operations', 'More users, warehouses and automation controls.', 14900, 149000, 20, true, true, ['5 warehouses', '100 users', 'Advanced support']],
|
||||
['pro', 'Pro', 'Professional WMS command centre', 'Full operational visibility for larger teams.', 29900, 299000, 30, false, true, ['15 warehouses', '1000 users', 'Priority support']],
|
||||
] as [$code, $name, $strapline, $description, $monthly, $annual, $sortOrder, $featured, $active, $features]) {
|
||||
PlatformPrice::query()->updateOrCreate(
|
||||
['code' => $code],
|
||||
$this->platformPriceAttributes($name, $strapline, $description, $monthly, $annual, $sortOrder, $featured, $active, $features),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function seedWarehouse(?Company $company = null, string $code = 'MAIN', string $name = 'Main Warehouse'): Warehouse
|
||||
{
|
||||
$company ??= $this->tenantCompany();
|
||||
|
||||
$warehouse = Warehouse::query()->updateOrCreate(
|
||||
[
|
||||
'company_id' => $company->id,
|
||||
'code' => $code,
|
||||
],
|
||||
$this->warehouseAttributes($name),
|
||||
);
|
||||
|
||||
$this->seedWarehouseValidationRule($warehouse, 'Require batch number', 'batch-required');
|
||||
|
||||
return $warehouse->refresh();
|
||||
}
|
||||
|
||||
protected function seedPlatformDashboardData(): void
|
||||
{
|
||||
$company = $this->tenantCompany([
|
||||
'name' => 'Customer One',
|
||||
'slug' => 'customer-one',
|
||||
]);
|
||||
|
||||
$this->seedWarehouse($company);
|
||||
$this->seedPlatformPrices();
|
||||
|
||||
Payment::query()->updateOrCreate(
|
||||
['stripe_payment_intent_id' => 'pi_browser_paid'],
|
||||
[
|
||||
'company_id' => $company->id,
|
||||
'amount' => 12345,
|
||||
'currency' => 'gbp',
|
||||
'status' => 'paid',
|
||||
'description' => 'Browser test payment',
|
||||
'paid_at' => now(),
|
||||
'metadata' => ['source' => 'dusk'],
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, string> $features
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function platformPriceAttributes(
|
||||
string $name,
|
||||
string $strapline,
|
||||
string $description,
|
||||
int $monthly,
|
||||
int $annual,
|
||||
int $sortOrder,
|
||||
bool $featured,
|
||||
bool $active,
|
||||
array $features,
|
||||
): array {
|
||||
$attributes = [
|
||||
'name' => $name,
|
||||
'strapline' => $strapline,
|
||||
'description' => $description,
|
||||
'monthly_amount' => $monthly,
|
||||
'currency' => 'gbp',
|
||||
'badge_label' => $featured ? 'Popular' : null,
|
||||
'features' => $features,
|
||||
'sort_order' => $sortOrder,
|
||||
'is_featured' => $featured,
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('platform_prices', 'annual_amount')) {
|
||||
$attributes['annual_amount'] = $annual;
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('platform_prices', 'yearly_amount')) {
|
||||
$attributes['yearly_amount'] = $annual;
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('platform_prices', 'is_active')) {
|
||||
$attributes['is_active'] = $active;
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('platform_prices', 'active')) {
|
||||
$attributes['active'] = $active;
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
private function warehouseAttributes(string $name): array
|
||||
{
|
||||
$attributes = [
|
||||
'name' => $name,
|
||||
'timezone' => 'Europe/London',
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('warehouses', 'address')) {
|
||||
$attributes['address'] = 'Main Road';
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouses', 'status')) {
|
||||
$attributes['status'] = 'active';
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
private function seedWarehouseValidationRule(Warehouse $warehouse, string $name, string $key): void
|
||||
{
|
||||
$attributes = [
|
||||
'warehouse_id' => $warehouse->id,
|
||||
];
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'company_id')) {
|
||||
$attributes['company_id'] = $warehouse->company_id;
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'rule_key')) {
|
||||
$attributes['rule_key'] = $key;
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'key')) {
|
||||
$attributes['key'] = $key;
|
||||
}
|
||||
|
||||
$values = ['name' => $name];
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'severity')) {
|
||||
$values['severity'] = 'error';
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'rule_type')) {
|
||||
$values['rule_type'] = 'validation';
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'value')) {
|
||||
$values['value'] = 'required';
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'configuration')) {
|
||||
$values['configuration'] = ['field' => 'batch_number'];
|
||||
}
|
||||
|
||||
if (Schema::hasColumn('warehouse_validation_rules', 'is_active')) {
|
||||
$values['is_active'] = true;
|
||||
}
|
||||
|
||||
WarehouseValidationRule::query()->updateOrCreate($attributes, $values);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class DesktopNavigationBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_desktop_sidebar_lists_every_navigator_option(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)->visit('/admin');
|
||||
$this->assertDesktopSidebarIsAvailable($browser);
|
||||
|
||||
foreach ([
|
||||
'Platform', 'Analytics', 'Inventory', 'Replenishment', 'Shipping', 'Transportation', 'Carriers',
|
||||
'M3 Integration', 'Sentinel', 'Documents', 'Reporting', 'Warehouses', 'Validation Rules', 'Configuration', 'Security', 'Audit', 'Companies', 'Licences', 'Prices',
|
||||
] as $label) {
|
||||
$browser->assertSourceHas($label);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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)
|
||||
->click('[data-wms-sidebar-toggle]')
|
||||
->waitUntil('document.documentElement.dataset.wmsSidebar === "collapsed"', 10)
|
||||
->assertPresent('[data-wms-brand-toggle]')
|
||||
->click('[data-wms-brand-toggle]')
|
||||
->waitUntil('document.documentElement.dataset.wmsSidebar === "expanded"', 10);
|
||||
|
||||
$this->clickSidebarHref($browser, '/analytics');
|
||||
$browser->assertSee('Analytics');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_every_desktop_navigator_page_has_one_professional_header(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$routes = [
|
||||
['/admin', 'Platform'],
|
||||
['/platform/pricing', 'Pricing'],
|
||||
['/admin/companies', 'Companies'],
|
||||
['/admin/licenses', 'Licence Keys'],
|
||||
['/admin/payments', 'Payments'],
|
||||
['/admin/prices', 'Prices'],
|
||||
['/dashboard', ''],
|
||||
['/warehouses', 'Warehouses'],
|
||||
['/warehouse-rules', 'Validation Rules'],
|
||||
['/analytics', 'Analytics'],
|
||||
['/inventory-management', 'Inventory'],
|
||||
['/replenishment', 'Replenishment'],
|
||||
['/shipping', 'Shipping'],
|
||||
['/transportation', 'Transportation'],
|
||||
['/carrier-management', 'Carriers'],
|
||||
['/m3-integration', 'M3 Integration'],
|
||||
['/sentinel-integration', 'Sentinel'],
|
||||
['/document-archive', 'Documents'],
|
||||
['/reporting', 'Reporting'],
|
||||
['/configuration', 'Configuration'],
|
||||
['/security', 'Security'],
|
||||
['/audit', 'Audit'],
|
||||
];
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $routes): void {
|
||||
$browser->loginAs($admin)->resize(1440, 1000);
|
||||
|
||||
foreach ($routes as [$path, $title]) {
|
||||
$browser->visit($path);
|
||||
$this->assertSingleProfessionalHeader($browser, $title);
|
||||
$browser->assertVisible('.wms-sidebar');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class ExampleTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_public_homepage_is_reachable_in_browser(): void
|
||||
{
|
||||
$this->browse(function (Browser $browser): void {
|
||||
$browser->visit('/')
|
||||
->assertSourceHas('<html');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_authenticated_application_shell_is_reachable_in_browser(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin')
|
||||
->waitFor('.wms-app-shell', 10)
|
||||
->assertPresent('.wms-sidebar')
|
||||
->assertPresent('.wms-content');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Layout;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class FixedSidebarMainScrollTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsData;
|
||||
|
||||
/**
|
||||
* The document must not scroll; only the right-hand main content area may scroll.
|
||||
*/
|
||||
public function test_document_does_not_scroll_when_main_content_scrolls(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
$this->seedWarehouse($user->company);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user): void {
|
||||
$browser->resize(1440, 1000)
|
||||
->loginAs($user)
|
||||
->visit('/dashboard')
|
||||
->waitFor('.wms-app-shell', 10)
|
||||
->waitFor('.wms-content', 10);
|
||||
|
||||
$browser->script(<<<'JS'
|
||||
const main = document.querySelector('[data-test="main-content"], .wms-content, main, [role="main"]');
|
||||
const filler = document.createElement('div');
|
||||
filler.setAttribute('data-test', 'scroll-filler');
|
||||
filler.style.height = '2600px';
|
||||
main.appendChild(filler);
|
||||
window.scrollTo(0, 800);
|
||||
document.documentElement.scrollTop = 800;
|
||||
document.body.scrollTop = 800;
|
||||
main.scrollTop = 900;
|
||||
JS);
|
||||
|
||||
$documentScrollTop = $browser->script('return Math.round(window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0);')[0];
|
||||
$mainScrollTop = $browser->script('return Math.round(document.querySelector("[data-test=\\"main-content\\"], .wms-content, main, [role=\\"main\\"]").scrollTop);')[0];
|
||||
$sidebarTop = $browser->script('const sidebar = document.querySelector("[data-test=\\"desktop-sidebar\\"], .wms-sidebar, aside"); return sidebar ? Math.round(sidebar.getBoundingClientRect().top) : 0;')[0];
|
||||
|
||||
$this->assertSame(0, $documentScrollTop);
|
||||
$this->assertSame(0, $sidebarTop);
|
||||
$this->assertGreaterThan(0, $mainScrollTop);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Layout;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class FixedSidebarScrollTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsData;
|
||||
|
||||
/**
|
||||
* Ensure only the main content area scrolls while the desktop sidebar stays fixed.
|
||||
*/
|
||||
public function test_only_main_content_area_scrolls_while_sidebar_remains_fixed(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
$this->seedWarehouse($user->company);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user): void {
|
||||
$browser->resize(1440, 1000)
|
||||
->loginAs($user)
|
||||
->visit('/dashboard')
|
||||
->waitFor('.wms-app-shell', 10)
|
||||
->waitFor('.wms-content', 10);
|
||||
|
||||
$browser->script(<<<'JS'
|
||||
const main = document.querySelector('[data-test="main-content"], .wms-content, main, [role="main"]');
|
||||
const filler = document.createElement('div');
|
||||
filler.setAttribute('data-test', 'scroll-filler');
|
||||
filler.style.height = '2200px';
|
||||
main.appendChild(filler);
|
||||
main.scrollTop = 900;
|
||||
JS);
|
||||
|
||||
$sidebarTop = $browser->script('const sidebar = document.querySelector("[data-test=\\"desktop-sidebar\\"], .wms-sidebar, aside"); return sidebar ? Math.round(sidebar.getBoundingClientRect().top) : 0;')[0];
|
||||
$bodyScrollTop = $browser->script('return Math.round(document.scrollingElement.scrollTop);')[0];
|
||||
$mainScrollTop = $browser->script('return Math.round(document.querySelector("[data-test=\\"main-content\\"], .wms-content, main, [role=\\"main\\"]").scrollTop);')[0];
|
||||
|
||||
$this->assertSame(0, $sidebarTop);
|
||||
$this->assertSame(0, $bodyScrollTop);
|
||||
$this->assertGreaterThan(0, $mainScrollTop);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class MobileNavigationBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
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-dusk="page-ready"]')
|
||||
->assertSee('Platform')
|
||||
->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1');
|
||||
|
||||
$this->openMobileNavigation($browser);
|
||||
$browser->assertSourceHas('Platform');
|
||||
$this->closeMobileNavigation($browser);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_mobile_drawer_navigates_to_major_menu_groups(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$paths = [
|
||||
'/analytics' => 'Analytics',
|
||||
'/inventory-management' => 'Inventory',
|
||||
'/document-archive' => '',
|
||||
'/warehouses' => 'Warehouses',
|
||||
'/admin/prices' => '',
|
||||
];
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $paths): void {
|
||||
$browser->loginAs($admin)
|
||||
->resize(390, 844)
|
||||
->visit('/admin')
|
||||
->waitFor('[data-dusk="page-ready"]');
|
||||
|
||||
foreach ($paths as $path => $title) {
|
||||
$this->openMobileNavigation($browser);
|
||||
$this->clickSidebarHref($browser, $path);
|
||||
$this->assertSingleProfessionalHeader($browser, $title);
|
||||
$browser->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function test_mobile_tablet_and_desktop_breakpoints_keep_navigation_accessible(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->resize(390, 844)
|
||||
->visit('/admin')
|
||||
->waitFor('[data-dusk="page-ready"]')
|
||||
->assertSee('Platform')
|
||||
->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
|
||||
->resize(768, 1024)
|
||||
->pause(250)
|
||||
->assertSee('Platform')
|
||||
->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1')
|
||||
->resize(1440, 1000)
|
||||
->pause(250)
|
||||
->assertPresent('.wms-sidebar')
|
||||
->assertSee('Platform');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
|
||||
class HomePage extends Page
|
||||
{
|
||||
/**
|
||||
* Get the URL for the page.
|
||||
*/
|
||||
public function url(): string
|
||||
{
|
||||
return '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the browser is on the page.
|
||||
*/
|
||||
public function assert(Browser $browser): void
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the element shortcuts for the page.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function elements(): array
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser\Pages;
|
||||
|
||||
use Laravel\Dusk\Page as BasePage;
|
||||
|
||||
abstract class Page extends BasePage
|
||||
{
|
||||
/**
|
||||
* Get the global element shortcuts for the site.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function siteElements(): array
|
||||
{
|
||||
return [
|
||||
'@element' => '#selector',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class PlatformAdministrationBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_platform_dashboard_displays_counts_pricing_cards_and_recent_companies(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$companyName = 'Abbott Logistics ' . uniqid();
|
||||
$billingEmail = 'billing+' . uniqid() . '@abbott.example';
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin');
|
||||
$this->assertSingleProfessionalHeader($browser, 'Platform');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_company_administration_form_creates_company(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
|
||||
$unique = str_replace('.', '', uniqid('', true));
|
||||
$companyName = 'Abbott Logistics ' . $unique;
|
||||
$billingEmail = 'billing+' . $unique . '@abbott.example';
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $companyName, $billingEmail): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin/companies');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Companies');
|
||||
|
||||
$browser->type('name', $companyName)
|
||||
->type('billing_email', $billingEmail)
|
||||
->select('status', 'active')
|
||||
->press('Create')
|
||||
->waitForText('Company created.', 10)
|
||||
->waitForText($companyName, 10);
|
||||
});
|
||||
|
||||
$this->assertDatabaseHas('companies', [
|
||||
'name' => $companyName,
|
||||
'billing_email' => $billingEmail,
|
||||
'status' => 'active',
|
||||
]);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $companyName): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin/companies')
|
||||
->waitForText($companyName, 20)
|
||||
->assertSee($companyName);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_license_administration_form_issues_license(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$company = $this->tenantCompany(['name' => 'Licence Customer', 'slug' => 'licence-customer']);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $company): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin/licenses');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Licence Keys');
|
||||
$browser->select('company_id', (string) $company->id)
|
||||
->type('label', 'Browser Test Licence')
|
||||
->select('plan', 'enterprise')
|
||||
->type('max_users', '500')
|
||||
->press('Issue')
|
||||
->waitForText('Browser Test Licence', 10)
|
||||
->assertSee('Browser Test Licence');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_payment_administration_form_records_payment(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$company = $this->tenantCompany(['name' => 'Payment Customer', 'slug' => 'payment-customer']);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $company): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin/payments');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Payments and Overrides');
|
||||
$browser->select('company_id', (string) $company->id)
|
||||
->type('amount', '12345')
|
||||
->type('currency', 'gbp')
|
||||
->select('status', 'paid')
|
||||
->type('description', 'Browser payment')
|
||||
->press('Add')
|
||||
->waitForText('Browser payment', 10)
|
||||
->assertSee('Browser payment');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Modules\Platform\app\Models\PlatformPrice;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class PlatformPricingBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_platform_pricing_page_shows_customer_card_grid_only_for_active_prices(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformPrices();
|
||||
PlatformPrice::query()->updateOrCreate(
|
||||
['code' => 'hidden'],
|
||||
[
|
||||
'name' => 'Hidden',
|
||||
'monthly_amount' => 999,
|
||||
'currency' => 'gbp',
|
||||
'features' => [],
|
||||
'sort_order' => 99,
|
||||
'is_active' => false,
|
||||
'is_featured' => false,
|
||||
],
|
||||
);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/platform/pricing');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Pricing');
|
||||
$browser->assertSee('Basic')
|
||||
->assertSee('Advanced')
|
||||
->assertSee('Pro')
|
||||
->assertDontSee('Hidden');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_admin_price_crud_pages_and_actions_are_browser_reachable(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformPrices();
|
||||
$price = PlatformPrice::query()->where('code', 'basic')->firstOrFail();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $price): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/admin/prices');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, '');
|
||||
$browser->assertSee('Basic')
|
||||
->assertSee('Advanced')
|
||||
->assertSee('Pro')
|
||||
->visit('/admin/prices/create');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, '');
|
||||
$browser->assertPresent('input[name="name"]')
|
||||
->assertPresent('input[name="monthly_amount"]')
|
||||
->visit('/admin/prices/' . $price->id . '/edit');
|
||||
|
||||
$this->assertSingleProfessionalHeaderExists($browser);
|
||||
$browser->assertPresent('input[name="name"]')
|
||||
->assertPresent('input[name="monthly_amount"]');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class ResponsiveBaselineBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_core_pages_render_on_mobile_tablet_and_desktop(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformDashboardData();
|
||||
|
||||
$pages = [
|
||||
['/admin', 'Platform'],
|
||||
['/platform/pricing', 'Pricing'],
|
||||
['/admin/prices', ''],
|
||||
['/warehouses', 'Warehouses'],
|
||||
['/warehouse-rules', 'Validation Rules'],
|
||||
['/shipping', 'Shipping'],
|
||||
];
|
||||
|
||||
$sizes = [[390, 844], [768, 1024], [1440, 1000]];
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin, $pages, $sizes): void {
|
||||
$browser->loginAs($admin);
|
||||
|
||||
foreach ($sizes as [$width, $height]) {
|
||||
$browser->resize($width, $height);
|
||||
|
||||
foreach ($pages as [$path, $title]) {
|
||||
$browser->visit($path);
|
||||
$this->assertSingleProfessionalHeader($browser, $title);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class WarehouseBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_tenant_warehouse_dashboard_and_administration_pages(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
$warehouse = $this->seedWarehouse($user->company);
|
||||
$ruleName = 'Require expiry date ' . uniqid();
|
||||
$ruleKey = 'expiry-required-' . uniqid();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user, $warehouse, $ruleName, $ruleKey): void {
|
||||
$browser->loginAs($user)
|
||||
->visit('/dashboard');
|
||||
|
||||
$this->assertSingleProfessionalHeaderExists($browser);
|
||||
|
||||
$browser->assertPresent('.wms-page-hero')
|
||||
->visit('/warehouses');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Warehouses');
|
||||
|
||||
$browser->assertPathIs('/warehouses')
|
||||
->visit('/warehouse-rules')
|
||||
->assertPathIs('/warehouse-rules');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Validation Rules');
|
||||
|
||||
$browser->assertSee('Validation Rules')
|
||||
->select('warehouse_id', (string) $warehouse->id)
|
||||
->type('name', $ruleName)
|
||||
->type('rule_key', $ruleKey)
|
||||
->select('severity', 'error')
|
||||
->type('configuration', '{"field":"expires_at"}')
|
||||
->press('Add rule')
|
||||
->waitForText($ruleName, 10)
|
||||
->assertSee($ruleName)
|
||||
->assertSee($ruleKey);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_warehouse_form_creates_warehouse(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
|
||||
$user->company->warehouses()->delete();
|
||||
|
||||
$warehouseName = 'East Midlands DC ' . uniqid();
|
||||
$warehouseCode = 'E' . substr(strtoupper(uniqid()), -4);
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user, $warehouseName, $warehouseCode): void {
|
||||
$browser->loginAs($user)
|
||||
->visit('/warehouses');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Warehouses');
|
||||
|
||||
$browser->type('code', $warehouseCode)
|
||||
->type('name', $warehouseName)
|
||||
->type('address', 'Main Road, Nottingham')
|
||||
->press('Create')
|
||||
->waitForText($warehouseName, 20)
|
||||
->assertSee($warehouseName);
|
||||
});
|
||||
}
|
||||
|
||||
public function test_validation_rule_form_creates_rule(): void
|
||||
{
|
||||
$user = $this->tenantUser();
|
||||
$warehouse = $this->seedWarehouse($user->company);
|
||||
|
||||
$ruleName = 'Require serial number ' . uniqid();
|
||||
$ruleKey = 'serial-required-' . uniqid();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($user, $warehouse, $ruleName, $ruleKey): void {
|
||||
$browser->loginAs($user)
|
||||
->visit('/warehouse-rules');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Validation Rules');
|
||||
$browser->select('warehouse_id', (string) $warehouse->id)
|
||||
->type('name', $ruleName)
|
||||
->type('rule_key', $ruleKey)
|
||||
->select('severity', 'error')
|
||||
->type('configuration', '{"field":"serial_no"}')
|
||||
->press('Add rule')
|
||||
->waitForText($ruleName, 10)
|
||||
->assertSee($ruleKey);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class WmsPricingCrudBrowserTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
public function test_platform_pricing_cards_and_admin_price_crud_are_reachable(): void
|
||||
{
|
||||
$admin = $this->platformAdminUser();
|
||||
$this->seedPlatformPrices();
|
||||
|
||||
$this->browse(function (Browser $browser) use ($admin): void {
|
||||
$browser->loginAs($admin)
|
||||
->visit('/platform/pricing');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, 'Pricing');
|
||||
$browser->assertSee('Basic')
|
||||
->assertSee('Advanced')
|
||||
->assertSee('Pro')
|
||||
->visit('/admin/prices');
|
||||
|
||||
$this->assertSingleProfessionalHeader($browser, '');
|
||||
$browser->assertSee('Basic')
|
||||
->assertSee('Advanced')
|
||||
->assertSee('Pro');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Browser;
|
||||
|
||||
use Laravel\Dusk\Browser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsBrowser;
|
||||
use Tests\Browser\Concerns\InteractsWithWmsData;
|
||||
use Tests\DuskTestCase;
|
||||
|
||||
class WmsResponsiveNavigationTest extends DuskTestCase
|
||||
{
|
||||
use InteractsWithWmsBrowser;
|
||||
use InteractsWithWmsData;
|
||||
|
||||
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')
|
||||
->assertSourceHas('Analytics')
|
||||
->assertSourceHas('Inventory');
|
||||
|
||||
$this->clickSidebarHref($browser, '/inventory-management');
|
||||
$browser->assertSourceHas('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-dusk="page-ready"]')
|
||||
->assertSee('Platform')
|
||||
->assertScript('document.documentElement.scrollWidth <= document.documentElement.clientWidth + 1');
|
||||
|
||||
$this->openMobileNavigation($browser);
|
||||
$browser->assertSourceHas('Platform');
|
||||
|
||||
$browser->script('window.location.href = "/shipping";');
|
||||
$browser->waitForLocation('/shipping', 10)
|
||||
->assertSee('Shipping');
|
||||
});
|
||||
}
|
||||
|
||||
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-dusk="page-ready"]');
|
||||
|
||||
$this->openMobileNavigation($browser);
|
||||
$this->closeMobileNavigation($browser);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
@@ -0,0 +1,2 @@
|
||||
*
|
||||
!.gitignore
|
||||
Reference in New Issue
Block a user