import { test, expect } from '@playwright/test'; import { login, logout, isLoggedIn } from '../helpers/auth.helper'; import { navigateToSearchesDashboard, clickNavLink } from '../helpers/navigation.helper'; import { getDataGridRowCount, doubleClickDataGridRow, getBadgeStyle, clickButton, StatusBadgeStyles } from '../helpers/radzen.helper'; test.describe('Searches Dashboard', () => { test.beforeEach(async ({ page }) => { await navigateToSearchesDashboard(page); }); test.describe('Page Load and Display', () => { test('page loads and displays search list heading', async ({ page }) => { // Verify page title await expect(page).toHaveTitle(/Searches - JDE Scoping Tool/); // Verify "Searches" heading is visible await expect(page.locator('h4:has-text("Searches")')).toBeVisible(); }); test('page shows data grid component', async ({ page }) => { // Verify data grid is visible const dataGrid = page.locator('.rz-data-grid'); await expect(dataGrid).toBeVisible({ timeout: 10000 }); }); test('no error notification on page load', async ({ page }) => { // Verify no error notification const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 5000 }); }); }); test.describe('Data Grid Columns', () => { test('data grid shows Name column', async ({ page }) => { const nameHeader = page.locator('.rz-data-grid th:has-text("Name")'); await expect(nameHeader).toBeVisible(); }); test('data grid shows Submitted column', async ({ page }) => { const submittedHeader = page.locator('.rz-data-grid th:has-text("Submitted")'); await expect(submittedHeader).toBeVisible(); }); test('data grid shows Status column', async ({ page }) => { const statusHeader = page.locator('.rz-data-grid th:has-text("Status")'); await expect(statusHeader).toBeVisible(); }); test('data grid shows Actions column', async ({ page }) => { const actionsHeader = page.locator('.rz-data-grid th:has-text("Actions")'); await expect(actionsHeader).toBeVisible(); }); test('all expected columns are present', async ({ page }) => { const headers = page.locator('.rz-data-grid th'); // Get all header texts const headerTexts = await headers.allTextContents(); // Verify expected columns exist expect(headerTexts.some(h => h.includes('Name'))).toBe(true); expect(headerTexts.some(h => h.includes('Submitted'))).toBe(true); expect(headerTexts.some(h => h.includes('Status'))).toBe(true); expect(headerTexts.some(h => h.includes('Actions'))).toBe(true); }); }); test.describe('Action Buttons', () => { test('Start New Search button is visible', async ({ page }) => { const newSearchButton = page.locator('button:has-text("Start New Search")'); await expect(newSearchButton).toBeVisible(); }); test('View Search Queue button is visible', async ({ page }) => { const queueButton = page.locator('button:has-text("View Search Queue")'); await expect(queueButton).toBeVisible(); }); test('clicking Start New Search navigates to search page', async ({ page }) => { await clickButton(page, 'Start New Search'); // Wait for navigation await page.waitForLoadState('networkidle', { timeout: 30000 }); // Should navigate to /search await expect(page).toHaveURL(/\/search$/); }); test('clicking View Search Queue navigates to queue page', async ({ page }) => { await clickButton(page, 'View Search Queue'); // Wait for navigation await page.waitForLoadState('networkidle', { timeout: 30000 }); // Should navigate to /search/queue await expect(page).toHaveURL(/\/search\/queue/); }); }); test.describe('Status Badges', () => { test('status badges display with correct styling for Error status', async ({ page }) => { // Look for any Error badge in the grid const errorBadge = page.locator('.rz-data-grid .rz-badge:has-text("Error")').first(); // If an error badge exists, verify its style if (await errorBadge.isVisible({ timeout: 2000 }).catch(() => false)) { const style = await getBadgeStyle(errorBadge); expect(style).toBe('danger'); } }); test('status badges display with correct styling for Ended status', async ({ page }) => { const endedBadge = page.locator('.rz-data-grid .rz-badge:has-text("Ended")').first(); if (await endedBadge.isVisible({ timeout: 2000 }).catch(() => false)) { const style = await getBadgeStyle(endedBadge); expect(style).toBe('success'); } }); test('status badges display with correct styling for Running status', async ({ page }) => { const runningBadge = page.locator('.rz-data-grid .rz-badge:has-text("Running")').first(); if (await runningBadge.isVisible({ timeout: 2000 }).catch(() => false)) { const style = await getBadgeStyle(runningBadge); expect(style).toBe('info'); } }); test('status badges display with correct styling for Queued status', async ({ page }) => { const queuedBadge = page.locator('.rz-data-grid .rz-badge:has-text("Queued")').first(); if (await queuedBadge.isVisible({ timeout: 2000 }).catch(() => false)) { const style = await getBadgeStyle(queuedBadge); expect(style).toBe('warning'); } }); }); test.describe('Row Interactions', () => { test('View button is present in Actions column', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Check for View button in first row const viewButton = page.locator('.rz-data-grid tbody tr').first().locator('button:has-text("View")'); await expect(viewButton).toBeVisible(); } }); test('clicking View button navigates to search details', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Click View button in first row const viewButton = page.locator('.rz-data-grid tbody tr').first().locator('button:has-text("View")'); await viewButton.click(); // Wait for navigation await page.waitForLoadState('networkidle', { timeout: 30000 }); // Should navigate to /search/{id} await expect(page).toHaveURL(/\/search\/\d+/); } }); test('double-click row navigates to search details', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Double-click first row await doubleClickDataGridRow(page, 0); // Wait for navigation await page.waitForLoadState('networkidle', { timeout: 30000 }); // Should navigate to /search/{id} await expect(page).toHaveURL(/\/search\/\d+/); } }); }); test.describe('Data Grid Features', () => { test('data grid supports sorting', async ({ page }) => { // Click on Name column header to sort const nameHeader = page.locator('.rz-data-grid th:has-text("Name")'); await nameHeader.click(); await page.waitForTimeout(500); // Verify sort indicator appears (ascending or descending) const sortIndicator = page.locator('.rz-data-grid th .rz-sortable-column-icon'); // Just verify the click didn't cause an error const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 2000 }); }); test('data grid supports pagination', async ({ page }) => { // Look for pager component const pager = page.locator('.rz-pager'); // Pager should be visible (may show even with few records) await expect(pager).toBeVisible({ timeout: 5000 }); }); test('data grid supports column resize', async ({ page }) => { // The grid has AllowColumnResize="true" // Verify resize handles exist const resizeHandle = page.locator('.rz-data-grid .rz-resizable-handle'); // If there are any resize handles, the feature is enabled const handleCount = await resizeHandle.count(); // This may be 0 if no columns are resizable in the current view // Just verify no error occurred const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 2000 }); }); }); test.describe('Empty State', () => { test('displays appropriate message when no searches exist', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount === 0) { // Should show "No records to display" or similar message const noRecordsMessage = page.locator('text=No records to display'); await expect(noRecordsMessage).toBeVisible(); } }); }); test.describe('Date Formatting', () => { test('submitted date is formatted correctly (MM/dd/yyyy hh:mm:ss tt)', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Get text from Submitted column (index 1) const submittedCell = page.locator('.rz-data-grid tbody tr').first().locator('td').nth(1); const dateText = await submittedCell.textContent(); if (dateText && dateText.trim()) { // Verify date format matches MM/dd/yyyy hh:mm:ss tt pattern const datePattern = /^\d{2}\/\d{2}\/\d{4} \d{2}:\d{2}:\d{2} (AM|PM)$/; expect(dateText.trim()).toMatch(datePattern); } } }); }); });