- Add HVAC_Test_User_Factory class with: * User creation with specific roles * Multiple role support * Persona management system * Account cleanup integration - Create comprehensive test suite in HVAC_Test_User_Factory_Test.php - Update testing improvement plan documentation - Add implementation decisions to project memory bank - Restructure .gitignore with: * Whitelist approach for better file management * Explicit backup exclusions * Specific bin directory inclusions Part of the Account Management component from the testing framework improvement plan.
138 lines
No EOL
5.3 KiB
TypeScript
138 lines
No EOL
5.3 KiB
TypeScript
import { Page, expect } from '@playwright/test';
|
|
|
|
export class RegistrationPage {
|
|
readonly page: Page;
|
|
private readonly selectors = {
|
|
// Personal Information
|
|
firstNameInput: '#first_name',
|
|
lastNameInput: '#last_name',
|
|
emailInput: '#email',
|
|
passwordInput: '#password',
|
|
displayNameInput: '#display_name',
|
|
profileImageInput: '#profile_image',
|
|
|
|
// Business Information
|
|
businessNameInput: '#business_name',
|
|
businessPhoneInput: '#business_phone',
|
|
businessEmailInput: '#business_email',
|
|
countrySelect: '#country',
|
|
stateSelect: '#state',
|
|
cityInput: '#city',
|
|
businessTypeSelect: '#business_type',
|
|
|
|
// Training Information
|
|
trainingAudienceSelect: '#training_audience',
|
|
trainingFormatsSelect: '#training_formats',
|
|
trainingLocationsSelect: '#training_locations',
|
|
trainingResourcesSelect: '#training_resources',
|
|
applicationDetailsTextarea: '#application_details',
|
|
|
|
// Form Controls
|
|
submitButton: '#submit-registration',
|
|
errorMessages: '.error-message',
|
|
successMessage: '.success-message'
|
|
};
|
|
|
|
constructor(page: Page) {
|
|
this.page = page;
|
|
}
|
|
|
|
async navigate() {
|
|
await this.page.goto('/community-registration/');
|
|
}
|
|
|
|
async fillPersonalInfo(data: {
|
|
firstName: string,
|
|
lastName: string,
|
|
email: string,
|
|
password: string,
|
|
displayName: string
|
|
}) {
|
|
await this.page.fill(this.selectors.firstNameInput, data.firstName);
|
|
await this.page.fill(this.selectors.lastNameInput, data.lastName);
|
|
await this.page.fill(this.selectors.emailInput, data.email);
|
|
await this.page.fill(this.selectors.passwordInput, data.password);
|
|
await this.page.fill(this.selectors.displayNameInput, data.displayName);
|
|
}
|
|
|
|
async fillBusinessInfo(data: {
|
|
businessName: string,
|
|
businessPhone: string,
|
|
businessEmail: string,
|
|
country: string,
|
|
state: string,
|
|
city: string,
|
|
businessType: string
|
|
}) {
|
|
await this.page.fill(this.selectors.businessNameInput, data.businessName);
|
|
await this.page.fill(this.selectors.businessPhoneInput, data.businessPhone);
|
|
await this.page.fill(this.selectors.businessEmailInput, data.businessEmail);
|
|
await this.page.selectOption(this.selectors.countrySelect, data.country);
|
|
await this.page.waitForTimeout(500); // Wait for state dropdown to update
|
|
await this.page.selectOption(this.selectors.stateSelect, data.state);
|
|
await this.page.fill(this.selectors.cityInput, data.city);
|
|
await this.page.selectOption(this.selectors.businessTypeSelect, data.businessType);
|
|
}
|
|
|
|
async fillTrainingInfo(data: {
|
|
audience: string[],
|
|
formats: string[],
|
|
locations: string[],
|
|
resources: string[],
|
|
details: string
|
|
}) {
|
|
await this.page.selectOption(this.selectors.trainingAudienceSelect, data.audience);
|
|
await this.page.selectOption(this.selectors.trainingFormatsSelect, data.formats);
|
|
await this.page.selectOption(this.selectors.trainingLocationsSelect, data.locations);
|
|
await this.page.selectOption(this.selectors.trainingResourcesSelect, data.resources);
|
|
await this.page.fill(this.selectors.applicationDetailsTextarea, data.details);
|
|
}
|
|
|
|
async uploadProfileImage(filePath: string) {
|
|
const input = await this.page.$(this.selectors.profileImageInput);
|
|
if (input) {
|
|
await input.setInputFiles(filePath);
|
|
}
|
|
}
|
|
|
|
async submitForm() {
|
|
await this.page.click(this.selectors.submitButton);
|
|
}
|
|
|
|
async verifyErrorMessage(expectedError: string) {
|
|
const errorElement = await this.page.waitForSelector(this.selectors.errorMessages);
|
|
const errorText = await errorElement.textContent();
|
|
expect(errorText?.toLowerCase()).toContain(expectedError.toLowerCase());
|
|
}
|
|
|
|
async verifySuccessfulRegistration() {
|
|
await this.page.waitForSelector(this.selectors.successMessage);
|
|
const currentUrl = this.page.url();
|
|
expect(currentUrl).toContain('/registration-success');
|
|
}
|
|
|
|
async verifyPasswordComplexity(password: string): Promise<boolean> {
|
|
const hasUpperCase = /[A-Z]/.test(password);
|
|
const hasLowerCase = /[a-z]/.test(password);
|
|
const hasNumber = /[0-9]/.test(password);
|
|
const isLongEnough = password.length >= 8;
|
|
|
|
return hasUpperCase && hasLowerCase && hasNumber && isLongEnough;
|
|
}
|
|
|
|
async verifyCountryStateLogic() {
|
|
// Verify US/Canada states at top
|
|
await this.page.selectOption(this.selectors.countrySelect, 'US');
|
|
let states = await this.page.$$eval(this.selectors.stateSelect + ' option',
|
|
(options: HTMLOptionElement[]) => options.map(opt => opt.value)
|
|
);
|
|
expect(states[1]).toMatch(/^(US-|CA-)/); // First state should be US or CA (after default option)
|
|
|
|
// Verify "Other" option for non-US/Canada
|
|
await this.page.selectOption(this.selectors.countrySelect, 'FR');
|
|
states = await this.page.$$eval(this.selectors.stateSelect + ' option',
|
|
(options: HTMLOptionElement[]) => options.map(opt => opt.value)
|
|
);
|
|
expect(states).toContain('OTHER');
|
|
}
|
|
} |