- Remove `playwright.config.js` to clean up configuration. - Add new E2E test suites (`admin-pos-orders`, `admin-module-goals`, `admin-module-pos-mobile-order-flow`) to structure Admin module tests. - Introduce reusable authentication and data seeding utilities in `fixtures` for streamlined test flows and maintainability.
171 lines
6.1 KiB
TypeScript
171 lines
6.1 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import {
|
|
passkeyTestData,
|
|
goToUserLogin,
|
|
goToSubuserLogin,
|
|
isPasskeyButtonVisible,
|
|
} from './fixtures';
|
|
|
|
/** Passkey Authentication Tests */
|
|
|
|
// User Passkey Tests
|
|
test.describe('[AUTH][Passkey][User]', () => {
|
|
test('should display passkey login button on user login page when supported', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
// Check if passkey button is visible (depends on browser WebAuthn support)
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// The button visibility depends on WebAuthn support
|
|
// In most modern browsers (Chrome, Edge, Firefox), it should be visible
|
|
const isVisible = await passkeyButton.isVisible();
|
|
|
|
if (isVisible) {
|
|
await expect(passkeyButton).toBeVisible();
|
|
await expect(passkeyButton.locator('.fa-fingerprint')).toBeVisible();
|
|
}
|
|
});
|
|
|
|
test('should have passkey button with fingerprint icon', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// Skip test if passkeys not supported in this browser
|
|
if (!(await passkeyButton.isVisible())) {
|
|
test.skip();
|
|
return;
|
|
}
|
|
|
|
// Button should contain fingerprint icon
|
|
await expect(passkeyButton.locator('.fa-fingerprint')).toBeVisible();
|
|
});
|
|
|
|
test('should display loading spinner when passkey login is clicked', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// Skip test if passkeys not supported
|
|
if (!(await passkeyButton.isVisible())) {
|
|
test.skip();
|
|
return;
|
|
}
|
|
|
|
// Click passkey button - this will trigger WebAuthn prompt
|
|
// Note: The actual WebAuthn flow cannot be completed in automated tests
|
|
// without additional browser configuration or mocking
|
|
await passkeyButton.click();
|
|
|
|
// Button should show loading spinner while waiting for authenticator
|
|
// (This may be brief or the test may need adjustment based on actual behavior)
|
|
await expect(passkeyButton.locator('.fa-spinner')).toBeVisible({ timeout: 1000 }).catch(() => {
|
|
// Loading state may be too fast to catch
|
|
});
|
|
});
|
|
|
|
test('should not disable other login options when passkey is available', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
// Regular login form should still be functional
|
|
const customerNumberInput = page.locator('input[name="customer_number"]');
|
|
const passwordInput = page.locator('input[name="password"]');
|
|
const loginButton = page.locator('button[id="login-button"]');
|
|
|
|
await expect(customerNumberInput).toBeVisible();
|
|
await expect(passwordInput).toBeVisible();
|
|
await expect(loginButton).toBeVisible();
|
|
await expect(loginButton).not.toBeDisabled();
|
|
});
|
|
|
|
test('should show QR code login option alongside passkey', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
// QR code login should still be available
|
|
const qrLoginLink = page.locator('a[href="/auth/loginqr"], a:has-text("QR")');
|
|
await expect(qrLoginLink).toBeVisible();
|
|
});
|
|
});
|
|
|
|
// Subuser Passkey Tests
|
|
test.describe('[AUTH][Passkey][Subuser]', () => {
|
|
test('should display passkey login button on subuser login page when supported', async ({ page }) => {
|
|
await goToSubuserLogin(page);
|
|
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// The button visibility depends on WebAuthn support
|
|
const isVisible = await passkeyButton.isVisible();
|
|
|
|
if (isVisible) {
|
|
await expect(passkeyButton).toBeVisible();
|
|
}
|
|
});
|
|
|
|
test('should not disable phone login when passkey is available', async ({ page }) => {
|
|
await goToSubuserLogin(page);
|
|
|
|
// Regular login form should still be functional
|
|
const phoneInput = page.locator('input[name="phone"]');
|
|
const passwordInput = page.locator('input[name="password"]');
|
|
const loginButton = page.locator('button[id="subuser-login-button"]');
|
|
|
|
await expect(phoneInput).toBeVisible();
|
|
await expect(passwordInput).toBeVisible();
|
|
await expect(loginButton).toBeVisible();
|
|
await expect(loginButton).not.toBeDisabled();
|
|
});
|
|
});
|
|
|
|
// Passkey Browser Support Tests
|
|
test.describe('[AUTH][Passkey][Browser Support]', () => {
|
|
test('should gracefully handle browsers without passkey support', async ({ page, browserName }) => {
|
|
await goToUserLogin(page);
|
|
|
|
// In browsers without WebAuthn, the passkey button should not be visible
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// Get visibility state - this test documents the behavior rather than asserting specific state
|
|
const isVisible = await passkeyButton.isVisible();
|
|
|
|
// Log the state for test reporting
|
|
console.log(`Passkey button visible in ${browserName}: ${isVisible}`);
|
|
|
|
// The important thing is that the page loads correctly regardless
|
|
await expect(page.locator('form')).toBeVisible();
|
|
});
|
|
|
|
test('should always show password-based login as fallback', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
// Password login should always be available, regardless of passkey support
|
|
await expect(page.locator('input[name="customer_number"]')).toBeVisible();
|
|
await expect(page.locator('input[name="password"]')).toBeVisible();
|
|
await expect(page.locator('button[id="login-button"]')).toBeVisible();
|
|
});
|
|
});
|
|
|
|
// Passkey Button State Tests
|
|
test.describe('[AUTH][Passkey][Button State]', () => {
|
|
test('should disable passkey button while loading', async ({ page }) => {
|
|
await goToUserLogin(page);
|
|
|
|
const passkeyButton = page.locator('button[id="passkey-login-button"]');
|
|
|
|
// Skip if passkeys not supported
|
|
if (!(await passkeyButton.isVisible())) {
|
|
test.skip();
|
|
return;
|
|
}
|
|
|
|
// Initial state - button should be enabled
|
|
await expect(passkeyButton).not.toBeDisabled();
|
|
|
|
// After clicking, button should become disabled while loading
|
|
await passkeyButton.click();
|
|
|
|
// The button should be disabled during the authentication attempt
|
|
await expect(passkeyButton).toBeDisabled();
|
|
});
|
|
});
|