import { test, expect } from '@playwright/test'; import { login, logout, isLoggedIn } from '../helpers/auth.helper'; import { navigateToSearchQueue, navigateToSearchesDashboard, clickNavLink } from '../helpers/navigation.helper'; import { getDataGridRowCount, getBadgeStyle, clickButton, StatusBadgeStyles } from '../helpers/radzen.helper'; test.describe('Search Queue Page', () => { test.beforeEach(async ({ page }) => { await navigateToSearchQueue(page); }); test.describe('Page Load and Display', () => { test('page loads and displays Search Queue heading', async ({ page }) => { // Verify page title await expect(page).toHaveTitle(/Search Queue - JDE Scoping Tool/); // Verify "Search Queue" heading is visible await expect(page.locator('h4:has-text("Search Queue")')).toBeVisible(); }); test('page shows processor status panel', async ({ page }) => { // Verify "Search Processor Status" section is visible await expect(page.locator('text=Search Processor Status')).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 }) => { const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 5000 }); }); }); test.describe('Processor Status Panel', () => { test('status panel is contained within a RadzenCard', async ({ page }) => { const card = page.locator('.rz-card').filter({ hasText: 'Search Processor Status' }); await expect(card).toBeVisible(); }); test('status message field is visible', async ({ page }) => { // Look for "Status Message" label await expect(page.locator('text=Status Message')).toBeVisible(); }); test('last update timestamp field is visible', async ({ page }) => { // Look for "Last Update Timestamp" label await expect(page.locator('text=Last Update Timestamp')).toBeVisible(); }); test('status message textbox is read-only', async ({ page }) => { // The status message input should be read-only const statusInput = page.locator('.rz-card').filter({ hasText: 'Status Message' }).locator('input').first(); if (await statusInput.isVisible({ timeout: 2000 }).catch(() => false)) { const readOnly = await statusInput.getAttribute('readonly'); // In Radzen, readonly inputs have the readonly attribute expect(readOnly !== null || await statusInput.isDisabled()).toBeTruthy(); } }); test('timestamp textbox is read-only', async ({ page }) => { const timestampInput = page.locator('.rz-card').filter({ hasText: 'Last Update Timestamp' }).locator('input').first(); if (await timestampInput.isVisible({ timeout: 2000 }).catch(() => false)) { const readOnly = await timestampInput.getAttribute('readonly'); expect(readOnly !== null || await timestampInput.isDisabled()).toBeTruthy(); } }); }); test.describe('Data Grid Columns', () => { test('data grid shows Owner column', async ({ page }) => { const ownerHeader = page.locator('.rz-data-grid th:has-text("Owner")'); await expect(ownerHeader).toBeVisible(); }); 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 Started column', async ({ page }) => { const startedHeader = page.locator('.rz-data-grid th:has-text("Started")'); await expect(startedHeader).toBeVisible(); }); test('data grid shows Ended column', async ({ page }) => { const endedHeader = page.locator('.rz-data-grid th:has-text("Ended")'); await expect(endedHeader).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('all expected columns are present', async ({ page }) => { const headers = page.locator('.rz-data-grid th'); const headerTexts = await headers.allTextContents(); // Verify all expected columns expect(headerTexts.some(h => h.includes('Owner'))).toBe(true); expect(headerTexts.some(h => h.includes('Name'))).toBe(true); expect(headerTexts.some(h => h.includes('Submitted'))).toBe(true); expect(headerTexts.some(h => h.includes('Started'))).toBe(true); expect(headerTexts.some(h => h.includes('Ended'))).toBe(true); expect(headerTexts.some(h => h.includes('Status'))).toBe(true); }); }); test.describe('Queue Display', () => { test('queue shows only queued and running searches', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Get all status badges in the grid const statusBadges = page.locator('.rz-data-grid tbody .rz-badge'); const badgeCount = await statusBadges.count(); for (let i = 0; i < badgeCount; i++) { const badgeText = await statusBadges.nth(i).textContent(); // Queue should only show Queued or Running statuses // (Ended and Error are removed from queue) if (badgeText) { expect(['Queued', 'Running', 'New']).toContain(badgeText.trim()); } } } }); }); test.describe('Status Badges', () => { test('Running status displays with info style', 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('Queued status displays with warning style', 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('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 no error occurred const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 2000 }); }); test('data grid supports pagination with 20 items per page', async ({ page }) => { // Look for pager component const pager = page.locator('.rz-pager'); await expect(pager).toBeVisible({ timeout: 5000 }); }); test('data grid supports column resize', async ({ page }) => { // The grid has AllowColumnResize="true" // Just verify no error on the page const errorNotification = page.locator('.rz-notification-error'); await expect(errorNotification).not.toBeVisible({ timeout: 2000 }); }); }); test.describe('Date Formatting', () => { test('submitted date is formatted correctly', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount > 0) { // Get text from Submitted column (index 2, after Owner and Name) const submittedCell = page.locator('.rz-data-grid tbody tr').first().locator('td').nth(2); 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); } } }); }); test.describe('Empty State', () => { test('displays appropriate message when queue is empty', async ({ page }) => { const rowCount = await getDataGridRowCount(page); if (rowCount === 0) { // Should show "No records to display" or similar const noRecordsMessage = page.locator('text=No records to display'); await expect(noRecordsMessage).toBeVisible(); } }); }); test.describe('Navigation', () => { test('can navigate to queue from searches dashboard', async ({ page }) => { // Start from searches dashboard await navigateToSearchesDashboard(page); // Click View Search Queue button await clickButton(page, 'View Search Queue'); // Wait for navigation await page.waitForLoadState('networkidle', { timeout: 30000 }); // Should be on queue page await expect(page).toHaveURL(/\/search\/queue/); await expect(page.locator('h4:has-text("Search Queue")')).toBeVisible(); }); }); });