import { Page, expect } from '@playwright/test'; import { BasePage } from './BasePage'; import { PATHS } from '../config/staging-config'; /** * Page object representing the login page */ export class LoginPage extends BasePage { // Login form elements based on debug analysis private readonly usernameInput = 'input[name="log"]'; private readonly passwordInput = 'input[name="pwd"]'; private readonly loginButton = 'input[type="submit"]'; private readonly rememberMeCheckbox = 'input[name="rememberme"]'; private readonly loginError = '.login-error, .login_error, #login_error, .notice-error, .woocommerce-error, .wp-die-message'; private readonly forgotPasswordLink = 'a:text("Lost your password?")'; private readonly loginForm = 'form#hvac_community_loginform'; constructor(page: Page) { super(page); } /** * Navigate to the login page */ async navigate(): Promise { this.log('Navigating to login page'); await this.page.goto(PATHS.login); await this.page.waitForLoadState('networkidle'); // Make sure the form is visible before proceeding await this.page.waitForSelector(this.loginForm, { timeout: 10000 }); } /** * Alternative name for navigate for backward compatibility */ async navigateToLogin(): Promise { await this.navigate(); } /** * Login with provided credentials * @param username Username or email * @param password Password */ async login(username: string, password: string): Promise { this.log(`Logging in as ${username}`); // Wait for form elements to be ready await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 10000 }); await this.page.waitForSelector(this.passwordInput, { state: 'visible', timeout: 5000 }); await this.page.waitForSelector(this.loginButton, { state: 'visible', timeout: 5000 }); // Fill in the credentials await this.page.fill(this.usernameInput, username); await this.page.fill(this.passwordInput, password); // Click login and wait for navigation await this.page.click(this.loginButton); await this.page.waitForLoadState('networkidle'); this.log('Login form submitted'); } /** * Check if we're logged in */ async isLoggedIn(): Promise { await this.page.waitForLoadState('networkidle'); const url = await this.getUrl(); return url.includes('hvac-dashboard'); } /** * Check if username field is visible */ async isUsernameFieldVisible(): Promise { try { await this.page.waitForSelector(this.usernameInput, { state: 'visible', timeout: 5000 }); return true; } catch (error) { return false; } } /** * Get error message if login failed */ async getErrorMessage(): Promise { // Check all possible error selectors const errorSelectors = this.loginError.split(', '); for (const selector of errorSelectors) { if (await this.page.isVisible(selector)) { return await this.page.textContent(selector); } } // Check for any text containing common error messages const pageContent = await this.page.content(); if (pageContent.includes('Invalid username') || pageContent.includes('incorrect password') || pageContent.includes('Unknown username') || pageContent.includes('Error:')) { // Try to find error message in the page content const errorText = await this.page.evaluate(() => { const errorElements = Array.from(document.querySelectorAll('p, div, span')) .filter(el => el.textContent && (el.textContent.includes('Invalid') || el.textContent.includes('Error') || el.textContent.includes('incorrect') || el.textContent.includes('Unknown'))); return errorElements.length > 0 ? errorElements[0].textContent : null; }); return errorText; } return null; } /** * Click on "forgot password" link */ async clickForgotPassword(): Promise { await this.page.click(this.forgotPasswordLink); await this.page.waitForLoadState('networkidle'); } /** * Toggle "remember me" checkbox * @param check If true, check the box; if false, uncheck it */ async setRememberMe(check: boolean): Promise { const isChecked = await this.page.isChecked(this.rememberMeCheckbox); if (check !== isChecked) { await this.page.click(this.rememberMeCheckbox); } } }