fix: Update login form selectors to match actual page structure

- Updated LoginPage selectors to use more robust input[name] selectors instead of id-based
- Added better error handling and message detection
- Enhanced form waiting for better reliability
- Created debug test scripts to verify selector functionality
- Fixed isLoginFormVisible reference in trainer journey test

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
bengizmo 2025-05-21 20:21:16 -03:00
parent 7ac4d4b853
commit d1f1005a5a
4 changed files with 215 additions and 37 deletions

View file

@ -0,0 +1,113 @@
import { test, expect } from '@playwright/test';
import { STAGING_URL } from './config/staging-config';
test('Debug login page', async ({ page }) => {
console.log('Starting login page debug');
// Navigate to the login page
console.log('Navigating to login page...');
await page.goto(`${STAGING_URL}/community-login/`, { waitUntil: 'networkidle' });
console.log(`Current URL: ${page.url()}`);
// Take screenshot of the page
await page.screenshot({ path: 'screenshots/login-page.png' });
console.log('Screenshot saved to screenshots/login-page.png');
// Get page title
const title = await page.title();
console.log(`Page title: ${title}`);
// Check for redirects
if (!page.url().includes('community-login')) {
console.log(`⚠️ Page was redirected to: ${page.url()}`);
}
// Check for iframes
const iframes = await page.$$('iframe');
console.log(`Number of iframes: ${iframes.length}`);
// Dump HTML content
const html = await page.content();
console.log('First 500 chars of HTML:');
console.log(html.substring(0, 500));
// Look for common login form elements with various selectors
const selectors = [
'#user_login',
'#username',
'input[name="log"]',
'input[name="username"]',
'#user_pass',
'#password',
'input[name="pwd"]',
'input[name="password"]',
'#wp-submit',
'input[type="submit"]',
'button[type="submit"]'
];
console.log('\nChecking for form elements:');
for (const selector of selectors) {
const count = await page.$$eval(selector, (elements) => elements.length).catch(() => 0);
if (count > 0) {
console.log(`✅ Found ${count} elements matching selector: ${selector}`);
const element = await page.$(selector);
if (element) {
const tagName = await element.evaluate(el => el.tagName).catch(() => 'Unknown');
const type = await element.evaluate(el => el.getAttribute('type')).catch(() => 'Unknown');
const name = await element.evaluate(el => el.getAttribute('name')).catch(() => 'Unknown');
const id = await element.evaluate(el => el.getAttribute('id')).catch(() => 'Unknown');
console.log(` Tag: ${tagName}, Type: ${type}, Name: ${name}, ID: ${id}`);
}
} else {
console.log(`❌ No elements found for selector: ${selector}`);
}
}
// Check for error containers
const errorSelectors = [
'.login-error',
'#login_error',
'.login_error',
'.notice-error',
'.woocommerce-error',
'.wp-die-message'
];
console.log('\nChecking for error containers:');
for (const selector of errorSelectors) {
const count = await page.$$eval(selector, (elements) => elements.length).catch(() => 0);
console.log(`${selector}: ${count > 0 ? '✅ Found' : '❌ Not found'}`);
}
// Output all forms on the page
const forms = await page.$$('form');
console.log(`\nNumber of forms: ${forms.length}`);
for (let i = 0; i < forms.length; i++) {
const form = forms[i];
const action = await form.evaluate(f => f.getAttribute('action') || 'No action').catch(() => 'Unknown');
const method = await form.evaluate(f => f.getAttribute('method') || 'No method').catch(() => 'Unknown');
const id = await form.evaluate(f => f.getAttribute('id') || 'No id').catch(() => 'Unknown');
const className = await form.evaluate(f => f.getAttribute('class') || 'No class').catch(() => 'Unknown');
console.log(`\nForm #${i+1}:`);
console.log(` ID: ${id}`);
console.log(` Class: ${className}`);
console.log(` Action: ${action}`);
console.log(` Method: ${method}`);
// Get inputs in the form
const inputs = await form.$$('input');
console.log(` Inputs: ${inputs.length}`);
for (const input of inputs) {
const type = await input.evaluate(i => i.getAttribute('type') || 'No type').catch(() => 'Unknown');
const name = await input.evaluate(i => i.getAttribute('name') || 'No name').catch(() => 'Unknown');
const id = await input.evaluate(i => i.getAttribute('id') || 'No id').catch(() => 'Unknown');
console.log(` Input: Type=${type}, Name=${name}, ID=${id}`);
}
}
console.log('\nLogin page debug complete');
});

View file

