import { test, expect } from './fixtures/auth'; import { CommonActions } from './utils/common-actions'; /** * Certificate management and bulk operations tests * Tests: bulk generation, filtering, searching, reporting * @tag @certificates @management */ test.describe('Certificate Management', () => { test('Bulk certificate operations', async ({ authenticatedPage: page }) => { const actions = new CommonActions(page); // Navigate to Generate Certificates page await actions.navigateAndWait('/generate-certificates/'); // Test bulk selection functionality const eventSelect = page.locator('select[name="event_id"]'); await expect(eventSelect).toBeVisible(); const eventOptions = await eventSelect.locator('option').count(); if (eventOptions > 1) { // Select event with most attendees for bulk testing await eventSelect.selectOption({ index: 1 }); await actions.waitForAjax(); // Wait for attendees to load await page.waitForSelector('input[name="attendee_ids[]"]', { timeout: 10000 }); const attendeeCheckboxes = page.locator('input[name="attendee_ids[]"]'); const attendeeCount = await attendeeCheckboxes.count(); if (attendeeCount > 1) { // Test select all functionality if available const selectAllCheckbox = page.locator('input[id*="select-all"], input[name="select_all"]'); if (await selectAllCheckbox.count() > 0) { await selectAllCheckbox.check(); await actions.screenshot('bulk-select-all'); // Verify all attendees are selected for (let i = 0; i < attendeeCount; i++) { await expect(attendeeCheckboxes.nth(i)).toBeChecked(); } } else { // Manually select multiple attendees const selectCount = Math.min(3, attendeeCount); for (let i = 0; i < selectCount; i++) { await attendeeCheckboxes.nth(i).check(); } } await actions.screenshot('bulk-attendees-selected'); // Test bulk generation (without actually submitting to avoid spam) const submitButton = page.locator('button[type="submit"], input[type="submit"]'); await expect(submitButton).toBeVisible(); console.log(`Verified bulk selection of ${attendeeCount} attendees`); } } }); test('Certificate filtering and search', async ({ authenticatedPage: page }) => { const actions = new CommonActions(page); // Navigate to Certificate Reports page await actions.navigateAndWait('/certificate-reports/'); // Look for filtering controls const filterControls = [ page.locator('select[name*="filter"], select[id*="filter"]'), page.locator('input[name*="search"], input[id*="search"]'), page.locator('input[type="date"]'), page.locator('select[name*="event"], select[id*="event"]') ]; let foundFilters = false; for (const control of filterControls) { const count = await control.count(); if (count > 0) { foundFilters = true; console.log(`Found ${count} filter control(s)`); // Test the filter control const firstControl = control.first(); const tagName = await firstControl.evaluate(el => el.tagName.toLowerCase()); if (tagName === 'select') { const options = await firstControl.locator('option').count(); if (options > 1) { await firstControl.selectOption({ index: 1 }); await actions.waitForAjax(); await actions.screenshot('filter-applied'); } } else if (tagName === 'input') { const inputType = await firstControl.getAttribute('type'); if (inputType === 'text' || inputType === 'search') { await firstControl.fill('test'); await actions.waitForAjax(); await actions.screenshot('search-applied'); } } break; // Test one filter to avoid conflicts } } if (!foundFilters) { console.log('No filter controls found - this may be expected for current implementation'); } }); test('Certificate reporting and statistics', async ({ authenticatedPage: page }) => { const actions = new CommonActions(page); // Navigate to Certificate Reports await actions.navigateAndWait('/certificate-reports/'); // Verify statistics display const statSelectors = [ '.stat-value', '.stat-number', '.dashboard-stat', '.certificate-stat', 'span:has-text(/^\d+$/)', 'div:has-text(/total/i)', 'td:has-text(/^\d+$/)' ]; let statsFound = false; let totalStats = 0; for (const selector of statSelectors) { const elements = page.locator(selector); const count = await elements.count(); if (count > 0) { statsFound = true; totalStats += count; // Verify statistics contain numbers for (let i = 0; i < Math.min(count, 5); i++) { const text = await elements.nth(i).textContent(); const hasNumber = /\d/.test(text || ''); expect(hasNumber).toBeTruthy(); } } } expect(statsFound).toBeTruthy(); console.log(`Found ${totalStats} statistical elements`); await actions.screenshot('certificate-statistics-verified'); // Test export functionality if available const exportButtons = page.locator('button:has-text(/export/i), a:has-text(/export/i), a:has-text(/download/i)'); const exportCount = await exportButtons.count(); if (exportCount > 0) { console.log(`Found ${exportCount} export option(s)`); // Note: Not clicking to avoid file downloads in tests await expect(exportButtons.first()).toBeVisible(); } }); test('Certificate data integrity and validation', async ({ authenticatedPage: page }) => { const actions = new CommonActions(page); // Test data consistency between pages await actions.navigateAndWait('/certificate-reports/'); // Extract statistics from reports page const reportStats = []; const statElements = page.locator('.stat-value, .stat-number, .dashboard-stat'); const statCount = await statElements.count(); for (let i = 0; i < Math.min(statCount, 4); i++) { const text = await statElements.nth(i).textContent(); const number = parseInt(text?.replace(/[^\d]/g, '') || '0'); reportStats.push(number); } // Navigate to generation page and verify consistency await actions.navigateAndWait('/generate-certificates/'); const eventSelect = page.locator('select[name="event_id"]'); const eventOptions = await eventSelect.locator('option').count(); // Event count should be consistent (minus the default option) const actualEventCount = Math.max(0, eventOptions - 1); console.log(`Found ${actualEventCount} events in generation page`); // Verify no PHP errors occurred during navigation const phpErrors = await actions.checkForPHPErrors(); expect(phpErrors.length).toBe(0); await actions.screenshot('data-integrity-verified'); }); });