Skip to content

Commit 516e953

Browse files
feat: refactor waiting for page to load and update readme
1 parent 2a50d14 commit 516e953

File tree

10 files changed

+173
-44
lines changed

10 files changed

+173
-44
lines changed

Readme.md

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,13 @@
1212
<a href="https://github.com/Valiantsin2021/playwright-performance-metrics"><img src="https://img.shields.io/badge/Author-Valentin%20Lutchanka-blue" alt="playwright-performance-metrics author" /></a>
1313
<a href="https://github.com/Valiantsin2021/playwright-performance-metrics/actions/workflows/ci.yml"><img src="https://github.com/Valiantsin2021/playwright-performance-metrics/actions/workflows/ci.yml/badge.svg?branch=main" alt="playwright-performance-metrics ci tests" /></a>
1414
</p>
15+
<h3 align="center">A comprehensive performance metrics collector for Playwright tests. Collect and analyze web vital metrics, network timing, and resource usage in your Playwright tests.</h3>
16+
<img src="img\performance-UI.png" alt="Performance-UI" />
1517

16-
---
17-
18-
A comprehensive performance metrics collector for Playwright tests. Collect and analyze web vital metrics, network timing, and resource usage in your Playwright tests.
1918

2019
## Features
2120

22-
- Collect Web Vitals (LCP, FID, CLS)
21+
- Collect Web Vitals (LCP, CLS)
2322
- Network timing metrics (TTFB, resource timing)
2423
- Network condition emulation (3G, 4G, WiFi)
2524
- Resource usage tracking
@@ -117,7 +116,9 @@ npm install -D playwright-performance-metrics
117116

118117
## Usage
119118

120-
Basic usage:
119+
**Basic usage:**
120+
121+
* Note: it is important to wait the completion of the page load before collecting metrics.
121122

122123
```typescript
123124
import { test } from '@playwright/test';
@@ -126,8 +127,7 @@ import { PerformanceMetricsCollector } from 'playwright-performance-metrics';
126127
test('measure page performance', async ({ page }) => {
127128
const collector = new PerformanceMetricsCollector(page);
128129

129-
await page.goto('https://example.com');
130-
130+
await page.goto('https://example.com', { waitUntil: 'networkidle' })
131131
const metrics = await collector.collectMetrics({
132132
timeout: 10000,
133133
initialDelay: 1000
@@ -139,17 +139,37 @@ test('measure page performance', async ({ page }) => {
139139
'Largest Contentful Paint': metrics.largestContentfulPaint,
140140
'Cumulative Layout Shift': metrics.cumulativeLayoutShift
141141
});
142+
expect(metrics.pageloadTiming, 'Page load time is less than 2000ms').toBeLessThan(2000)
143+
expect(metrics.domCompleteTiming, 'DOM Complete is less than 900ms').toBeLessThan(900)
144+
expect(metrics.paint?.firstContentfulPaint, 'First Contentful Paint is less than 2000ms').toBeLessThan(2000)
145+
expect(metrics.paint?.firstPaint, 'First Paint is less than 1000ms').toBeLessThan(1000)
146+
expect(metrics.largestContentfulPaint, 'Largest Contentful Paint is less than 2500ms').toBeLessThan(2500)
147+
expect(metrics.cumulativeLayoutShift, 'Cumulative Layout Shift is less than 0.1').toBeLessThan(0.1)
148+
expect(metrics.totalBlockingTime, 'Total Blocking Time is less than 500ms').toBeLessThan(500)
149+
expect(metrics.totalBytes, 'Total bytes is less than 1.5 MB').toBeLessThan(1024 * 1024 * 1.5)
150+
expect(metrics.timeToFirstByte?.total, 'Time to first byte is less than 900ms').toBeLessThan(900)
151+
expect(metrics.timeToFirstByte.dns, 'DNS time is less than 100ms').toBeLessThan(100)
152+
expect(metrics.timeToFirstByte.wait, 'Wait time is less than 100ms').toBeLessThan(100)
153+
expect(metrics.timeToFirstByte.redirect, 'Redirect time is less than 100ms').toBeLessThan(100)
154+
expect(metrics.timeToFirstByte.tls, 'TLS time is less than 100ms').toBeLessThan(100)
155+
expect(metrics.timeToFirstByte.connection, 'Connection time is less than 100ms').toBeLessThan(100)
142156
});
143157
```
144158

