Browse Source

Add performance monitoring to Playwright test suite

Enhance test files with comprehensive performance tracking:
- Add performance collector integration to usage limits, project gifts, and offer recording tests
- Implement detailed user action timing with measureUserAction wrapper
- Add navigation metrics collection and validation
- Include performance data attachments to test reports
- Add dialog overlay handling for improved test reliability

Files modified:
- test-playwright/10-check-usage-limits.spec.ts
- test-playwright/37-record-gift-on-project.spec.ts
- test-playwright/50-record-offer.spec.ts
pull/159/head
Matthew Raymer 3 weeks ago
parent
commit
835619fc66
  1. 68
      test-playwright/10-check-usage-limits.spec.ts
  2. 123
      test-playwright/37-record-gift-on-project.spec.ts
  3. 382
      test-playwright/50-record-offer.spec.ts

68
test-playwright/10-check-usage-limits.spec.ts

@ -60,29 +60,59 @@
*/ */
import { test, expect } from '@playwright/test'; import { test, expect } from '@playwright/test';
import { importUser } from './testUtils'; import { importUser } from './testUtils';
import { createPerformanceCollector, attachPerformanceData, assertPerformanceMetrics } from './performanceUtils';
test('Check usage limits', async ({ page }) => { test('Check usage limits', async ({ page }, testInfo) => {
// Check without ID first // STEP 1: Initialize the performance collector
await page.goto('./account'); const perfCollector = await createPerformanceCollector(page);
await expect(page.locator('div.bg-slate-100.rounded-md').filter({ hasText: 'Usage Limits' })).toBeHidden();
// Import user 01 // STEP 2: Check without ID first
const did = await importUser(page, '01'); await perfCollector.measureUserAction('navigate-to-account', async () => {
await page.goto('./account');
});
const initialMetrics = await perfCollector.collectNavigationMetrics('account-page-load');
await testInfo.attach('initial-page-load-metrics', {
contentType: 'application/json',
body: JSON.stringify(initialMetrics, null, 2)
});
// Verify that "Usage Limits" section is visible await perfCollector.measureUserAction('verify-no-usage-limits', async () => {
await expect(page.locator('#sectionUsageLimits')).toBeVisible(); await expect(page.locator('div.bg-slate-100.rounded-md').filter({ hasText: 'Usage Limits' })).toBeHidden();
await expect(page.locator('#sectionUsageLimits')).toContainText('You have done'); });
await expect(page.locator('#sectionUsageLimits')).toContainText('You have uploaded');
await expect(page.getByText('Your claims counter resets')).toBeVisible(); // STEP 3: Import user 01
await expect(page.getByText('Your registration counter resets')).toBeVisible(); await perfCollector.measureUserAction('import-user-account', async () => {
await expect(page.getByText('Your image counter resets')).toBeVisible(); const did = await importUser(page, '01');
await expect(page.getByRole('button', { name: 'Recheck Limits' })).toBeVisible(); });
// Set name // STEP 4: Verify usage limits section
await page.getByRole('button', { name: 'Set Your Name' }).click(); await perfCollector.measureUserAction('verify-usage-limits-section', async () => {
const name = 'User ' + did.slice(11, 14); await expect(page.locator('#sectionUsageLimits')).toBeVisible();
await page.getByPlaceholder('Name').fill(name); await expect(page.locator('#sectionUsageLimits')).toContainText('You have done');
await page.getByRole('button', { name: 'Save', exact: true }).click(); await expect(page.locator('#sectionUsageLimits')).toContainText('You have uploaded');
});
await perfCollector.measureUserAction('verify-usage-limit-texts', async () => {
await expect(page.getByText('Your claims counter resets')).toBeVisible();
await expect(page.getByText('Your registration counter resets')).toBeVisible();
await expect(page.getByText('Your image counter resets')).toBeVisible();
await expect(page.getByRole('button', { name: 'Recheck Limits' })).toBeVisible();
});
// STEP 5: Set name
await perfCollector.measureUserAction('click-set-name-button', async () => {
await page.getByRole('button', { name: 'Set Your Name' }).click();
});
await perfCollector.measureUserAction('fill-and-save-name', async () => {
const name = 'User ' + '01'.slice(0, 2);
await page.getByPlaceholder('Name').fill(name);
await page.getByRole('button', { name: 'Save', exact: true }).click();
});
// STEP 6: 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);
}); });

123
test-playwright/37-record-gift-on-project.spec.ts

