153 lines
5.3 KiB
TypeScript
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');
|
|
}
|
|
}
|