145-
With network emulation:
159+
**With network emulation:**
160+
161+
Library provides predefined presets for network conditions.
162+
163+
- REGULAR_4G
164+
- SLOW_3G
165+
- FAST_WIFI
146166

147167
```typescript
148168
import { DefaultNetworkPresets } from 'playwright-performance-metrics';
149169

150170
test('measure performance with slow 3G', async ({ page }) => {
151171
const collector = new PerformanceMetricsCollector(page);
152-
172+
await page.goto('https://example.com', { waitUntil: 'networkidle' })
153173
const metrics = await collector.collectMetrics({
154174
networkConditions: DefaultNetworkPresets.SLOW_3G,
155175
timeout: 30000
@@ -159,6 +179,34 @@ test('measure performance with slow 3G', async ({ page }) => {
159179
});
160180
```
161181

182+
**With fixtures:**
183+
184+
```typescript
185+
// fixture.ts
186+
187+
import { test as base, expect } from '@playwright/test'
188+
import { PerformanceMetricsCollector } from 'playwright-performance-metrics'
189+
190+
const test = base.extend({
191+
collector: async ({ page }, use) => {
192+
const collector = new PerformanceMetricsCollector(page)
193+
await use(collector)
194+
}
195+
})
196+
197+
export { test, expect }
198+
199+
// test.spec.ts
200+
201+
import { expect, test } from './fixture.ts'
202+
203+
test('measure page performance', async ({ page, collector }) => {
204+
await page.goto('https://example.com', { waitUntil: 'networkidle' })
205+
const metrics = await collector.collectMetrics()
206+
expect(metrics.domCompleteTiming, 'DOM Complete is less than 900ms').toBeLessThan(900)
207+
expect(metrics.paint?.firstContentfulPaint, 'First Contentful Paint is less than 2000ms').toBeLessThan(2000)})
208+
})
209+
```
162210
## API Reference
163211

164212
### PerformanceMetricsCollector
@@ -173,15 +221,25 @@ constructor(page: Page)
173221

174222
#### Methods
175223

176-
##### collectMetrics(options?: PerformanceOptions): Promise<PerformanceMetrics>
224+
- ##### collectMetrics(options?: PerformanceOptions): Promise<PerformanceMetrics>
177225

178-
Collects performance metrics from the page.
226+
```typescript
227+
/**
228+
* Collect performance metrics from the page.
229+
* @param options - Options for metric collection.
230+
* @returns Collected performance metrics.
231+
*/
232+
```
179233

180-
Options:
181-
- `timeout`: Collection timeout in milliseconds
182-
- `initialDelay`: Initial delay before starting collection
183-
- `retryTimeout`: Maximum time to retry collecting metrics
184-
- `networkConditions`: Network conditions to emulate
234+
- ##### options:
235+
```typescript
236+
/** Maximum time to wait for metrics collection (ms) */
237+
timeout?: number
238+
/** Maximum time to retry collecting metrics (ms) */
239+
retryTimeout?: number
240+
/** Network emulation settings */
241+
networkConditions?: NetworkConditions
242+
```
185243

186244
### Network Presets
187245

