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 { 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 { // 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 { 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 { 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 { 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 { // 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 { 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 { 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 { 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 { 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;