ee044d03e0
- Add /health endpoint with anonymous access for monitoring - Add FileUploadResult<T> model and PostMultipartForFileResultAsync for proper upload response handling - Add ApiResult.Success() factory method for interface types - Refactor Login.razor for cleaner code - Add comprehensive Playwright E2E test suite with fixtures and helpers
238 lines
7.0 KiB
TypeScript
238 lines
7.0 KiB
TypeScript
import { Page } from '@playwright/test';
|
|
|
|
/**
|
|
* Configuration for autocomplete filter panels
|
|
*/
|
|
export interface AutocompleteConfig {
|
|
/** Panel header text to identify the panel */
|
|
panelHeader: string;
|
|
/** Minimum characters to trigger search */
|
|
minSearchLength: number;
|
|
/** Column to check for duplicates */
|
|
keyColumn: string;
|
|
}
|
|
|
|
/**
|
|
* Profit Center autocomplete configuration
|
|
*/
|
|
export const profitCenterConfig: AutocompleteConfig = {
|
|
panelHeader: 'Filter by Profit Center',
|
|
minSearchLength: 3,
|
|
keyColumn: 'Code',
|
|
};
|
|
|
|
/**
|
|
* Work Center autocomplete configuration
|
|
*/
|
|
export const workCenterConfig: AutocompleteConfig = {
|
|
panelHeader: 'Filter by Work Center',
|
|
minSearchLength: 3,
|
|
keyColumn: 'Work Center',
|
|
};
|
|
|
|
/**
|
|
* Operator autocomplete configuration
|
|
*/
|
|
export const operatorConfig: AutocompleteConfig = {
|
|
panelHeader: 'Filter by Operator',
|
|
minSearchLength: 3,
|
|
keyColumn: 'User ID',
|
|
};
|
|
|
|
/**
|
|
* Add an item via autocomplete search
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
* @param searchText - Text to search for (must be >= minSearchLength)
|
|
*/
|
|
export async function addAutocompleteItem(
|
|
page: Page,
|
|
config: AutocompleteConfig,
|
|
searchText: string
|
|
): Promise<void> {
|
|
// Find the panel by its header
|
|
const panel = page.locator(`.rz-card:has-text("${config.panelHeader}")`);
|
|
|
|
// Find the autocomplete input within the panel
|
|
const autocomplete = panel.locator('.rz-autocomplete input');
|
|
|
|
// Clear and type the search text
|
|
await autocomplete.clear();
|
|
await autocomplete.fill(searchText);
|
|
|
|
// Wait for search results to appear
|
|
await page.waitForTimeout(500);
|
|
|
|
// Click the first matching result in the dropdown
|
|
const dropdown = page.locator('.rz-autocomplete-list');
|
|
if (await dropdown.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
await dropdown.locator('.rz-autocomplete-list-item').first().click();
|
|
await page.waitForTimeout(300);
|
|
}
|
|
|
|
// Click the Add button
|
|
await panel.locator('button:has-text("Add")').click();
|
|
await page.waitForTimeout(300);
|
|
}
|
|
|
|
/**
|
|
* Add multiple items via autocomplete
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
* @param searchTexts - Array of search texts
|
|
*/
|
|
export async function addMultipleAutocompleteItems(
|
|
page: Page,
|
|
config: AutocompleteConfig,
|
|
searchTexts: string[]
|
|
): Promise<void> {
|
|
for (const text of searchTexts) {
|
|
await addAutocompleteItem(page, config, text);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an item from the autocomplete list by clicking its delete button
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
* @param rowIndex - The zero-based row index to remove
|
|
*/
|
|
export async function removeAutocompleteItem(
|
|
page: Page,
|
|
config: AutocompleteConfig,
|
|
rowIndex: number
|
|
): Promise<void> {
|
|
const panel = page.locator(`.rz-card:has-text("${config.panelHeader}")`);
|
|
const grid = panel.locator('.rz-data-grid');
|
|
const rows = grid.locator('tbody tr');
|
|
|
|
// Click the delete button in the specified row
|
|
await rows.nth(rowIndex).locator('button:has-text("Delete")').click();
|
|
await page.waitForTimeout(300);
|
|
}
|
|
|
|
/**
|
|
* Clear all items from the autocomplete panel
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
*/
|
|
export async function clearAutocompleteItems(
|
|
page: Page,
|
|
config: AutocompleteConfig
|
|
): Promise<void> {
|
|
const panel = page.locator(`.rz-card:has-text("${config.panelHeader}")`);
|
|
const clearButton = panel.locator('button:has-text("Clear Data")');
|
|
|
|
if (await clearButton.isVisible({ timeout: 2000 }).catch(() => false)) {
|
|
await clearButton.click();
|
|
|
|
// Wait for and confirm the dialog
|
|
await page.waitForSelector('text=Confirm Clear', { timeout: 5000 });
|
|
await page.locator('button:has-text("OK")').click();
|
|
await page.waitForTimeout(500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the count of items in the autocomplete panel
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
* @returns Number of items in the grid
|
|
*/
|
|
export async function getAutocompleteItemCount(
|
|
page: Page,
|
|
config: AutocompleteConfig
|
|
): Promise<number> {
|
|
const panel = page.locator(`.rz-card:has-text("${config.panelHeader}")`);
|
|
const grid = panel.locator('.rz-data-grid');
|
|
|
|
// Check for "No records" message
|
|
const noRecords = grid.locator('text=No records to display');
|
|
if (await noRecords.isVisible({ timeout: 1000 }).catch(() => false)) {
|
|
return 0;
|
|
}
|
|
|
|
const rows = grid.locator('tbody tr');
|
|
return await rows.count();
|
|
}
|
|
|
|
/**
|
|
* Check if the autocomplete panel is visible
|
|
* @param page - Playwright page object
|
|
* @param config - Autocomplete configuration
|
|
* @returns true if panel is visible
|
|
*/
|
|
export async function isAutocompletePanelVisible(
|
|
page: Page,
|
|
config: AutocompleteConfig
|
|
): Promise<boolean> {
|
|
const panel = page.locator(`text=${config.panelHeader}`);
|
|
return await panel.isVisible({ timeout: 2000 }).catch(() => false);
|
|
}
|
|
|
|
/**
|
|
* Add a profit center
|
|
* @param page - Playwright page object
|
|
* @param code - Profit center code (e.g., "1AM")
|
|
*/
|
|
export async function addProfitCenter(page: Page, code: string): Promise<void> {
|
|
await addAutocompleteItem(page, profitCenterConfig, code);
|
|
}
|
|
|
|
/**
|
|
* Add multiple profit centers
|
|
* @param page - Playwright page object
|
|
* @param codes - Array of profit center codes
|
|
*/
|
|
export async function addProfitCenters(page: Page, codes: string[]): Promise<void> {
|
|
await addMultipleAutocompleteItems(page, profitCenterConfig, codes);
|
|
}
|
|
|
|
/**
|
|
* Add a work center
|
|
* @param page - Playwright page object
|
|
* @param code - Work center code
|
|
*/
|
|
export async function addWorkCenter(page: Page, code: string): Promise<void> {
|
|
await addAutocompleteItem(page, workCenterConfig, code);
|
|
}
|
|
|
|
/**
|
|
* Add multiple work centers
|
|
* @param page - Playwright page object
|
|
* @param codes - Array of work center codes
|
|
*/
|
|
export async function addWorkCenters(page: Page, codes: string[]): Promise<void> {
|
|
await addMultipleAutocompleteItems(page, workCenterConfig, codes);
|
|
}
|
|
|
|
/**
|
|
* Add an operator
|
|
* @param page - Playwright page object
|
|
* @param userId - Operator user ID (e.g., "ADAMSSN")
|
|
*/
|
|
export async function addOperator(page: Page, userId: string): Promise<void> {
|
|
await addAutocompleteItem(page, operatorConfig, userId);
|
|
}
|
|
|
|
/**
|
|
* Add multiple operators
|
|
* @param page - Playwright page object
|
|
* @param userIds - Array of operator user IDs
|
|
*/
|
|
export async function addOperators(page: Page, userIds: string[]): Promise<void> {
|
|
await addMultipleAutocompleteItems(page, operatorConfig, userIds);
|
|
}
|
|
|
|
/**
|
|
* Common test data for autocomplete panels
|
|
*/
|
|
export const TestAutocompleteData = {
|
|
profitCenters: ['1AM', '1BM', '1CM', '1PM', '2DM', '2SM', '3TM', '4IM', '5SM'],
|
|
workCenters: ['WC001', 'WC002', 'WC003'],
|
|
operators: [
|
|
'ADAMSSN', 'AGNEWA', 'AGNEWL', 'ALASMARB', 'ALEXIUCG',
|
|
'ALLENHY', 'ALLENNI', 'ALURUM', 'ALVESM1', 'APONTEVE',
|
|
],
|
|
} as const;
|