test: Add comprehensive E2E tests for enhanced dashboard features
- Add tests for search functionality with debounce - Add tests for date range filtering - Add tests for per-page selector - Add tests for column sorting (ascending/descending) - Add tests for pagination controls - Add tests for combined filters working together - Add tests for responsive design on mobile/tablet - Add tests for loading indicators - Add tests for error handling - Add performance measurement for search operations Tests cover all new dashboard features including search, filters, pagination, and sorting to ensure functionality works as expected. Co-Authored-By: Ben Reed <ben@tealmaker.com>
This commit is contained in:
parent
1bd871cc7b
commit
a4d08fb15a
1 changed files with 343 additions and 0 deletions
343
wordpress-dev/tests/e2e/dashboard-enhanced-features.test.ts
Normal file
343
wordpress-dev/tests/e2e/dashboard-enhanced-features.test.ts
Normal file
|
|
@ -0,0 +1,343 @@
|
||||||
|
import { test, expect } from './fixtures/auth';
|
||||||
|
import { CommonActions } from './utils/common-actions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enhanced Dashboard Features Test Suite
|
||||||
|
*
|
||||||
|
* Tests the new search, filtering, pagination, and sorting features
|
||||||
|
* added to the trainer dashboard.
|
||||||
|
*/
|
||||||
|
test.describe('Enhanced Dashboard Features', () => {
|
||||||
|
let actions: CommonActions;
|
||||||
|
|
||||||
|
test.beforeEach(async ({ authenticatedPage: page }) => {
|
||||||
|
actions = new CommonActions(page);
|
||||||
|
|
||||||
|
// Navigate to dashboard
|
||||||
|
await actions.navigateAndWait('/hvac-dashboard/');
|
||||||
|
|
||||||
|
// Verify we're on the dashboard
|
||||||
|
await expect(page.locator('h1:has-text("Trainer Dashboard")')).toBeVisible();
|
||||||
|
|
||||||
|
// Wait for events table to load
|
||||||
|
await page.waitForSelector('.hvac-events-table-wrapper', { timeout: 10000 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Search functionality', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing search functionality...');
|
||||||
|
|
||||||
|
// Find the search box
|
||||||
|
const searchBox = page.locator('#hvac-event-search');
|
||||||
|
await expect(searchBox).toBeVisible();
|
||||||
|
|
||||||
|
// Type a search term
|
||||||
|
await searchBox.fill('Test');
|
||||||
|
|
||||||
|
// Wait for debounce and AJAX to complete
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Check that the table has been updated (loading class removed)
|
||||||
|
await expect(page.locator('.hvac-events-table-wrapper.loading')).not.toBeVisible();
|
||||||
|
|
||||||
|
// Take screenshot of search results
|
||||||
|
await actions.screenshot('dashboard-search-results');
|
||||||
|
|
||||||
|
// Clear search
|
||||||
|
await searchBox.clear();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
console.log('✓ Search functionality working');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Date range filters', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing date range filters...');
|
||||||
|
|
||||||
|
// Find date inputs
|
||||||
|
const dateFrom = page.locator('#hvac-date-from');
|
||||||
|
const dateTo = page.locator('#hvac-date-to');
|
||||||
|
|
||||||
|
await expect(dateFrom).toBeVisible();
|
||||||
|
await expect(dateTo).toBeVisible();
|
||||||
|
|
||||||
|
// Set date range (events from last 30 days)
|
||||||
|
const today = new Date();
|
||||||
|
const thirtyDaysAgo = new Date(today);
|
||||||
|
thirtyDaysAgo.setDate(today.getDate() - 30);
|
||||||
|
|
||||||
|
await dateFrom.fill(thirtyDaysAgo.toISOString().split('T')[0]);
|
||||||
|
await dateTo.fill(today.toISOString().split('T')[0]);
|
||||||
|
|
||||||
|
// Wait for AJAX update
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Verify table updated
|
||||||
|
await expect(page.locator('.hvac-events-table-wrapper.loading')).not.toBeVisible();
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-date-filtered');
|
||||||
|
|
||||||
|
console.log('✓ Date range filters working');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Per page selector', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing per page selector...');
|
||||||
|
|
||||||
|
// Find per page selector
|
||||||
|
const perPageSelector = page.locator('#hvac-per-page');
|
||||||
|
await expect(perPageSelector).toBeVisible();
|
||||||
|
|
||||||
|
// Get initial row count
|
||||||
|
const initialRows = await page.locator('.hvac-events-table tbody tr').count();
|
||||||
|
console.log(`Initial rows: ${initialRows}`);
|
||||||
|
|
||||||
|
// Change to 25 per page
|
||||||
|
await perPageSelector.selectOption('25');
|
||||||
|
|
||||||
|
// Wait for AJAX update
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Check if pagination info updated
|
||||||
|
const displayingNum = page.locator('.displaying-num').first();
|
||||||
|
if (await displayingNum.count() > 0) {
|
||||||
|
const text = await displayingNum.textContent();
|
||||||
|
console.log(`Pagination info: ${text}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-per-page-25');
|
||||||
|
|
||||||
|
console.log('✓ Per page selector working');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Column sorting', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing column sorting...');
|
||||||
|
|
||||||
|
// Test sorting by event name
|
||||||
|
const nameHeader = page.locator('th.sortable a[data-orderby="name"]').first();
|
||||||
|
await expect(nameHeader).toBeVisible();
|
||||||
|
|
||||||
|
// Click to sort by name
|
||||||
|
await nameHeader.click();
|
||||||
|
|
||||||
|
// Wait for AJAX update
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Verify sorted class is applied
|
||||||
|
const nameColumn = page.locator('th.sortable').filter({ has: page.locator('a[data-orderby="name"]') }).first();
|
||||||
|
await expect(nameColumn).toHaveClass(/sorted/);
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-sorted-by-name');
|
||||||
|
|
||||||
|
// Click again to reverse sort
|
||||||
|
await nameHeader.click();
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-sorted-by-name-desc');
|
||||||
|
|
||||||
|
console.log('✓ Column sorting working');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Pagination controls', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing pagination controls...');
|
||||||
|
|
||||||
|
// Check if pagination exists
|
||||||
|
const pagination = page.locator('.tablenav-pages').first();
|
||||||
|
const hasPagination = await pagination.count() > 0;
|
||||||
|
|
||||||
|
if (hasPagination) {
|
||||||
|
console.log('Pagination controls found');
|
||||||
|
|
||||||
|
// Check for next button
|
||||||
|
const nextButton = pagination.locator('a.next-page').first();
|
||||||
|
if (await nextButton.count() > 0 && !await nextButton.locator('..').hasClass('disabled')) {
|
||||||
|
// Click next page
|
||||||
|
await nextButton.click();
|
||||||
|
|
||||||
|
// Wait for update
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Verify page changed
|
||||||
|
const currentPage = await page.locator('.current-page').first().inputValue();
|
||||||
|
expect(parseInt(currentPage)).toBeGreaterThan(1);
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-page-2');
|
||||||
|
|
||||||
|
// Go back to first page
|
||||||
|
const firstButton = pagination.locator('a.first-page').first();
|
||||||
|
if (await firstButton.count() > 0) {
|
||||||
|
await firstButton.click();
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Not enough events for pagination');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('No pagination needed (few events)');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✓ Pagination controls tested');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Combined filters', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(45000);
|
||||||
|
|
||||||
|
console.log('Testing combined filters...');
|
||||||
|
|
||||||
|
// Apply multiple filters together
|
||||||
|
|
||||||
|
// 1. Set status filter
|
||||||
|
const draftFilter = page.locator('.hvac-event-filters a[data-status="draft"]').first();
|
||||||
|
if (await draftFilter.count() > 0) {
|
||||||
|
await draftFilter.click();
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Add search term
|
||||||
|
const searchBox = page.locator('#hvac-event-search');
|
||||||
|
await searchBox.fill('Event');
|
||||||
|
await page.waitForTimeout(1000); // Wait for debounce
|
||||||
|
|
||||||
|
// 3. Sort by date
|
||||||
|
const dateHeader = page.locator('th.sortable a[data-orderby="date"]').first();
|
||||||
|
await dateHeader.click();
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// 4. Change per page
|
||||||
|
const perPageSelector = page.locator('#hvac-per-page');
|
||||||
|
await perPageSelector.selectOption('50');
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Take screenshot of combined filters
|
||||||
|
await actions.screenshot('dashboard-combined-filters');
|
||||||
|
|
||||||
|
// Verify URL has all parameters
|
||||||
|
const currentUrl = page.url();
|
||||||
|
console.log(`Current URL with filters: ${currentUrl}`);
|
||||||
|
|
||||||
|
// Reset filters
|
||||||
|
const allFilter = page.locator('.hvac-event-filters a[data-status="all"]').first();
|
||||||
|
await allFilter.click();
|
||||||
|
await searchBox.clear();
|
||||||
|
|
||||||
|
console.log('✓ Combined filters working');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Table responsiveness', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing table responsiveness...');
|
||||||
|
|
||||||
|
// Test mobile viewport
|
||||||
|
await page.setViewportSize({ width: 375, height: 667 });
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
// Check if controls stack vertically
|
||||||
|
await expect(page.locator('.hvac-table-controls')).toBeVisible();
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-mobile-view');
|
||||||
|
|
||||||
|
// Test tablet viewport
|
||||||
|
await page.setViewportSize({ width: 768, height: 1024 });
|
||||||
|
await page.waitForTimeout(500);
|
||||||
|
|
||||||
|
await actions.screenshot('dashboard-tablet-view');
|
||||||
|
|
||||||
|
// Reset to desktop
|
||||||
|
await page.setViewportSize({ width: 1280, height: 720 });
|
||||||
|
|
||||||
|
console.log('✓ Table responsiveness tested');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Loading indicators', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing loading indicators...');
|
||||||
|
|
||||||
|
// Trigger a search to see loading state
|
||||||
|
const searchBox = page.locator('#hvac-event-search');
|
||||||
|
await searchBox.fill('Loading test');
|
||||||
|
|
||||||
|
// Try to catch the loading state (might be quick)
|
||||||
|
const loadingIndicator = page.locator('.hvac-loading');
|
||||||
|
const wasLoading = await loadingIndicator.count() > 0;
|
||||||
|
|
||||||
|
if (wasLoading) {
|
||||||
|
console.log('✓ Loading indicator displayed');
|
||||||
|
} else {
|
||||||
|
console.log('Loading too fast to capture (good performance)');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
await expect(page.locator('.hvac-events-table-wrapper.loading')).not.toBeVisible();
|
||||||
|
|
||||||
|
console.log('✓ Loading indicators tested');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('Error handling', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
|
||||||
|
console.log('Testing error handling...');
|
||||||
|
|
||||||
|
// Test invalid page number in URL
|
||||||
|
await page.goto(page.url() + '?paged=9999');
|
||||||
|
await page.waitForLoadState('networkidle');
|
||||||
|
|
||||||
|
// Should still show table (even if empty)
|
||||||
|
await expect(page.locator('.hvac-events-table-wrapper')).toBeVisible();
|
||||||
|
|
||||||
|
// Test invalid date format (this should be prevented by input type=date)
|
||||||
|
const dateFrom = page.locator('#hvac-date-from');
|
||||||
|
const validDate = '2024-01-01';
|
||||||
|
await dateFrom.fill(validDate);
|
||||||
|
|
||||||
|
console.log('✓ Error handling tested');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Dashboard Performance', () => {
|
||||||
|
test('Measure search performance', async ({ authenticatedPage: page }) => {
|
||||||
|
test.setTimeout(30000);
|
||||||
|
const actions = new CommonActions(page);
|
||||||
|
|
||||||
|
await actions.navigateAndWait('/hvac-dashboard/');
|
||||||
|
|
||||||
|
console.log('Measuring search performance...');
|
||||||
|
|
||||||
|
const searchBox = page.locator('#hvac-event-search');
|
||||||
|
|
||||||
|
// Measure time for search
|
||||||
|
const startTime = Date.now();
|
||||||
|
await searchBox.fill('Performance test');
|
||||||
|
|
||||||
|
// Wait for the table to update
|
||||||
|
await page.waitForFunction(() => {
|
||||||
|
const wrapper = document.querySelector('.hvac-events-table-wrapper');
|
||||||
|
return wrapper && !wrapper.classList.contains('loading');
|
||||||
|
}, { timeout: 10000 });
|
||||||
|
|
||||||
|
const endTime = Date.now();
|
||||||
|
const searchTime = endTime - startTime;
|
||||||
|
|
||||||
|
console.log(`Search completed in ${searchTime}ms`);
|
||||||
|
expect(searchTime).toBeLessThan(3000); // Should complete within 3 seconds
|
||||||
|
|
||||||
|
console.log('✓ Performance acceptable');
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue