nxtgauge-frontend-solid/tests/e2e/helpers/gender-combobox.ts

153 lines
5.3 KiB
TypeScript

import { type Page, type Locator } from '@playwright/test';
/**
* Select a gender option from the gender combobox using keyboard navigation (ArrowDown + Enter).
* Works with both native <select> elements and custom combobox inputs.
*
* @param page - Playwright page object
* @param genderValue - One of: "Male", "Female", "Other", "Prefer not to say"
*/
export async function selectGenderWithKeyboard(page: Page, genderValue: string): Promise<void> {
// Find the gender select or input (try multiple selectors)
const genderSelect = page.locator('select').filter({ hasText: /gender/i }).or(
page.locator('select').filter({ has: page.locator('option[value="Male"]') })
);
const genderInput = page.locator('input[placeholder*="gender" i], input[placeholder*="Select" i]');
const selectVisible = await genderSelect.isVisible().catch(() => false);
const inputVisible = await genderInput.isVisible().catch(() => false);
if (selectVisible) {
// Native <select> - use selectOption as fallback if keyboard doesn't work
const optionValues: Record<string, string> = {
'Male': 'Male',
'Female': 'Female',
'Other': 'Other',
'Prefer not to say': 'Prefer not to say',
};
const value = optionValues[genderValue];
if (value) {
await genderSelect.selectOption(value);
}
} else if (inputVisible) {
// Custom combobox input - click to open dropdown
await genderInput.click();
// Build the option selector based on the gender value
// For DashboardDesignPreview-style dropdowns, options appear in a list
// Try to find and click the matching option
const optionLocator = page.locator(`text="${genderValue}"`).first();
const optionVisible = await optionLocator.isVisible().catch(() => false);
if (optionVisible) {
await optionLocator.click();
} else {
// Fallback: type the value and press Enter
await genderInput.fill(genderValue);
await genderInput.press('Enter');
}
}
}
/**
* Select a gender option using direct JavaScript value injection via page.evaluate.
* This bypasses the UI and directly sets the value in the DOM/state.
*
* @param page - Playwright page object
* @param genderValue - One of: "Male", "Female", "Other", "Prefer not to say"
* @param fieldKey - The field key, defaults to "gender"
*/
export async function setGenderViaJS(page: Page, genderValue: string, fieldKey = 'gender'): Promise<void> {
// Try native select first
const nativeSelectWorked = await page.evaluate((value: string) => {
const selects = Array.from(document.querySelectorAll('select'));
for (const sel of selects) {
const options = Array.from(sel.options).map((o: HTMLOptionElement) => o.value);
if (options.includes(value)) {
sel.value = value;
sel.dispatchEvent(new Event('change', { bubbles: true }));
return true;
}
}
return false;
}, genderValue);
if (!nativeSelectWorked) {
// Try custom combobox - inject into input value and trigger input event
await page.evaluate((value: string) => {
const inputs = Array.from(document.querySelectorAll('input'));
for (const input of inputs) {
const placeholder = input.getAttribute('placeholder') || '';
if (placeholder.toLowerCase().includes('gender') || placeholder.toLowerCase().includes('select')) {
input.value = value;
input.dispatchEvent(new Event('input', { bubbles: true }));
input.dispatchEvent(new Event('change', { bubbles: true }));
return;
}
}
}, genderValue);
}
}
/**
* Select gender using keyboard ArrowDown + Enter sequence.
* This is the preferred approach for custom comboboxes.
*
* @param page - Playwright page object
* @param genderValue - The gender option to select
*/
export async function selectGenderArrowDownEnter(page: Page, genderValue: string): Promise<void> {
// Find gender field - try select first, then input
let genderField: Locator | null = null;
let isSelect = false;
try {
const selectLocator = page.locator('select');
if (await selectLocator.isVisible()) {
genderField = selectLocator;
isSelect = true;
}
} catch {
// not visible
}
if (!genderField) {
// Try input with placeholder matching gender or Select
const inputs = page.locator('input');
const count = await inputs.count();
for (let i = 0; i < count; i++) {
const input = inputs.nth(i);
const placeholder = await input.getAttribute('placeholder').catch(() => '');
if (placeholder && (placeholder.toLowerCase().includes('gender') || placeholder.toLowerCase().includes('select'))) {
if (await input.isVisible()) {
genderField = input;
break;
}
}
}
}
if (!genderField) {
throw new Error('Gender field not found on page');
}
if (isSelect) {
// For native select: click to focus, then ArrowDown + Enter
await genderField.click();
await genderField.press('ArrowDown');
await genderField.press('Enter');
} else {
// For custom combobox: click to open dropdown list
await genderField.click();
// Wait briefly for dropdown to appear
await page.waitForTimeout(300);
// Press ArrowDown to navigate to the option
await genderField.press('ArrowDown');
// Press Enter to select
await genderField.press('Enter');
}
}