@ -1,50 +1,101 @@
import { test, expect, Page } from '@playwright/test'; import { test, expect, Page } from '@playwright/test';
import { importUser } from './testUtils'; import { importUser } from './testUtils';
import { createPerformanceCollector, attachPerformanceData, assertPerformanceMetrics } from './performanceUtils';
async function testProjectGive(page: Page, selector: string) { async function testProjectGive(page: Page, selector: string, testInfo: any) {
// STEP 1: Initialize the performance collector
const perfCollector = await createPerformanceCollector(page);
// Generate a random string of a few characters // STEP 2: Generate unique test data
const randomString = Math.random().toString(36).substring(2, 6); const randomString = Math.random().toString(36).substring(2, 6);
// Generate a random non-zero single-digit number
const randomNonZeroNumber = Math.floor(Math.random() * 99) + 1; const randomNonZeroNumber = Math.floor(Math.random() * 99) + 1;
// Standard title prefix
const standardTitle = 'Gift '; const standardTitle = 'Gift ';
// Combine title prefix with the random string
const finalTitle = standardTitle + randomString; const finalTitle = standardTitle + randomString;
// find a project and enter a give to it and see that it shows // STEP 3: Import user and navigate to discover
await importUser(page, '00'); await perfCollector.measureUserAction('import-user-account', async () => {
await page.goto('./discover'); await importUser(page, '00');
await page.getByTestId('closeOnboardingAndFinish').click(); });
await page.locator('ul#listDiscoverResults li:first-child a').click() await perfCollector.measureUserAction('navigate-to-discover', async () => {
// wait for the project page to load await page.goto('./discover');
await page.waitForLoadState('networkidle'); });
// click the give button, inside the first div const initialMetrics = await perfCollector.collectNavigationMetrics('discover-page-load');
await page.getByTestId(selector).locator('div:first-child div button').click(); await testInfo.attach('initial-page-load-metrics', {
await page.getByPlaceholder('What was given').fill(finalTitle); contentType: 'application/json',
await page.getByRole('spinbutton').fill(randomNonZeroNumber.toString()); body: JSON.stringify(initialMetrics, null, 2)
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(); // dismiss info alert await perfCollector.measureUserAction('close-onboarding', async () => {
await page.getByTestId('closeOnboardingAndFinish').click();
// refresh the page });
await page.reload();
// check that the give is in the list await perfCollector.measureUserAction('select-first-project', async () => {
await page await page.locator('ul#listDiscoverResults li:first-child a').click();
.getByTestId(selector) });
.locator('div ul li:first-child')
.filter({ hasText: finalTitle }) // STEP 4: Wait for project page to load
.isVisible(); 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 }) => { test('Record a give to a project', async ({ page }, testInfo) => {
await testProjectGive(page, 'gives-to'); await testProjectGive(page, 'gives-to', testInfo);
}); });
test('Record a give from a project', async ({ page }) => { test('Record a give from a project', async ({ page }, testInfo) => {
await testProjectGive(page, 'gives-from'); await testProjectGive(page, 'gives-from', testInfo);
}); });

382
test-playwright/50-record-offer.spec.ts

@ -1,127 +1,291 @@
import { test, expect, Page } from '@playwright/test'; import { test, expect, Page } from '@playwright/test';
import { importUser, importUserFromAccount } from './testUtils'; import { importUser, importUserFromAccount } from './testUtils';
import { createPerformanceCollector, attachPerformanceData, assertPerformanceMetrics } from './performanceUtils';
test('Record an offer', async ({ page }) => { test('Record an offer', async ({ page }, testInfo) => {
test.setTimeout(60000); test.setTimeout(60000);
// Generate a random string of 3 characters, skipping the "0." at the beginning // 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, 5); const randomString = Math.random().toString(36).substring(2, 5);
// Standard title prefix
const description = `Offering of ${randomString}`; const description = `Offering of ${randomString}`;
const updatedDescription = `Updated ${description}`; const updatedDescription = `Updated ${description}`;
const randomNonZeroNumber = Math.floor(Math.random() * 998) + 1; const randomNonZeroNumber = Math.floor(Math.random() * 998) + 1;
// Switch to user 0 // STEP 3: Import user and navigate to discover page
// await importUser(page); await perfCollector.measureUserAction('import-user-account', async () => {
// Become User Zero await importUserFromAccount(page, "00");
await importUserFromAccount(page, "00"); });
// Select a project
await page.goto('./discover'); await perfCollector.measureUserAction('navigate-to-discover', async () => {
await page.getByTestId('closeOnboardingAndFinish').click(); await page.goto('./discover');
await page.locator('ul#listDiscoverResults li:nth-child(1)').click(); });
// Record an offer const initialMetrics = await perfCollector.collectNavigationMetrics('discover-page-load');
await page.locator('button', { hasText: 'Edit' }).isVisible(); // since the 'edit' takes longer to show, wait for that (lest the click miss) await testInfo.attach('initial-page-load-metrics', {
await page.getByTestId('offerButton').click(); contentType: 'application/json',
await page.getByTestId('inputDescription').fill(description); body: JSON.stringify(initialMetrics, null, 2)
await page.getByTestId('inputOfferAmount').fill(randomNonZeroNumber.toString()); });
expect(page.getByRole('button', { name: 'Sign & Send' }));
await page.getByRole('button', { name: 'Sign & Send' }).click(); // STEP 4: Close onboarding and select project
await expect(page.getByText('That offer was recorded.')).toBeVisible(); await perfCollector.measureUserAction('close-onboarding', async () => {
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert await page.getByTestId('closeOnboardingAndFinish').click();
// go to the offer and check the values });
await page.goto('./projects');
await page.getByRole('link', { name: 'Offers', exact: true }).click(); await perfCollector.measureUserAction('select-project', async () => {
await page.locator('li').filter({ hasText: description }).locator('a').first().click(); await page.locator('ul#listDiscoverResults li:nth-child(1)').click();
await expect(page.getByRole('heading', { name: 'Verifiable Claim Details' })).toBeVisible(); });
await expect(page.getByText(description, { exact: true })).toBeVisible();
await expect(page.getByText('Offered to a bigger plan')).toBeVisible(); // STEP 5: Record an offer
await perfCollector.measureUserAction('wait-for-edit-button', async () => {
await page.locator('button', { hasText: 'Edit' }).isVisible();
});
await perfCollector.measureUserAction('click-offer-button', async () => {
await page.getByTestId('offerButton').click();
});
await perfCollector.measureUserAction('fill-offer-details', async () => {
await page.getByTestId('inputDescription').fill(description);
await page.getByTestId('inputOfferAmount').fill(randomNonZeroNumber.toString());
});
await perfCollector.measureUserAction('submit-offer', async () => {
expect(page.getByRole('button', { name: 'Sign & Send' }));
await page.getByRole('button', { name: 'Sign & Send' }).click();
await expect(page.getByText('That offer was recorded.')).toBeVisible();
await page.locator('div[role="alert"] button > svg.fa-xmark').click();
});
// STEP 6: Navigate to projects and check offer
await perfCollector.measureUserAction('navigate-to-projects', async () => {
await page.goto('./projects');
});
await perfCollector.measureUserAction('click-offers-tab', async () => {
await page.getByRole('link', { name: 'Offers', exact: true }).click();
});
await perfCollector.measureUserAction('click-offer-details', async () => {
await page.locator('li').filter({ hasText: description }).locator('a').first().click();
});
await perfCollector.measureUserAction('verify-offer-details', async () => {
await expect(page.getByRole('heading', { name: 'Verifiable Claim Details' })).toBeVisible();
await expect(page.getByText(description, { exact: true })).toBeVisible();
await expect(page.getByText('Offered to a bigger plan')).toBeVisible();
});
// STEP 7: Expand details and check public server
const serverPagePromise = page.waitForEvent('popup'); const serverPagePromise = page.waitForEvent('popup');
// expand the Details section to see the extended details
await page.getByRole('heading', { name: 'Details', exact: true }).click(); await perfCollector.measureUserAction('expand-details', async () => {
await page.getByRole('link', { name: 'View on the Public Server' }).click(); await page.getByRole('heading', { name: 'Details', exact: true }).click();
});
await perfCollector.measureUserAction('open-public-server', async () => {
await page.getByRole('link', { name: 'View on the Public Server' }).click();
});
const serverPage = await serverPagePromise; const serverPage = await serverPagePromise;
await expect(serverPage.getByText(description)).toBeVisible(); await perfCollector.measureUserAction('verify-public-server', async () => {
await expect(serverPage.getByText('did:none:HIDDEN')).toBeVisible(); await expect(serverPage.getByText(description)).toBeVisible();
// Now update that offer await expect(serverPage.getByText('did:none:HIDDEN')).toBeVisible();
});
// find the edit page and check the old values again
await page.goto('./projects'); // STEP 8: Update the offer
await page.getByRole('link', { name: 'Offers', exact: true }).click(); await perfCollector.measureUserAction('navigate-back-to-projects', async () => {
await page.locator('li').filter({ hasText: description }).locator('a').first().click(); await page.goto('./projects');
await page.getByTestId('editClaimButton').click(); });
await page.locator('heading', { hasText: 'What is offered' }).isVisible();
const itemDesc = await page.getByTestId('itemDescription'); await perfCollector.measureUserAction('click-offers-tab-again', async () => {
await expect(itemDesc).toHaveValue(description); await page.getByRole('link', { name: 'Offers', exact: true }).click();
const amount = await page.getByTestId('inputOfferAmount'); });
await expect(amount).toHaveValue(randomNonZeroNumber.toString());
// update the values await perfCollector.measureUserAction('click-offer-to-edit', async () => {
await itemDesc.fill(updatedDescription); await page.locator('li').filter({ hasText: description }).locator('a').first().click();
await amount.fill(String(randomNonZeroNumber + 1)); });
await page.getByRole('button', { name: 'Sign & Send' }).click();
await expect(page.getByText('That offer was recorded.')).toBeVisible(); await perfCollector.measureUserAction('click-edit-button', async () => {
await page.locator('div[role="alert"] button > svg.fa-xmark').click(); // dismiss info alert await page.getByTestId('editClaimButton').click();
// go to the offer claim again and check the updated values });
await page.goto('./projects');
await page.getByRole('link', { name: 'Offers', exact: true }).click(); await perfCollector.measureUserAction('verify-edit-form', async () => {
await page.locator('li').filter({ hasText: description }).locator('a').first().click(); await page.locator('heading', { hasText: 'What is offered' }).isVisible();
const newItemDesc = page.getByTestId('description'); const itemDesc = await page.getByTestId('itemDescription');
await expect(newItemDesc).toHaveText(updatedDescription); await expect(itemDesc).toHaveValue(description);
// go to edit page const amount = await page.getByTestId('inputOfferAmount');
await page.getByTestId('editClaimButton').click(); await expect(amount).toHaveValue(randomNonZeroNumber.toString());
const newAmount = page.getByTestId('inputOfferAmount'); });
await expect(newAmount).toHaveValue((randomNonZeroNumber + 1).toString());
// go to the home page and check that the offer is shown as new await perfCollector.measureUserAction('update-offer-values', async () => {
await page.goto('./'); const itemDesc = await page.getByTestId('itemDescription');
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber'); await itemDesc.fill(updatedDescription);
// extract the number and check that it's greater than 0 or "50+" const amount = await page.getByTestId('inputOfferAmount');
const offerNumText = await offerNumElem.textContent(); await amount.fill(String(randomNonZeroNumber + 1));
if (offerNumText === null) { });
throw new Error('Expected Activity Number greater than 0 but got null.');
} else if (offerNumText === '50+') { await perfCollector.measureUserAction('submit-updated-offer', async () => {
// we're OK await page.getByRole('button', { name: 'Sign & Send' }).click();
} else if (parseInt(offerNumText) > 0) { await expect(page.getByText('That offer was recorded.')).toBeVisible();
// we're OK await page.locator('div[role="alert"] button > svg.fa-xmark').click();
} else { });
throw new Error(`Expected Activity Number of greater than 0 but got ${offerNumText}.`);
} // STEP 9: Verify updated offer
await perfCollector.measureUserAction('navigate-to-projects-final', async () => {
// click on the number of new offers to go to the list page await page.goto('./projects');
await offerNumElem.click(); });
await expect(page.getByText('New Offers To Your Projects', { exact: true })).toBeVisible();
// get the icon child of the showOffersToUserProjects await perfCollector.measureUserAction('click-offers-tab-final', async () => {
await page.getByTestId('showOffersToUserProjects').locator('div > svg.fa-chevron-right').click(); await page.getByRole('link', { name: 'Offers', exact: true }).click();
await expect(page.getByText(description)).toBeVisible(); });
await perfCollector.measureUserAction('click-updated-offer', async () => {
await page.locator('li').filter({ hasText: description }).locator('a').first().click();
});
await perfCollector.measureUserAction('verify-updated-offer', async () => {
const newItemDesc = page.getByTestId('description');
await expect(newItemDesc).toHaveText(updatedDescription);
});
await perfCollector.measureUserAction('click-edit-button-final', async () => {
await page.getByTestId('editClaimButton').click();
});
await perfCollector.measureUserAction('verify-updated-amount', async () => {
const newAmount = page.getByTestId('inputOfferAmount');
await expect(newAmount).toHaveValue((randomNonZeroNumber + 1).toString());
});
// STEP 10: Check home page for new offers
await perfCollector.measureUserAction('navigate-to-home', async () => {
await page.goto('./');
});
await perfCollector.measureUserAction('verify-new-offers-indicator', async () => {
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber');
const offerNumText = await offerNumElem.textContent();
if (offerNumText === null) {
throw new Error('Expected Activity Number greater than 0 but got null.');
} else if (offerNumText === '50+') {
// we're OK
} else if (parseInt(offerNumText) > 0) {
// we're OK
} else {
throw new Error(`Expected Activity Number of greater than 0 but got ${offerNumText}.`);
}
});
await perfCollector.measureUserAction('click-new-offers-number', async () => {
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber');
await offerNumElem.click();
});
await perfCollector.measureUserAction('verify-new-offers-page', async () => {
await expect(page.getByText('New Offers To Your Projects', { exact: true })).toBeVisible();
});
await perfCollector.measureUserAction('expand-offers-section', async () => {
await page.getByTestId('showOffersToUserProjects').locator('div > svg.fa-chevron-right').click();
});
await perfCollector.measureUserAction('verify-offer-in-list', async () => {
await expect(page.getByText(description)).toBeVisible();
});
// STEP 11: 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('Affirm delivery of an offer', async ({ page }) => { test('Affirm delivery of an offer', async ({ page }, testInfo) => {
// go to the home page and check that the offer is shown as new // STEP 1: Initialize the performance collector
// await importUser(page); const perfCollector = await createPerformanceCollector(page);
await importUserFromAccount(page, "00"); // STEP 2: Import user and navigate to home
await page.goto('./'); await perfCollector.measureUserAction('import-user-account', async () => {
await page.getByTestId('closeOnboardingAndFinish').click(); await importUserFromAccount(page, "00");
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber'); });
await expect(offerNumElem).toBeVisible();
// click on the number of new offers to go to the list page await perfCollector.measureUserAction('navigate-to-home', async () => {
await offerNumElem.click(); await page.goto('./');
});
// get the link that comes after the showOffersToUserProjects and click it const initialMetrics = await perfCollector.collectNavigationMetrics('home-page-load');
await page.getByTestId('showOffersToUserProjects').locator('a').click(); await testInfo.attach('initial-page-load-metrics', {
contentType: 'application/json',
// get the first item of the list and click on the icon with file-lines body: JSON.stringify(initialMetrics, null, 2)
const firstItem = page.getByTestId('listRecentOffersToUserProjects').locator('li').first(); });
await expect(firstItem).toBeVisible();
await firstItem.locator('svg.fa-file-lines').click(); await perfCollector.measureUserAction('close-onboarding', async () => {
await expect(page.getByText('Verifiable Claim Details', { exact: true })).toBeVisible(); await page.getByTestId('closeOnboardingAndFinish').click();
});
// click on the 'Affirm Delivery' button
await page.getByRole('button', { name: 'Affirm Delivery' }).click(); // STEP 3: Check new offers indicator
// fill our offer info and submit await perfCollector.measureUserAction('verify-new-offers-indicator', async () => {
await page.getByPlaceholder('What was given').fill('Whatever the offer says'); const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber');
await page.getByRole('spinbutton').fill('2'); await expect(offerNumElem).toBeVisible();
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(); // dismiss info alert // STEP 4: Navigate to offers list
await perfCollector.measureUserAction('click-new-offers-number', async () => {
// Close any dialog overlays that might be blocking clicks
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
}
}
// Wait for any animations to complete
await page.waitForTimeout(500);
const offerNumElem = page.getByTestId('newOffersToUserProjectsActivityNumber');
await offerNumElem.click();
});
await perfCollector.measureUserAction('click-offers-link', async () => {
await page.getByTestId('showOffersToUserProjects').locator('a').click();
});
// STEP 5: Affirm delivery
await perfCollector.measureUserAction('select-first-offer', async () => {
const firstItem = page.getByTestId('listRecentOffersToUserProjects').locator('li').first();
await expect(firstItem).toBeVisible();
await firstItem.locator('svg.fa-file-lines').click();
});
await perfCollector.measureUserAction('verify-claim-details', async () => {
await expect(page.getByText('Verifiable Claim Details', { exact: true })).toBeVisible();
});
await perfCollector.measureUserAction('click-affirm-delivery', async () => {
await page.getByRole('button', { name: 'Affirm Delivery' }).click();
});
await perfCollector.measureUserAction('fill-delivery-details', async () => {
await page.getByPlaceholder('What was given').fill('Whatever the offer says');
await page.getByRole('spinbutton').fill('2');
});
await perfCollector.measureUserAction('submit-delivery', 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 6: 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);
}); });

Loading…
Cancel
Save