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(); }); });