perf.test.ts
Overview
perf.test.ts is an automated performance testing script using the Playwright testing framework. Its primary purpose is to verify that a specific "Expensive Component" in a web application renders within an acceptable performance benchmark — specifically, it asserts that the component finishes rendering within 1 second after a user interaction (a checkbox click).
The test navigates to a performance-focused page (./perf), triggers a rendering process by clicking a checkbox, and uses in-browser performance marks combined with DOM mutation observation to precisely measure the render time of a complex React component containing a large number of child elements (10,000 divs). This ensures that UI performance regressions are caught early in development.
Detailed Explanation
Test Suite: performance
Purpose: Group all performance-related tests.
Contains one test verifying rendering speed of the expensive component.
Test: should render expensive component within 1 second after checkbox click
Purpose
To measure and assert that the "Expensive Component" renders completely within 1000 milliseconds after a checkbox input is clicked.
Parameters
Receives Playwright’s test fixtures, specifically the
pageobject representing the browser page context.
Workflow
Navigate to the Performance Page
await page.goto('./perf', { waitUntil: 'load' })Loads the performance testing page, waiting for all network activity and page load to complete.
Inject Performance Measurement Script
Uses
page.evaluate()to run client-side JavaScript in the browser context.This script performs the following:
Selects the checkbox input element.
Sets up a
MutationObserveron thedocument.bodyto detect when the "Expensive Component" container appears and track the number of child div elements rendered inside it.Logs progress every 1000 rendered components for visibility.
When the total number of rendered child components reaches the target (10,000), it uses double
requestAnimationFrameto ensure that the browser has painted the UI.Marks the paint completion time with
window.performance.mark('expensive-component-painted').Adds a one-time event listener on the checkbox click to start the performance timer and mark the start time (
state-change-start).
Trigger Rendering
const checkbox = page.locator('input[type="checkbox"]') await checkbox.click()Finds the checkbox and clicks it, triggering the UI to start rendering the expensive component.
Wait for Expensive Component to Appear
const expensiveComponentHeading = page.locator('h2:has-text("Expensive Component")') await expect(expensiveComponentHeading).toBeVisible({ timeout: 60_000 })Waits up to 60 seconds for the heading of the component to appear in the DOM, indicating rendering has started.
Wait for Paint Completion
await page.waitForFunction(() => { return window.performance.getEntriesByName('expensive-component-painted').length > 0 }, { timeout: 5000 })Waits up to 5 seconds for the paint completion mark to be recorded, signaling rendering and paint are done.
Calculate Render Time
const renderTime = await page.evaluate(() => { const startMark = window.performance.getEntriesByName('state-change-start')[0] const paintMark = window.performance.getEntriesByName('expensive-component-painted')[0] if (!startMark || !paintMark) { throw new Error('Performance marks not found') } return paintMark.startTime - startMark.startTime })Retrieves the timing marks and calculates the render duration in milliseconds.
Assert Performance Requirement
expect(renderTime).toBeLessThan(1000)Fails the test if the render time exceeds 1000ms (1 second).
Important Implementation Details
MutationObserver
Used to detect DOM changes dynamically, specifically monitoring when the "Expensive Component" container and its child nodes are added during React rendering.
Double
requestAnimationFrameA technique to ensure that the browser has completed painting the UI after React rendering is complete before marking the end time. This avoids measuring only the JavaScript execution time and includes actual visual rendering.
Performance Marks
Uses the User Timing API (
performance.mark) to measure precise start and end points of rendering.Logging
Uses console logs inside the browser context to provide visibility into the rendering process (e.g., every 1000 rendered components).
Timeouts
60 seconds max to wait for the component heading to appear.
5 seconds max to wait for the paint completion mark.
Interaction with Other System Parts
UI Layer
This test interacts with the UI of the application, specifically a page at
./perfthat contains the Expensive Component and a checkbox to trigger rendering.React Rendering
The test indirectly measures React's reconciliation and rendering process by observing DOM mutations after the checkbox triggers a state change.
Performance Monitoring
Integrates with browser-native performance APIs to obtain accurate measurements of render times, which can feed into CI/CD performance regression checks.
Usage Example
This test script is intended to be run as part of the Playwright test suite:
npx playwright test perf.test.ts
The test will:
Load the
/perfpage.Click the checkbox.
Wait for the expensive component to fully render.
Assert the total render + paint duration is under 1 second.
If the test fails, it indicates a performance regression or slowdown in rendering this component.
Mermaid Diagram: Flowchart of Main Functions and Workflow
flowchart TD
A[Start Test] --> B[Navigate to ./perf page]
B --> C[Inject Performance Measurement Script]
C --> D[Set up MutationObserver to watch DOM changes]
C --> E[Attach click listener on checkbox to start timer]
D --> F[Detect Expensive Component container]
F --> G[Count rendered child components]
G -->|Rendered >= 10,000| H[Double requestAnimationFrame]
H --> I[Mark 'expensive-component-painted']
E --> J[Click checkbox to trigger rendering]
J --> K[Wait for Expensive Component heading visible]
K --> L[Wait for 'expensive-component-painted' mark]
L --> M[Calculate render duration]
M --> N[Assert renderTime < 1000ms]
N --> O[End Test]
Summary
perf.test.tsautomates a performance benchmark for a heavy React component.Uses Playwright for browser automation and in-page scripts for precise timing.
Employs MutationObserver and User Timing API for accurate render and paint measurement.
Ensures UI performance stays within acceptable limits (1 second render time).
Plays an integral role in performance regression detection within the overall testing strategy.