@ -1,48 +1,63 @@
import { test, expect } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';
import { DashboardPage } from './pages/DashboardPage';
test.describe('Login Flow', () => {
test('should show error on login page', async ({ page }) => {
test('should login with valid credentials', async ({ page }) => {
// Constants
const testTrainerUsername = 'test_trainer';
const testTrainerPassword = 'Test123!';
// Create a login page instance
const loginPage = new LoginPage(page);
// Navigate to login page
await page.goto('/community-login/');
await page.waitForLoadState('networkidle');
await loginPage.navigate();
// Save a screenshot before login
await page.screenshot({ path: 'login-page-before.png' });
await page.screenshot({ path: 'screenshots/login-page-before.png' });
// Dump the HTML content of the login form
const loginFormHTML = await page.locator('#loginform').innerHTML();
console.log('Login form HTML:', loginFormHTML);
// Verify login form is visible
expect(await loginPage.isUsernameFieldVisible()).toBeTruthy();
// Fill login form
await page.fill('#user_login', testTrainerUsername);
await page.fill('#user_pass', testTrainerPassword);
await page.click('#wp-submit');
// Login with valid credentials
await loginPage.login(testTrainerUsername, testTrainerPassword);
// Wait for navigation
await page.waitForTimeout(2000);
await page.waitForLoadState('networkidle');
// Check if we're logged in by looking for dashboard elements
await page.screenshot({ path: 'login-result.png' });
// Check if logged in
const isLoggedIn = await loginPage.isLoggedIn();
console.log(`Is logged in: ${isLoggedIn}`);
// Print current URL and page title for debugging
console.log('Current URL after login:', page.url());
// Take a screenshot of the result
await page.screenshot({ path: 'screenshots/login-success.png' });
// Dump any error messages
const errorHTML = await page.locator('.login-error, .message, #login_error').innerHTML().catch(() => 'No error element found');
console.log('Login error message:', errorHTML);
// Print current URL for debugging
const currentUrl = await page.url();
console.log('Current URL after login:', currentUrl);
// Instead of checking login success, check if an error is displayed
const hasError = await page.locator('.login-error, .message, #login_error').isVisible();
console.log('Has error displayed:', hasError);
// Verify login was successful
expect(isLoggedIn).toBeTruthy();
});
test('should show error with invalid credentials', async ({ page }) => {
// Create a login page instance
const loginPage = new LoginPage(page);
// Accept any result - we're just debugging
expect(true).toBeTruthy();
// Navigate to login page
await loginPage.navigate();
// Login with invalid credentials
await loginPage.login('invalid_user', 'wrong_password');
// Check for error message
const errorMessage = await loginPage.getErrorMessage();
console.log(`Error message: ${errorMessage}`);
// Take a screenshot of the error
await page.screenshot({ path: 'screenshots/login-error.png' });
// Expect an error message
expect(errorMessage).not.toBeNull();
});
});

View file

@ -6,13 +6,14 @@ import { PATHS } from '../config/staging-config';
* Page object representing the login page
*/
export class LoginPage extends BasePage {
// Login form elements
private readonly usernameInput = '#user_login';
private readonly passwordInput = '#user_pass';
private readonly loginButton = '#wp-submit';
private readonly rememberMeCheckbox = '#rememberme';
private readonly loginError = '.login-error, .login_error';
private readonly forgotPasswordLink = 'a.forgot-password, a:text("Lost your password?")';
// 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);
@ -22,8 +23,12 @@ export class LoginPage extends BasePage {
* Navigate to the login page
*/
async navigate(): Promise<void> {
this.log('Navigating to login page');
await this.page.goto(PATHS.login);
await this.page.waitForSelector(this.usernameInput);
await this.page.waitForLoadState('networkidle');
// Make sure the form is visible before proceeding
await this.page.waitForSelector(this.loginForm, { timeout: 10000 });
}
/**
@ -40,16 +45,28 @@ export class LoginPage extends BasePage {
*/
async login(username: string, password: string): Promise<void> {
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<boolean> {
await this.page.waitForLoadState('networkidle');
const url = await this.getUrl();
return url.includes('hvac-dashboard');
}
@ -58,16 +75,49 @@ export class LoginPage extends BasePage {
* Check if username field is visible
*/
async isUsernameFieldVisible(): Promise<boolean> {
return await this.page.isVisible(this.usernameInput);
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<string | null> {
if (await this.page.isVisible(this.loginError)) {
return await this.page.textContent(this.loginError);
// 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;
}

View file

@ -35,7 +35,7 @@ test.describe('Trainer User Journey', () => {
await expect(page).toHaveURL(/.*community-login/);
// Verify login form is visible
expect(await loginPage.isLoginFormVisible()).toBe(true);
expect(await loginPage.isUsernameFieldVisible()).toBe(true);
// Login with test trainer credentials
await loginPage.login(trainer.username, trainer.password);