Files
pleno-vue/tests/e2e/fixtures/authHelpers.ts
T
Jeppe Bundgaard b39b458f4f Add .prettierrc.json and refactor test files for improved formatting consistency:
- Introduced `.prettierrc.json` to enforce consistent code formatting across the project.
- Updated unit and e2e test files to address formatting issues, improve readability, and ensure alignment with the new Prettier configuration.
2026-04-13 09:13:27 +02:00

237 lines
8.5 KiB
TypeScript

import { Page, expect } from "@playwright/test";
import {
userCredentials,
subuserPhoneCredentials,
subuserUsernameCredentials,
operatorCredentials,
user2FACredentials,
subuser2FACredentials,
qrAuthToken,
} from "./testData";
import { generateOTP } from "./otp";
// Auth timeout in milliseconds (15 seconds)
const AUTH_TIMEOUT = 15000;
const USER_HOME_URL = /\/user(?:\/)?(?:[?#].*)?$/;
const ADMIN_HOME_URL = /\/admin(?:\/)?(?:[?#].*)?$/;
/**
* Reusable authentication helpers for tests
* Provides login functions for different user types
*/
/**
* Login as a customer user (by customer number)
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to userCredentials)
*/
export async function loginAsUser(
page: Page,
credentials?: { customerNumber: string; password: string; twoFactorAuthentication?: boolean; otpSecret?: string }
) {
const creds = credentials || userCredentials;
await page.goto("/login");
await page.fill('input[name="customer_number"]', creds.customerNumber);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="login-button"]');
// If two-factor authentication is enabled, wait for OTP input
if (creds.twoFactorAuthentication) {
await page.waitForSelector('input[name="2fa_code"]');
// Generate OTP using secret
await page.fill('input[name="2fa_code"]', generateOTP(creds.otpSecret!));
await page.click('button[id="2fa-verify-button"]');
}
await expect(page).toHaveURL(USER_HOME_URL, { timeout: AUTH_TIMEOUT });
}
/**
* Login as a subuser/driver (by phone number)
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to subuserPhoneCredentials)
*/
export async function loginAsSubuserByPhone(
page: Page,
credentials?: {
phoneCountryCode: string;
phone: string;
password: string;
twoFactorAuthentication?: boolean;
otpSecret?: string;
}
) {
const creds = credentials || subuserPhoneCredentials;
await page.goto("/login/driver");
await page.fill('input[name="phone_country_code"]', creds.phoneCountryCode);
await page.fill('input[name="phone"]', creds.phone);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="subuser-login-button"]');
// If two-factor authentication is enabled, wait for OTP input
if (creds.twoFactorAuthentication) {
await page.waitForSelector('input[name="2fa_code"]');
// Generate OTP using secret
await page.fill('input[name="2fa_code"]', generateOTP(creds.otpSecret!));
await page.click('button[id="2fa-verify-button"]');
}
await expect(page).toHaveURL(USER_HOME_URL, { timeout: AUTH_TIMEOUT });
}
/**
* Login as a subuser/driver (by username)
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to subuserUsernameCredentials)
*/
export async function loginAsSubuserByUsername(
page: Page,
credentials?: { username: string; password: string; twoFactorAuthentication?: boolean; otpSecret?: string }
) {
const creds = credentials || subuserUsernameCredentials;
await page.goto("/login/driver");
await page.click('button[id="subuser_login_method_username_button"]');
await page.waitForSelector('input[name="username"]');
await page.waitForSelector('input[name="password"]');
await page.fill('input[name="username"]', creds.username);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="subuser-login-button"]');
// If two-factor authentication is enabled, wait for OTP input
if (creds.twoFactorAuthentication) {
await page.waitForSelector('input[name="2fa_code"]');
// Generate OTP using secret
await page.fill('input[name="2fa_code"]', generateOTP(creds.otpSecret!));
await page.click('button[id="2fa-verify-button"]');
}
await expect(page).toHaveURL(USER_HOME_URL, { timeout: AUTH_TIMEOUT });
}
/**
* Login as an operator (by user ID)
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to operatorCredentials)
*/
export async function loginAsOperator(page: Page, credentials?: { userId: string; password: string }) {
const creds = credentials || operatorCredentials;
await page.goto("/admin/login");
await page.fill('input[name="user_id"]', creds.userId);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="operator_login_button"]');
await expect(page).toHaveURL(ADMIN_HOME_URL, { timeout: AUTH_TIMEOUT });
}
/**
* Navigate to user login page without logging in
* Useful for testing login failures
* @param page - Playwright page object
*/
export async function goToUserLogin(page: Page) {
await page.goto("/login");
}
/**
* Navigate to subuser/driver login page without logging in
* @param page - Playwright page object
*/
export async function goToSubuserLogin(page: Page) {
await page.goto("/login/driver");
}
/**
* Navigate to operator login page without logging in
* @param page - Playwright page object
*/
export async function goToOperatorLogin(page: Page) {
await page.goto("/admin/login");
}
/**
* Login as user and trigger 2FA verification screen
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to user2FACredentials)
*/
export async function loginAsUserWith2FA(page: Page, credentials?: { customerNumber: string; password: string }) {
const creds = credentials || user2FACredentials;
await page.goto("/login");
await page.fill('input[name="customer_number"]', creds.customerNumber);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="login-button"]');
// Wait for 2FA verification screen
await expect(page.locator('input[name="2fa_code"]')).toBeVisible({ timeout: AUTH_TIMEOUT });
}
/**
* Complete 2FA verification with a code
* @param page - Playwright page object
* @param code - The 6-digit 2FA code
*/
export async function verify2FACode(page: Page, code: string) {
await page.fill('input[name="2fa_code"]', code);
await page.click('button[id="2fa-verify-button"]');
}
/**
* Cancel 2FA verification and return to login
* @param page - Playwright page object
*/
export async function cancel2FA(page: Page) {
await page.click('button:has-text("Back to login"), button:has-text("Tilbage til login")');
}
/**
* Login as subuser and trigger 2FA verification screen
* @param page - Playwright page object
* @param credentials - Optional custom credentials (defaults to subuser2FACredentials)
*/
export async function loginAsSubuserWith2FA(
page: Page,
credentials?: { phoneCountryCode: string; phone: string; password: string }
) {
const creds = credentials || subuser2FACredentials;
await page.goto("/login/driver");
await page.fill('input[name="phone_country_code"]', creds.phoneCountryCode);
await page.fill('input[name="phone"]', creds.phone);
await page.fill('input[name="password"]', creds.password);
await page.click('button[id="subuser-login-button"]');
// Wait for 2FA verification screen
await expect(page.locator('input[name="2fa_code"]')).toBeVisible({ timeout: AUTH_TIMEOUT });
}
/**
* Check if passkey login button is visible
* @param page - Playwright page object
* @returns boolean - true if passkey button is visible
*/
export async function isPasskeyButtonVisible(page: Page): Promise<boolean> {
return await page.locator('button[id="passkey-login-button"]').isVisible();
}
/**
* Login using QR code authentication token
* @param page - Playwright page object
* @param token - Optional QR auth token (defaults to qrAuthToken from testData)
*/
export async function loginWithQRCode(page: Page, token?: string) {
const authToken = token || qrAuthToken;
if (!authToken) {
throw new Error("QR auth token is not set. Set PLENO_QR_TOKEN environment variable or pass token directly.");
}
await page.goto(`/login/qr?token=${authToken}`);
await expect(page).toHaveURL(USER_HOME_URL, { timeout: AUTH_TIMEOUT });
}
/**
* Navigate to QR code login page without authenticating
* Useful for testing QR code scanning UI
* @param page - Playwright page object
*/
export async function goToQRCodeLogin(page: Page) {
await page.goto("/login/qr");
}
/**
* Attempt QR code login with invalid token
* Useful for testing error handling
* @param page - Playwright page object
* @param invalidToken - Invalid token to test with
*/
export async function attemptInvalidQRCodeLogin(page: Page, invalidToken: string = "invalid-token") {
await page.goto(`/login/qr?token=${invalidToken}`);
}