Migrate Playwright suite to .NET UI tests and deprecate TS project
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
import { Page, expect, Locator } from '@playwright/test';
|
||||
|
||||
/**
|
||||
* Check if a form field has a validation error
|
||||
* @param page - Playwright page object
|
||||
* @param fieldName - The name attribute of the field
|
||||
* @returns true if field has validation error styling
|
||||
*/
|
||||
export async function fieldHasError(page: Page, fieldName: string): Promise<boolean> {
|
||||
const field = page.locator(`[name="${fieldName}"]`);
|
||||
const classes = await field.getAttribute('class') ?? '';
|
||||
|
||||
// Radzen validation error class
|
||||
return classes.includes('rz-state-invalid') || classes.includes('invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the validation summary has any errors
|
||||
* @param page - Playwright page object
|
||||
* @returns true if validation errors are present
|
||||
*/
|
||||
export async function hasValidationErrors(page: Page): Promise<boolean> {
|
||||
// Check for Radzen error notifications (Validation Error notifications)
|
||||
const errorNotification = page.locator('.rz-notification-error:has-text("Validation Error")');
|
||||
if (await errorNotification.isVisible({ timeout: 1000 }).catch(() => false)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for Radzen validation summary
|
||||
const validationSummary = page.locator('.rz-validation-summary');
|
||||
if (await validationSummary.isVisible({ timeout: 1000 }).catch(() => false)) {
|
||||
const errors = validationSummary.locator('.validation-message, .rz-message');
|
||||
const count = await errors.count();
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
// Check for standard validation messages
|
||||
const validationMessages = page.locator('.validation-message');
|
||||
return (await validationMessages.count()) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all validation error messages
|
||||
* @param page - Playwright page object
|
||||
* @returns Array of error message texts
|
||||
*/
|
||||
export async function getValidationErrors(page: Page): Promise<string[]> {
|
||||
const errors: string[] = [];
|
||||
|
||||
// Get errors from notification toasts (Validation Error notifications)
|
||||
const notificationErrors = page.locator('.rz-notification-error');
|
||||
const notificationCount = await notificationErrors.count();
|
||||
for (let i = 0; i < notificationCount; i++) {
|
||||
const notification = notificationErrors.nth(i);
|
||||
// Check if it's a validation error notification
|
||||
const title = await notification.locator('div').first().textContent() ?? '';
|
||||
if (title.includes('Validation Error')) {
|
||||
// Get the message (second div in the notification)
|
||||
const message = await notification.locator('div').nth(1).textContent();
|
||||
if (message) errors.push(message.trim());
|
||||
}
|
||||
}
|
||||
|
||||
// Get errors from validation summary
|
||||
const summaryErrors = page.locator('.rz-validation-summary .validation-message, .rz-validation-summary .rz-message');
|
||||
const summaryCount = await summaryErrors.count();
|
||||
for (let i = 0; i < summaryCount; i++) {
|
||||
const text = await summaryErrors.nth(i).textContent();
|
||||
if (text && !errors.includes(text.trim())) errors.push(text.trim());
|
||||
}
|
||||
|
||||
// Get inline validation messages
|
||||
const inlineErrors = page.locator('.field-validation-error, .validation-message');
|
||||
const inlineCount = await inlineErrors.count();
|
||||
for (let i = 0; i < inlineCount; i++) {
|
||||
const text = await inlineErrors.nth(i).textContent();
|
||||
if (text && !errors.includes(text.trim())) {
|
||||
errors.push(text.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that a specific validation error message is present
|
||||
* @param page - Playwright page object
|
||||
* @param expectedMessage - The expected error message (partial match)
|
||||
*/
|
||||
export async function assertValidationError(page: Page, expectedMessage: string): Promise<void> {
|
||||
const errors = await getValidationErrors(page);
|
||||
const found = errors.some(e => e.toLowerCase().includes(expectedMessage.toLowerCase()));
|
||||
expect(found, `Expected validation error containing "${expectedMessage}" but found: ${errors.join(', ')}`).toBe(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert no validation errors are present
|
||||
* @param page - Playwright page object
|
||||
*/
|
||||
export async function assertNoValidationErrors(page: Page): Promise<void> {
|
||||
const hasErrors = await hasValidationErrors(page);
|
||||
if (hasErrors) {
|
||||
const errors = await getValidationErrors(page);
|
||||
expect(hasErrors, `Expected no validation errors but found: ${errors.join(', ')}`).toBe(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a specific form field is required and shows error when empty
|
||||
* @param page - Playwright page object
|
||||
* @param fieldLocator - Locator for the field
|
||||
* @returns true if field shows required validation
|
||||
*/
|
||||
export async function isFieldRequired(page: Page, fieldLocator: Locator): Promise<boolean> {
|
||||
// Check for required attribute
|
||||
const required = await fieldLocator.getAttribute('required');
|
||||
if (required !== null) return true;
|
||||
|
||||
// Check for aria-required attribute
|
||||
const ariaRequired = await fieldLocator.getAttribute('aria-required');
|
||||
return ariaRequired === 'true';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a panel shows a validation message for missing required items
|
||||
* @param page - Playwright page object
|
||||
* @param panelHeader - The header text of the panel
|
||||
* @returns true if panel has validation error
|
||||
*/
|
||||
export async function panelHasValidationError(page: Page, panelHeader: string): Promise<boolean> {
|
||||
const panel = page.locator(`.rz-card:has-text("${panelHeader}")`);
|
||||
const validationMessage = panel.locator('.validation-message, .rz-message-error, .text-danger');
|
||||
return await validationMessage.isVisible({ timeout: 1000 }).catch(() => false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for validation to complete (after form submission attempt)
|
||||
* @param page - Playwright page object
|
||||
* @param timeout - Maximum time to wait (default: 2000ms)
|
||||
*/
|
||||
export async function waitForValidation(page: Page, timeout: number = 2000): Promise<void> {
|
||||
await page.waitForTimeout(timeout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Submit button is enabled (form is valid)
|
||||
* @param page - Playwright page object
|
||||
* @returns true if submit button is enabled
|
||||
*/
|
||||
export async function isSubmitEnabled(page: Page): Promise<boolean> {
|
||||
const submitButton = page.locator('button:has-text("Submit Search")');
|
||||
return !(await submitButton.isDisabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to submit and expect validation failure
|
||||
* @param page - Playwright page object
|
||||
* @param expectedError - Expected error message (partial match)
|
||||
*/
|
||||
export async function submitAndExpectError(page: Page, expectedError?: string): Promise<void> {
|
||||
await page.locator('button:has-text("Submit Search")').click();
|
||||
await waitForValidation(page);
|
||||
|
||||
expect(await hasValidationErrors(page), 'Expected validation errors after submit').toBe(true);
|
||||
|
||||
if (expectedError) {
|
||||
await assertValidationError(page, expectedError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation error message constants for common scenarios
|
||||
*/
|
||||
export const ValidationMessages = {
|
||||
SEARCH_NAME_REQUIRED: 'Search name is required',
|
||||
SEARCH_TYPE_REQUIRED: 'Search type is required',
|
||||
MIN_DATE_REQUIRED: 'Minimum date is required',
|
||||
MAX_DATE_REQUIRED: 'Maximum date is required',
|
||||
INVALID_DATE_RANGE: 'Minimum date must be before or equal to maximum date',
|
||||
WORK_ORDER_REQUIRED: 'At least one work order is required',
|
||||
PROFIT_CENTER_REQUIRED: 'At least one profit center is required',
|
||||
WORK_CENTER_REQUIRED: 'At least one work center is required',
|
||||
OPERATOR_REQUIRED: 'At least one operator is required',
|
||||
ITEM_NUMBER_REQUIRED: 'At least one item number is required',
|
||||
COMPONENT_LOT_REQUIRED: 'At least one component lot is required',
|
||||
PART_OPERATION_REQUIRED: 'At least one part operation is required',
|
||||
} as const;
|
||||
Reference in New Issue
Block a user