dist/performance-metrics.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ class PerformanceMetricsCollector {
6262
* @returns Collected performance metrics.
6363
*/
6464
async collectMetrics(options = {}) {
65-
const { timeout = 10000, initialDelay = 1000, retryTimeout = 5000, networkConditions } = options
65+
const { timeout = 10000, retryTimeout = 5000, networkConditions } = options
6666
// Initialize network conditions if provided
6767
if (networkConditions) {
6868
await this.initialize(networkConditions)
6969
}
70-
// Wait for initial delay
71-
await this.page.waitForTimeout(initialDelay)
70+
// Wait for page to load
71+
await this.page.waitForLoadState('networkidle', { timeout })
7272
const results = {}
7373
// Collect navigation timing metrics
7474
const navigationTiming = await this.page.evaluate(() => {

dist/types.d.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,13 @@ export interface NetworkConditions {
1717
}
1818
/**
1919
* Configuration options for performance metrics collection
20-
* @property startMark - Performance mark to start measuring from
21-
* @property endMark - Performance mark to end measuring at
2220
* @property timeout - Maximum time to wait for metrics collection
23-
* @property initialDelay - Initial delay before starting collection
2421
* @property retryTimeout - Maximum time to retry collecting metrics
2522
* @property networkConditions - Network emulation settings
2623
*/
2724
export interface PerformanceOptions {
2825
/** Maximum time to wait for metrics collection (ms) */
2926
timeout?: number
30-
/** Initial delay before starting collection (ms) */
31-
initialDelay?: number
3227
/** Maximum time to retry collecting metrics (ms) */
3328
retryTimeout?: number
3429
/** Network emulation settings */

img/performance-UI.png

362 KB
Loading

package-lock.json

Lines changed: 11 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

playwright.config.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
// @ts-check
2-
import { defineConfig } from '@playwright/test'
2+
import { defineConfig, devices } from '@playwright/test'
33

44
/**
55
* @see https://playwright.dev/docs/test-configuration
66
*/
77
export default defineConfig({
8-
// workers: 3,
8+
workers: 1,
99
timeout: 45_000,
1010
expect: {
1111
timeout: 25_000
@@ -37,9 +37,7 @@ export default defineConfig({
3737
{
3838
name: 'Performance_tests',
3939
testMatch: /.*.spec.ts/,
40-
use: {
41-
channel: 'chrome'
42-
}
40+
use: { ...devices['Desktop Chrome'], channel: 'chrome' }
4341
}
4442
]
4543
})

src/performance-metrics.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ export class PerformanceMetricsCollector implements IPerformanceMetricsCollector
6969
* @returns Collected performance metrics.
7070
*/
7171
async collectMetrics(options: PerformanceOptions = {}): Promise<PerformanceMetrics> {
72-
const { timeout = 10000, initialDelay = 1000, retryTimeout = 5000, networkConditions } = options
72+
const { timeout = 10000, retryTimeout = 5000, networkConditions } = options
7373

7474
// Initialize network conditions if provided
7575
if (networkConditions) {
7676
await this.initialize(networkConditions)
7777
}
7878

79-
// Wait for initial delay
80-
await this.page.waitForTimeout(initialDelay)
79+
// Wait for page to load
80+
await this.page.waitForLoadState('networkidle', { timeout })
8181

8282
const results: PerformanceMetrics = {}
8383

src/types.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,13 @@ export interface NetworkConditions {
1818

1919
/**
2020
* Configuration options for performance metrics collection
21-
* @property startMark - Performance mark to start measuring from
22-
* @property endMark - Performance mark to end measuring at
2321
* @property timeout - Maximum time to wait for metrics collection
24-
* @property initialDelay - Initial delay before starting collection
2522
* @property retryTimeout - Maximum time to retry collecting metrics
2623
* @property networkConditions - Network emulation settings
2724
*/
2825
export interface PerformanceOptions {
2926
/** Maximum time to wait for metrics collection (ms) */
3027
timeout?: number
31-
/** Initial delay before starting collection (ms) */
32-
initialDelay?: number
3328
/** Maximum time to retry collecting metrics (ms) */
3429
retryTimeout?: number
3530
/** Network emulation settings */

tests/test-2.spec.ts

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// @ts-nocheck
2+
import { expect, test } from '@playwright/test'
3+
import fs from 'fs'
4+
import { PerformanceMetricsCollector } from '../src/performance-metrics'
5+
const results = []
6+
for (let i = 1; i < 2; i++) {
7+
test.describe('Performance with one unified command ' + i, async () => {
8+
const url = `https://playwright.dev`
9+
test.beforeEach(async ({ page }) => {
10+
await page.goto(url, { waitUntil: 'networkidle' })
11+
})
12+
test(i + ` Should load ${url} page in less than 2 second`, async ({ page }) => {
13+
const collector = new PerformanceMetricsCollector(page)
14+
const metrics = await collector.collectMetrics()
15+
results.push(metrics)
16+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
17+
expect(metrics.pageloadTiming).toBeLessThan(2000)
18+
expect(metrics.domCompleteTiming).toBeLessThan(2000)
19+
})
20+
test(i + ` Should load ${url} page with timeToFirstByte less than 500ms`, async ({ page }) => {
21+
const collector = new PerformanceMetricsCollector(page)
22+
const metrics = await collector.collectMetrics()
23+
results.push(metrics)
24+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
25+
expect(metrics.timeToFirstByte.total, 'Time to first byte is less than 500ms').toBeLessThan(500)
26+
expect(metrics.timeToFirstByte.dns, 'DNS time is less than 200ms').toBeLessThan(200)
27+
expect(metrics.timeToFirstByte.wait, 'Wait time is less than 200ms').toBeLessThan(200)
28+
expect(metrics.timeToFirstByte.redirect, 'Redirect time is less than 200ms').toBeLessThan(200)
29+
expect(metrics.timeToFirstByte.tls, 'TLS time is less than 200ms').toBeLessThan(200)
30+
expect(metrics.timeToFirstByte.connection, 'Connection time is less than 200ms').toBeLessThan(200)
31+
})
32+
test(i + ` Should load ${url} page with resourceTiming less than 500ms`, async ({ page }) => {
33+
const collector = new PerformanceMetricsCollector(page)
34+
const metrics = await collector.collectMetrics()
35+
results.push(metrics)
36+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
37+
const resourceTiming = await metrics.resourceTiming('redirection.js')
38+
expect(resourceTiming?.duration, 'Resource timing is less than 500ms').toBeLessThan(500)
39+
})
40+
test(i + ` Should load ${url} page with size less than 1.5 MB`, async ({ page }) => {
41+
const collector = new PerformanceMetricsCollector(page)
42+
const metrics = await collector.collectMetrics()
43+
results.push(metrics)
44+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
45+
expect(metrics.totalBytes, 'Total bytes is less than 1.5 MB').toBeLessThan(1024 * 1024 * 1.5)
46+
})
47+
test(i + ` Should measure paint timings for ${url}`, async ({ page }) => {
48+
const collector = new PerformanceMetricsCollector(page)
49+
const metrics = await collector.collectMetrics()
50+
results.push(metrics)
51+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
52+
expect(metrics.paint.firstContentfulPaint, 'First Contentful Paint is less than 1500ms').toBeLessThan(1500)
53+
expect(metrics.paint.firstPaint, 'First Paint is less than 1500ms').toBeLessThan(1500)
54+
})
55+
test(i + ` Should measure largestContentfulPaint for ${url}`, async ({ page }) => {
56+
const collector = new PerformanceMetricsCollector(page)
57+
const metrics = await collector.collectMetrics()
58+
results.push(metrics)
59+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
60+
expect(metrics.largestContentfulPaint, `Largest Contentful Paint (${metrics.largestContentfulPaint}ms) should be less than 500ms`).toBeLessThan(500)
61+
})
62+
test(i + ` Should measure cumulativeLayoutShift for ${url}`, async ({ page }) => {
63+
const collector = new PerformanceMetricsCollector(page)
64+
const metrics = await collector.collectMetrics()
65+
results.push(metrics)
66+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
67+
expect(metrics.cumulativeLayoutShift, `Cumulative Layout Shift (${metrics.cumulativeLayoutShift}) should be less than 0.1`).toBeLessThan(0.1)
68+
})
69+
test(i + ` Should measure totalBlockingTime for ${url}`, async ({ page }) => {
70+
const collector = new PerformanceMetricsCollector(page)
71+
const metrics = await collector.collectMetrics()
72+
results.push(metrics)
73+
fs.appendFileSync('results.json', JSON.stringify(metrics) + '\n')
74+
expect(metrics.totalBlockingTime, `Total Blocking Time (${metrics.totalBlockingTime}ms) should be less than 500ms`).toBeLessThan(500)
75+
})
76+
})
77+
}

tests/test.spec.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,8 @@ test('Measure website performance default options', async () => {
1010
await page.goto('')
1111
const basicMetrics = await collector.collectMetrics({
1212
timeout: 15000,
13-
initialDelay: 2000
13+
retryTimeout: 500
1414
})
15-
1615
console.log('Basic Metrics:', {
1716
'Time to First Byte': basicMetrics.timeToFirstByte?.total,
1817
'DOM Complete': basicMetrics.domCompleteTiming,
@@ -42,8 +41,7 @@ test('Slow Network metrics', async () => {
4241
const collector = new PerformanceMetricsCollector(page)
4342
const slowNetworkMetrics = await collector.collectMetrics({
4443
networkConditions: DefaultNetworkPresets.SLOW_3G,
45-
timeout: 30000,
46-
initialDelay: 1000
44+
timeout: 30000
4745
})
4846

4947
console.log('Slow 3G Metrics:', {

0 commit comments

Comments
 (0)