- Add dedicated AttendeeFilterPage for isolating filtering functionality - Create optimized certificate test focusing on attendee search - Document testing strategy and best practices - Add script to analyze and improve Playwright configuration - Create optimized Playwright configuration template - Resolve test stability issues with simplified approach - Improve test isolation and reliability for certificates
213 lines
No EOL
8.8 KiB
TypeScript
213 lines
No EOL
8.8 KiB
TypeScript
import { test, expect } from '@playwright/test';
|
|
import { Config } from './utils/Config';
|
|
import { BasePage } from './pages/BasePage';
|
|
import { LoginPage } from './pages/LoginPage';
|
|
import { DashboardPage } from './pages/DashboardPage';
|
|
|
|
/**
|
|
* Optimized Certificate Tests
|
|
*
|
|
* This file contains E2E tests for the certificate system with a focus
|
|
* on verifying the attendee search filter functionality.
|
|
*/
|
|
|
|
// Simple CertificatePage implementation that doesn't depend on external files
|
|
class CertificatePage extends BasePage {
|
|
// Certificate Reports page selectors
|
|
private readonly certificateTitle = 'h1:has-text("Certificate Reports")';
|
|
private readonly certificateTable = '.hvac-certificate-table';
|
|
private readonly eventFilter = '#filter_event';
|
|
private readonly attendeeSearch = '#search_attendee';
|
|
private readonly revokedFilter = '#filter_revoked';
|
|
private readonly filterSubmit = 'button[type="submit"]';
|
|
private readonly clearFilters = 'a.hvac-clear-filters';
|
|
private readonly totalCountText = '.hvac-total-count';
|
|
private readonly pagination = '.hvac-pagination';
|
|
private readonly nextPage = '.hvac-pagination a.next';
|
|
private readonly previousPage = '.hvac-pagination a.prev';
|
|
private readonly certificateRows = '.hvac-certificate-table tbody tr';
|
|
private readonly certificateEventCells = 'td.certificate-event';
|
|
private readonly certificateAttendeeCells = 'td.certificate-attendee';
|
|
|
|
async navigateToCertificateReports(): Promise<void> {
|
|
await this.page.goto(Config.certificateReportsUrl);
|
|
await this.page.waitForLoadState('networkidle');
|
|
}
|
|
|
|
async isCertificateReportsPageVisible(): Promise<boolean> {
|
|
return this.page.locator(this.certificateTitle).isVisible();
|
|
}
|
|
|
|
async clearAllFilters(): Promise<void> {
|
|
if (await this.page.locator(this.clearFilters).isVisible()) {
|
|
await this.page.click(this.clearFilters);
|
|
await this.page.waitForTimeout(1000);
|
|
}
|
|
}
|
|
|
|
async filterByEvent(eventId: string): Promise<void> {
|
|
await this.clearAllFilters();
|
|
await this.page.selectOption(this.eventFilter, eventId);
|
|
await this.page.click(this.filterSubmit);
|
|
await this.page.waitForSelector(this.certificateTable);
|
|
}
|
|
|
|
async filterByAttendee(searchTerm: string): Promise<void> {
|
|
await this.clearAllFilters();
|
|
await this.page.fill(this.attendeeSearch, searchTerm);
|
|
await this.page.click(this.filterSubmit);
|
|
await this.page.waitForSelector(this.certificateTable);
|
|
}
|
|
|
|
async filterByRevoked(revoked: boolean): Promise<void> {
|
|
await this.clearAllFilters();
|
|
await this.page.selectOption(this.revokedFilter, revoked ? '1' : '0');
|
|
await this.page.click(this.filterSubmit);
|
|
await this.page.waitForSelector(this.certificateTable);
|
|
}
|
|
|
|
async getCertificateCount(): Promise<number> {
|
|
const countText = await this.page.locator(this.totalCountText).textContent();
|
|
const match = countText?.match(/of (\d+) certificates/);
|
|
return match ? parseInt(match[1]) : 0;
|
|
}
|
|
|
|
async getEventCellTexts(): Promise<string[]> {
|
|
return this.page.locator(this.certificateEventCells).allTextContents();
|
|
}
|
|
|
|
async getAttendeeCellTexts(): Promise<string[]> {
|
|
return this.page.locator(this.certificateAttendeeCells).allTextContents();
|
|
}
|
|
|
|
async hasPagination(): Promise<boolean> {
|
|
return this.page.locator(this.pagination).isVisible();
|
|
}
|
|
|
|
async clickNextPage(): Promise<void> {
|
|
await this.page.click(this.nextPage);
|
|
await this.page.waitForSelector(this.certificateTable);
|
|
}
|
|
}
|
|
|
|
// Simple test that verifies the certificate data and attendee search functionality
|
|
test('Certificate data and attendee search verification', async ({ page }) => {
|
|
// Create page objects
|
|
const loginPage = new LoginPage(page);
|
|
const dashboardPage = new DashboardPage(page);
|
|
const certificatePage = new CertificatePage(page);
|
|
|
|
// Test event IDs
|
|
const testEvents = [
|
|
{ id: '5641', name: 'HVAC System Design Fundamentals' },
|
|
{ id: '5668', name: 'Advanced Refrigeration Technology' },
|
|
{ id: '5688', name: 'Building Automation Systems Workshop' }
|
|
];
|
|
|
|
// Step 1: Login
|
|
console.log('Step 1: Logging in as test trainer');
|
|
await loginPage.navigate();
|
|
await loginPage.login(Config.testTrainer.username, Config.testTrainer.password);
|
|
|
|
// Verify successful login
|
|
const isLoggedIn = await dashboardPage.isVisible('h1:has-text("Dashboard")');
|
|
expect(isLoggedIn).toBeTruthy();
|
|
|
|
// Step 2: Navigate to certificate reports
|
|
console.log('Step 2: Navigating to certificate reports page');
|
|
await certificatePage.navigateToCertificateReports();
|
|
|
|
// Verify certificate page loaded
|
|
const certificatePageVisible = await certificatePage.isCertificateReportsPageVisible();
|
|
expect(certificatePageVisible).toBeTruthy();
|
|
|
|
// Step 3: Check total certificate count
|
|
console.log('Step 3: Checking total certificate count');
|
|
const totalCount = await certificatePage.getCertificateCount();
|
|
console.log(`Total certificates: ${totalCount}`);
|
|
expect(totalCount).toBeGreaterThanOrEqual(47); // We expect at least 47 certificates from our test data
|
|
|
|
// Step 4: Test event filtering
|
|
console.log('Step 4: Testing event filtering');
|
|
for (const event of testEvents) {
|
|
await certificatePage.filterByEvent(event.id);
|
|
const eventCount = await certificatePage.getCertificateCount();
|
|
console.log(`Event "${event.name}" has ${eventCount} certificates`);
|
|
|
|
// Verify all event cells contain the correct name
|
|
const eventCells = await certificatePage.getEventCellTexts();
|
|
for (const cellText of eventCells) {
|
|
expect(cellText).toContain(event.name);
|
|
}
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: `event-filter-${event.id}.png` });
|
|
}
|
|
|
|
// Step 5: Test attendee name filtering
|
|
console.log('Step 5: Testing attendee name filtering');
|
|
await certificatePage.filterByAttendee('Ben Tester');
|
|
const benCount = await certificatePage.getCertificateCount();
|
|
console.log(`Attendee "Ben Tester" has ${benCount} certificates`);
|
|
|
|
// Verify attendee cells contain Ben Tester
|
|
const benCells = await certificatePage.getAttendeeCellTexts();
|
|
for (const cellText of benCells) {
|
|
expect(cellText.toLowerCase()).toContain('ben tester');
|
|
}
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: 'attendee-name-filter.png' });
|
|
|
|
// Step 6: Test attendee email filtering
|
|
console.log('Step 6: Testing attendee email filtering');
|
|
await certificatePage.filterByAttendee('ben@tealmaker.com');
|
|
const emailCount = await certificatePage.getCertificateCount();
|
|
console.log(`Email "ben@tealmaker.com" has ${emailCount} certificates`);
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: 'attendee-email-filter.png' });
|
|
|
|
// Step 7: Test partial name filtering
|
|
console.log('Step 7: Testing partial name filtering');
|
|
await certificatePage.filterByAttendee('Smith');
|
|
const smithCount = await certificatePage.getCertificateCount();
|
|
console.log(`Partial name "Smith" has ${smithCount} certificates`);
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: 'partial-name-filter.png' });
|
|
|
|
// Step 8: Test partial email filtering
|
|
console.log('Step 8: Testing partial email filtering');
|
|
await certificatePage.filterByAttendee('@gmail');
|
|
const gmailCount = await certificatePage.getCertificateCount();
|
|
console.log(`Partial email "@gmail" has ${gmailCount} certificates`);
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: 'partial-email-filter.png' });
|
|
|
|
// Step 9: Test revoked filtering
|
|
console.log('Step 9: Testing revocation status filtering');
|
|
await certificatePage.filterByRevoked(true);
|
|
const revokedCount = await certificatePage.getCertificateCount();
|
|
console.log(`Found ${revokedCount} revoked certificates`);
|
|
|
|
// Take screenshot for verification
|
|
await page.screenshot({ path: 'revoked-filter.png' });
|
|
|
|
// Step 10: Test pagination
|
|
console.log('Step 10: Testing pagination if applicable');
|
|
await certificatePage.clearAllFilters();
|
|
const hasPagination = await certificatePage.hasPagination();
|
|
|
|
if (hasPagination) {
|
|
console.log('Pagination is available, testing navigation');
|
|
await certificatePage.clickNextPage();
|
|
// Take screenshot of second page
|
|
await page.screenshot({ path: 'pagination-page-2.png' });
|
|
} else {
|
|
console.log('No pagination available (not enough certificates)');
|
|
}
|
|
|
|
console.log('Certificate verification tests completed');
|
|
}); |