UNPKG

playwright-performance-reporter

Version:

Measure and publish performance metrics from browser dev-tools when running playwright

135 lines (134 loc) 4.42 kB
import { nativeChromiumPlugins, } from '../plugins/index.js'; export class NetworkActivityObserver { options; name = 'networkActivity'; plugins = [ nativeChromiumPlugins.networkDomainPlugin, ]; includeDetailsInSampling; requestStartTimes; requestMethods; networkActivities; subscriptions; isEnabled; constructor(options) { this.options = options; this.includeDetailsInSampling = options?.includeDetailsInSampling ?? false; this.requestStartTimes = new Map(); this.requestMethods = new Map(); this.networkActivities = []; this.subscriptions = []; this.isEnabled = false; } /** * @inheritdoc */ async onStart(accumulator, developmentTools) { this.common(accumulator, developmentTools, true); } /** * @inheritdoc */ async onSampling(accumulator, developmentTools) { this.common(accumulator, developmentTools, this.includeDetailsInSampling); } /** * @inheritdoc */ async onStop(accumulator, developmentTools) { this.common(accumulator, developmentTools, true); } /** * Common function for all lifecycle hooks */ common(accumulator, client, includeDetails) { if (!this.isEnabled) { this.setupListeners(client); } const result = { ...this.calculateAggregatedMetrics(), networkActivities: includeDetails ? [...this.networkActivities] : [], }; Object.assign(accumulator, result); } /** * Setup network event listeners */ setupListeners(client) { this.isEnabled = true; // Listen for request start this.subscriptions.push(this.setupRequestWillBeSent(client), this.setupResponseReceived(client), this.setupLoadingFinished(client), this.setupLoadingFailed(client)); } /** * Setup requestWillBeSent event listener * * @param client */ setupRequestWillBeSent(client) { return client.Network.requestWillBeSent(cdpResponse => { this.requestStartTimes.set(cdpResponse.requestId, Date.now()); this.requestMethods.set(cdpResponse.requestId, cdpResponse.request.method); }); } /** * Setup responseReceived event listener * * @param client */ setupResponseReceived(client) { return client.Network.responseReceived(cdpResponse => { const { requestId } = cdpResponse; const startTime = this.requestStartTimes.get(requestId); if (!startTime) { return; } const activity = { requestId, url: cdpResponse.response.url, method: this.requestMethods.get(requestId) ?? 'UNKNOWN', status: cdpResponse.response.status, timestamp: startTime, }; activity.duration = Date.now() - startTime; this.networkActivities.push(activity); }); } /** * Setup loadingFinished event listener * * @param client */ setupLoadingFinished(client) { return client.Network.loadingFinished(cdpResponse => { const { requestId } = cdpResponse; const activity = this.networkActivities.find(a => a.requestId === requestId); if (activity) { activity.transferSize = cdpResponse.encodedDataLength; } }); } /** * Setup loadingFailed event listener * * @param client */ setupLoadingFailed(client) { return client.Network.loadingFailed(cdpResponse => { const { requestId } = cdpResponse; const activity = this.networkActivities.find(a => a.requestId === requestId); if (activity) { activity.duration = Date.now() - (this.requestStartTimes.get(requestId) ?? Date.now()); } }); } /** * Calculate aggregated metrics from collected activities */ calculateAggregatedMetrics() { return { totalNetworkRequests: this.networkActivities.length, totalNetworkTransferSize: this.networkActivities.reduce((sum, a) => sum + (a.transferSize ?? 0), 0), totalNetworkDuration: this.networkActivities.reduce((sum, a) => sum + (a.duration ?? 0), 0), }; } }