import { test, expect, Page } from '@playwright/test'; import { importUser } from './testUtils'; import { createPerformanceCollector, attachPerformanceData, assertPerformanceMetrics } from './performanceUtils'; async function testProjectGive(page: Page, selector: string, testInfo: any) { // STEP 1: Initialize the performance collector const perfCollector = await createPerformanceCollector(page); // STEP 2: Generate unique test data const randomString = Math.random().toString(36).substring(2, 6); const randomNonZeroNumber = Math.floor(Math.random() * 99) + 1; const standardTitle = 'Gift '; const finalTitle = standardTitle + randomString; // STEP 3: Import user and navigate to discover await perfCollector.measureUserAction('import-user-account', async () => { await importUser(page, '00'); }); await perfCollector.measureUserAction('navigate-to-discover', async () => { await page.goto('./discover'); }); const initialMetrics = await perfCollector.collectNavigationMetrics('discover-page-load'); await testInfo.attach('initial-page-load-metrics', { contentType: 'application/json', body: JSON.stringify(initialMetrics, null, 2) }); await perfCollector.measureUserAction('close-onboarding', async () => { await page.getByTestId('closeOnboardingAndFinish').click(); }); await perfCollector.measureUserAction('select-first-project', async () => { await page.locator('ul#listDiscoverResults li:first-child a').click(); }); // STEP 4: Wait for project page to load await perfCollector.measureUserAction('wait-for-project-load', async () => { await page.waitForLoadState('networkidle'); }); // STEP 5: Handle dialog overlays await perfCollector.measureUserAction('close-dialog-overlays', async () => { await page.waitForTimeout(1000); const closeButtons = page.locator('button[aria-label*="close"], button[aria-label*="Close"], .dialog-overlay button, [role="dialog"] button'); const count = await closeButtons.count(); for (let i = 0; i < count; i++) { try { await closeButtons.nth(i).click({ timeout: 2000 }); } catch (e) { // Ignore errors if button is not clickable } } await page.waitForTimeout(500); }); // STEP 6: Record gift await perfCollector.measureUserAction('click-give-button', async () => { await page.getByTestId(selector).locator('div:first-child div button').click(); }); await perfCollector.measureUserAction('fill-gift-details', async () => { await page.getByPlaceholder('What was given').fill(finalTitle); await page.getByRole('spinbutton').fill(randomNonZeroNumber.toString()); }); await perfCollector.measureUserAction('submit-gift', async () => { await page.getByRole('button', { name: 'Sign & Send' }).click(); await expect(page.getByText('That gift was recorded.')).toBeVisible(); await page.locator('div[role="alert"] button > svg.fa-xmark').click(); }); // STEP 7: Verify gift appears in list await perfCollector.measureUserAction('refresh-page', async () => { await page.reload(); }); await perfCollector.measureUserAction('verify-gift-in-list', async () => { await page .getByTestId(selector) .locator('div ul li:first-child') .filter({ hasText: finalTitle }) .isVisible(); }); // STEP 8: Attach and validate performance data const { webVitals, performanceReport, summary } = await attachPerformanceData(testInfo, perfCollector); const avgNavigationTime = perfCollector.navigationMetrics.reduce((sum, nav) => sum + nav.metrics.loadComplete, 0) / perfCollector.navigationMetrics.length; assertPerformanceMetrics(webVitals, initialMetrics, avgNavigationTime); } test('Record a give to a project', async ({ page }, testInfo) => { await testProjectGive(page, 'gives-to', testInfo); }); test('Record a give from a project', async ({ page }, testInfo) => { await testProjectGive(page, 'gives-from', testInfo); });