@wdio/lighthouse-service 9.0.0-alpha.369 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,3 @@
1
- /// <reference types="src/@types/lighthouse.js" />
2
1
  import CriConnection from 'lighthouse/lighthouse-core/gather/connections/cri.js';
3
2
  /**
4
3
  * this class got patched to enable connecting to a remote path like
@@ -1 +1 @@
1
- {"version":3,"file":"cri.d.ts","sourceRoot":"","sources":["../../src/lighthouse/cri.ts"],"names":[],"mappings":";AAAA,OAAO,aAAa,MAAM,sDAAsD,CAAA;AAKhF;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,aAAa;IAC5D,OAAO,CAAC,UAAU,CAAC,CAAQ;IAE3B;;;;;OAKG;gBACS,IAAI,GAAE,MAAqB,EAAE,QAAQ,GAAE,MAAyB;IAI5E,YAAY,CAAE,SAAS,EAAE,MAAM;IAI/B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE;CAGtE"}
1
+ {"version":3,"file":"cri.d.ts","sourceRoot":"","sources":["../../src/lighthouse/cri.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,MAAM,sDAAsD,CAAA;AAKhF;;;;GAIG;AACH,MAAM,CAAC,OAAO,OAAO,qBAAsB,SAAQ,aAAa;IAC5D,OAAO,CAAC,UAAU,CAAC,CAAQ;IAE3B;;;;;OAKG;gBACS,IAAI,GAAE,MAAqB,EAAE,QAAQ,GAAE,MAAyB;IAI5E,YAAY,CAAE,SAAS,EAAE,MAAM;IAI/B;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,GAAG,EAAE;CAGtE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wdio/lighthouse-service",
3
- "version": "9.0.0-alpha.369+43868ec82",
3
+ "version": "9.0.0",
4
4
  "description": "A WebdriverIO service that allows you to run Chrome DevTools commands in your tests",
5
5
  "author": "Christian Bromann <mail@bromann.dev>",
6
6
  "homepage": "https://github.com/webdriverio/webdriverio/tree/main/packages/wdio-lighthouse-service",
@@ -33,24 +33,26 @@
33
33
  "type": "module",
34
34
  "types": "./build/index.d.ts",
35
35
  "exports": {
36
- ".": "./build/index.js",
37
- "./package.json": "./package.json"
36
+ ".": {
37
+ "types": "./build/index.d.ts",
38
+ "import": "./build/index.js"
39
+ }
38
40
  },
39
41
  "typeScriptVersion": "3.8.3",
40
42
  "dependencies": {
41
43
  "@babel/core": "^7.18.0",
42
44
  "@tracerbench/trace-event": "^8.0.0",
43
45
  "@types/node": "^20.1.0",
44
- "@wdio/logger": "9.0.0-alpha.369+43868ec82",
45
- "@wdio/types": "9.0.0-alpha.369+43868ec82",
46
+ "@wdio/logger": "9.0.0",
47
+ "@wdio/types": "9.0.0",
46
48
  "babel-plugin-istanbul": "^6.1.1",
47
- "devtools-protocol": "^0.0.1323829",
49
+ "devtools-protocol": "^0.0.1340018",
48
50
  "istanbul-lib-coverage": "^3.2.0",
49
51
  "istanbul-lib-report": "^3.0.0",
50
52
  "istanbul-reports": "^3.1.4",
51
53
  "lighthouse": "8.6.0",
52
- "puppeteer-core": "22.12.1",
53
- "webdriverio": "9.0.0-alpha.369+43868ec82"
54
+ "puppeteer-core": "23.0.2",
55
+ "webdriverio": "9.0.0"
54
56
  },
55
57
  "publishConfig": {
56
58
  "access": "public"
@@ -60,7 +62,7 @@
60
62
  "@types/istanbul-lib-coverage": "^2.0.6",
61
63
  "@types/istanbul-lib-report": "^3.0.0",
62
64
  "@types/istanbul-reports": "^3.0.4",
63
- "@wdio/globals": "9.0.0-alpha.369+43868ec82"
65
+ "@wdio/globals": "9.0.0"
64
66
  },
65
- "gitHead": "43868ec82075db90009f00bb737f6df0f1744ca6"
67
+ "gitHead": "957693463371a4cb329395dcdbce8fb0c930ab93"
66
68
  }
package/build/auditor.js DELETED
@@ -1,147 +0,0 @@
1
- import Diagnostics from 'lighthouse/lighthouse-core/audits/diagnostics.js';
2
- import MainThreadWorkBreakdown from 'lighthouse/lighthouse-core/audits/mainthread-work-breakdown.js';
3
- import Metrics from 'lighthouse/lighthouse-core/audits/metrics.js';
4
- import ServerResponseTime from 'lighthouse/lighthouse-core/audits/server-response-time.js';
5
- import CumulativeLayoutShift from 'lighthouse/lighthouse-core/audits/metrics/cumulative-layout-shift.js';
6
- import FirstContentfulPaint from 'lighthouse/lighthouse-core/audits/metrics/first-contentful-paint.js';
7
- import LargestContentfulPaint from 'lighthouse/lighthouse-core/audits/metrics/largest-contentful-paint.js';
8
- import SpeedIndex from 'lighthouse/lighthouse-core/audits/metrics/speed-index.js';
9
- import InteractiveMetric from 'lighthouse/lighthouse-core/audits/metrics/interactive.js';
10
- import TotalBlockingTime from 'lighthouse/lighthouse-core/audits/metrics/total-blocking-time.js';
11
- import ReportScoring from 'lighthouse/lighthouse-core/scoring.js';
12
- import defaultConfig from 'lighthouse/lighthouse-core/config/default-config.js';
13
- import logger from '@wdio/logger';
14
- import { DEFAULT_FORM_FACTOR, PWA_AUDITS } from './constants.js';
15
- const log = logger('@wdio/lighthouse-service:Auditor');
16
- export default class Auditor {
17
- _traceLogs;
18
- _devtoolsLogs;
19
- _formFactor;
20
- _url;
21
- constructor(_traceLogs, _devtoolsLogs, _formFactor) {
22
- this._traceLogs = _traceLogs;
23
- this._devtoolsLogs = _devtoolsLogs;
24
- this._formFactor = _formFactor;
25
- if (_traceLogs) {
26
- this._url = _traceLogs.pageUrl;
27
- }
28
- }
29
- _audit(AUDIT, params = {}) {
30
- const auditContext = {
31
- options: {
32
- ...AUDIT.defaultOptions
33
- },
34
- settings: {
35
- throttlingMethod: 'devtools',
36
- formFactor: this._formFactor || DEFAULT_FORM_FACTOR
37
- },
38
- LighthouseRunWarnings: false,
39
- computedCache: new Map()
40
- };
41
- try {
42
- return AUDIT.audit({
43
- traces: { defaultPass: this._traceLogs },
44
- devtoolsLogs: { defaultPass: this._devtoolsLogs },
45
- TestedAsMobileDevice: true,
46
- GatherContext: { gatherMode: 'navigation' },
47
- ...params
48
- }, auditContext);
49
- }
50
- catch (error) {
51
- log.error(error);
52
- return {
53
- score: 0,
54
- error
55
- };
56
- }
57
- }
58
- /**
59
- * an Auditor instance is created for every trace so provide an updateCommands
60
- * function to receive the latest performance metrics with the browser instance
61
- */
62
- updateCommands(browser, customFn) {
63
- const commands = Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter(fnName => fnName !== 'constructor' && fnName !== 'updateCommands' && !fnName.startsWith('_'));
64
- commands.forEach(fnName => browser.addCommand(fnName, customFn || this[fnName].bind(this)));
65
- }
66
- /**
67
- * Returns a list with a breakdown of all main thread task and their total duration
68
- */
69
- async getMainThreadWorkBreakdown() {
70
- const result = await this._audit(MainThreadWorkBreakdown);
71
- return result.details.items.map(({ group, duration }) => ({ group, duration }));
72
- }
73
- /**
74
- * Get some useful diagnostics about the page load
75
- */
76
- async getDiagnostics() {
77
- const result = await this._audit(Diagnostics);
78
- /**
79
- * return null if Audit fails
80
- */
81
- if (!Object.prototype.hasOwnProperty.call(result, 'details')) {
82
- return null;
83
- }
84
- return result.details.items[0];
85
- }
86
- /**
87
- * Get most common used performance metrics
88
- */
89
- async getMetrics() {
90
- const serverResponseTime = await this._audit(ServerResponseTime, { URL: this._url });
91
- const cumulativeLayoutShift = await this._audit(CumulativeLayoutShift);
92
- const result = await this._audit(Metrics);
93
- const metrics = result.details.items[0] || {};
94
- return {
95
- timeToFirstByte: Math.round(serverResponseTime.numericValue),
96
- serverResponseTime: Math.round(serverResponseTime.numericValue),
97
- domContentLoaded: metrics.observedDomContentLoaded,
98
- firstVisualChange: metrics.observedFirstVisualChange,
99
- firstPaint: metrics.observedFirstPaint,
100
- firstContentfulPaint: metrics.firstContentfulPaint,
101
- firstMeaningfulPaint: metrics.firstMeaningfulPaint,
102
- largestContentfulPaint: metrics.largestContentfulPaint,
103
- lastVisualChange: metrics.observedLastVisualChange,
104
- interactive: metrics.interactive,
105
- load: metrics.observedLoad,
106
- speedIndex: metrics.speedIndex,
107
- totalBlockingTime: metrics.totalBlockingTime,
108
- maxPotentialFID: metrics.maxPotentialFID,
109
- cumulativeLayoutShift: cumulativeLayoutShift.numericValue,
110
- };
111
- }
112
- /**
113
- * Returns the Lighthouse Performance Score which is a weighted mean of the following metrics: firstMeaningfulPaint, interactive, speedIndex
114
- */
115
- async getPerformanceScore() {
116
- const auditResults = {
117
- 'speed-index': await this._audit(SpeedIndex),
118
- 'first-contentful-paint': await this._audit(FirstContentfulPaint),
119
- 'largest-contentful-paint': await this._audit(LargestContentfulPaint),
120
- 'cumulative-layout-shift': await this._audit(CumulativeLayoutShift),
121
- 'total-blocking-time': await this._audit(TotalBlockingTime),
122
- interactive: await this._audit(InteractiveMetric)
123
- };
124
- if (!auditResults.interactive || !auditResults['cumulative-layout-shift'] || !auditResults['first-contentful-paint'] ||
125
- !auditResults['largest-contentful-paint'] || !auditResults['speed-index'] || !auditResults['total-blocking-time']) {
126
- log.info('One or multiple required metrics couldn\'t be found, setting performance score to: null');
127
- return null;
128
- }
129
- const scores = defaultConfig.categories.performance.auditRefs.filter((auditRef) => auditRef.weight).map((auditRef) => ({
130
- score: auditResults[auditRef.id].score,
131
- weight: auditRef.weight,
132
- }));
133
- return ReportScoring.arithmeticMean(scores);
134
- }
135
- async _auditPWA(params, auditsToBeRun = Object.keys(PWA_AUDITS)) {
136
- const audits = await Promise.all(Object.entries(PWA_AUDITS)
137
- .filter(([name]) => auditsToBeRun.includes(name))
138
- .map(async ([name, Audit]) => [name, await this._audit(Audit, params)]));
139
- return {
140
- passed: !audits.find(([, result]) => result.score < 1),
141
- details: audits.reduce((details, [name, result]) => {
142
- details[name] = result;
143
- return details;
144
- }, {})
145
- };
146
- }
147
- }
package/build/commands.js DELETED
@@ -1,212 +0,0 @@
1
- import logger from '@wdio/logger';
2
- import NetworkHandler from './handler/network.js';
3
- import { CLICK_TRANSITION, DEFAULT_THROTTLE_STATE, DEFAULT_TRACING_CATEGORIES, NETWORK_STATES } from './constants.js';
4
- import { sumByKey } from './utils.js';
5
- import DevtoolsGatherer from './gatherer/devtools.js';
6
- import Auditor from './auditor.js';
7
- import PWAGatherer from './gatherer/pwa.js';
8
- import TraceGatherer from './gatherer/trace.js';
9
- const log = logger('@wdio/lighthouse-service:CommandHandler');
10
- const TRACE_COMMANDS = ['click', 'navigateTo', 'url'];
11
- function isCDPSessionOnMessageObject(data) {
12
- return (data !== null &&
13
- typeof data === 'object' &&
14
- Object.prototype.hasOwnProperty.call(data, 'params') &&
15
- Object.prototype.hasOwnProperty.call(data, 'method'));
16
- }
17
- export default class CommandHandler {
18
- _session;
19
- _page;
20
- _driver;
21
- _options;
22
- _browser;
23
- _isTracing = false;
24
- _networkHandler;
25
- _traceEvents;
26
- _shouldRunPerformanceAudits = false;
27
- _cacheEnabled;
28
- _cpuThrottling;
29
- _networkThrottling;
30
- _formFactor;
31
- _traceGatherer;
32
- _devtoolsGatherer;
33
- _pwaGatherer;
34
- constructor(_session, _page, _driver, _options, _browser) {
35
- this._session = _session;
36
- this._page = _page;
37
- this._driver = _driver;
38
- this._options = _options;
39
- this._browser = _browser;
40
- this._networkHandler = new NetworkHandler(_session);
41
- this._traceGatherer = new TraceGatherer(_session, _page, _driver);
42
- this._pwaGatherer = new PWAGatherer(_session, _page, _driver);
43
- _session.on('Page.loadEventFired', this._traceGatherer.onLoadEventFired.bind(this._traceGatherer));
44
- _session.on('Page.frameNavigated', this._traceGatherer.onFrameNavigated.bind(this._traceGatherer));
45
- _page.on('requestfailed', this._traceGatherer.onFrameLoadFail.bind(this._traceGatherer));
46
- this._pwaGatherer = new PWAGatherer(_session, _page, _driver);
47
- /**
48
- * register browser commands
49
- */
50
- const commands = Object.getOwnPropertyNames(Object.getPrototypeOf(this)).filter(fnName => fnName !== 'constructor' && !fnName.startsWith('_'));
51
- commands.forEach(fnName => _browser.addCommand(fnName, this[fnName].bind(this)));
52
- this._devtoolsGatherer = new DevtoolsGatherer();
53
- _session.on('*', this._propagateWSEvents.bind(this));
54
- }
55
- /**
56
- * Start tracing the browser. You can optionally pass in custom tracing categories and the
57
- * sampling frequency.
58
- */
59
- startTracing({ categories = DEFAULT_TRACING_CATEGORIES, path, screenshots = true } = {}) {
60
- if (this._isTracing) {
61
- throw new Error('browser is already being traced');
62
- }
63
- this._isTracing = true;
64
- this._traceEvents = undefined;
65
- return this._page.tracing.start({ categories, path, screenshots });
66
- }
67
- /**
68
- * Stop tracing the browser.
69
- */
70
- async endTracing() {
71
- if (!this._isTracing) {
72
- throw new Error('No tracing was initiated, call `browser.startTracing()` first');
73
- }
74
- try {
75
- const traceBuffer = await this._page.tracing.stop();
76
- if (!traceBuffer) {
77
- throw new Error('No tracebuffer captured');
78
- }
79
- this._traceEvents = JSON.parse(traceBuffer.toString('utf8'));
80
- this._isTracing = false;
81
- }
82
- catch (err) {
83
- throw new Error(`Couldn't parse trace events: ${err.message}`);
84
- }
85
- return this._traceEvents;
86
- }
87
- /**
88
- * Returns the tracelogs that was captured within the tracing period.
89
- * You can use this command to store the trace logs on the file system to analyse the trace
90
- * via Chrome DevTools interface.
91
- */
92
- getTraceLogs() {
93
- return this._traceEvents;
94
- }
95
- /**
96
- * Returns page weight information of the last page load.
97
- */
98
- getPageWeight() {
99
- const requestTypes = Object.values(this._networkHandler.requestTypes).filter(Boolean);
100
- const pageWeight = sumByKey(requestTypes, 'size');
101
- const transferred = sumByKey(requestTypes, 'encoded');
102
- const requestCount = sumByKey(requestTypes, 'count');
103
- return { pageWeight, transferred, requestCount, details: this._networkHandler.requestTypes };
104
- }
105
- /**
106
- * set flag to run performance audits for page transitions
107
- */
108
- enablePerformanceAudits({ networkThrottling, cpuThrottling, cacheEnabled, formFactor } = DEFAULT_THROTTLE_STATE) {
109
- if (!NETWORK_STATES[networkThrottling]) {
110
- throw new Error(`Network throttling profile "${networkThrottling}" is unknown, choose between ${Object.keys(NETWORK_STATES).join(', ')}`);
111
- }
112
- if (typeof cpuThrottling !== 'number') {
113
- throw new Error(`CPU throttling rate needs to be typeof number but was "${typeof cpuThrottling}"`);
114
- }
115
- this._networkThrottling = networkThrottling;
116
- this._cpuThrottling = cpuThrottling;
117
- this._cacheEnabled = Boolean(cacheEnabled);
118
- this._formFactor = formFactor;
119
- this._shouldRunPerformanceAudits = true;
120
- }
121
- /**
122
- * custom command to disable performance audits
123
- */
124
- disablePerformanceAudits() {
125
- this._shouldRunPerformanceAudits = false;
126
- }
127
- /**
128
- * helper method to set throttling profile
129
- */
130
- async setThrottlingProfile(networkThrottling = DEFAULT_THROTTLE_STATE.networkThrottling, cpuThrottling = DEFAULT_THROTTLE_STATE.cpuThrottling, cacheEnabled = DEFAULT_THROTTLE_STATE.cacheEnabled) {
131
- if (!this._page || !this._session) {
132
- throw new Error('No page or session has been captured yet');
133
- }
134
- await this._page.setCacheEnabled(Boolean(cacheEnabled));
135
- await this._session.send('Emulation.setCPUThrottlingRate', { rate: cpuThrottling });
136
- await this._session.send('Network.emulateNetworkConditions', NETWORK_STATES[networkThrottling]);
137
- }
138
- async checkPWA(auditsToBeRun) {
139
- const auditor = new Auditor();
140
- const artifacts = await this._pwaGatherer.gatherData();
141
- return auditor._auditPWA(artifacts, auditsToBeRun);
142
- }
143
- _propagateWSEvents(data) {
144
- if (!isCDPSessionOnMessageObject(data)) {
145
- return;
146
- }
147
- this._devtoolsGatherer?.onMessage(data);
148
- const method = data.method || 'event';
149
- try {
150
- // can fail due to "Cannot convert a Symbol value to a string"
151
- log.debug(`cdp event: ${method} with params ${JSON.stringify(data.params)}`);
152
- }
153
- catch {
154
- // ignore
155
- }
156
- if (this._browser) {
157
- this._browser.emit(method, data.params);
158
- }
159
- }
160
- async _initCommand() {
161
- /**
162
- * enable domains for client
163
- */
164
- await Promise.all(['Page', 'Network', 'Runtime'].map((domain) => Promise.all([
165
- this._session?.send(`${domain}.enable`)
166
- ])));
167
- }
168
- _beforeCmd(commandName, params) {
169
- const isCommandNavigation = ['url', 'navigateTo'].some(cmdName => cmdName === commandName);
170
- if (!this._shouldRunPerformanceAudits || !this._traceGatherer || this._traceGatherer.isTracing || !TRACE_COMMANDS.includes(commandName)) {
171
- return;
172
- }
173
- /**
174
- * set browser profile
175
- */
176
- this.setThrottlingProfile(this._networkThrottling, this._cpuThrottling, this._cacheEnabled);
177
- const url = isCommandNavigation
178
- ? params[0]
179
- : CLICK_TRANSITION;
180
- return this._traceGatherer.startTracing(url);
181
- }
182
- _afterCmd(commandName) {
183
- if (!this._traceGatherer || !this._traceGatherer.isTracing || !TRACE_COMMANDS.includes(commandName)) {
184
- return;
185
- }
186
- /**
187
- * update custom commands once tracing finishes
188
- */
189
- this._traceGatherer.once('tracingComplete', (traceEvents) => {
190
- const auditor = new Auditor(traceEvents, this._devtoolsGatherer?.getLogs(), this._formFactor);
191
- auditor.updateCommands(this._browser);
192
- });
193
- this._traceGatherer.once('tracingError', (err) => {
194
- const auditor = new Auditor();
195
- auditor.updateCommands(this._browser, /* istanbul ignore next */ () => {
196
- throw new Error(`Couldn't capture performance due to: ${err.message}`);
197
- });
198
- });
199
- return new Promise((resolve) => {
200
- log.info(`Wait until tracing for command ${commandName} finishes`);
201
- /**
202
- * wait until tracing stops
203
- */
204
- this._traceGatherer?.once('tracingFinished', async () => {
205
- log.info('Disable throttling');
206
- await this.setThrottlingProfile('online', 0, true);
207
- log.info('continuing with next WebDriver command');
208
- resolve();
209
- });
210
- });
211
- }
212
- }
@@ -1,150 +0,0 @@
1
- import InstallableManifest from 'lighthouse/lighthouse-core/audits/installable-manifest.js';
2
- import ServiceWorker from 'lighthouse/lighthouse-core/audits/service-worker.js';
3
- import SplashScreen from 'lighthouse/lighthouse-core/audits/splash-screen.js';
4
- import ThemedOmnibox from 'lighthouse/lighthouse-core/audits/themed-omnibox.js';
5
- import ContentWidth from 'lighthouse/lighthouse-core/audits/content-width.js';
6
- import Viewport from 'lighthouse/lighthouse-core/audits/viewport.js';
7
- import AppleTouchIcon from 'lighthouse/lighthouse-core/audits/apple-touch-icon.js';
8
- import MaskableIcon from 'lighthouse/lighthouse-core/audits/maskable-icon.js';
9
- import { throttling } from 'lighthouse/lighthouse-core/config/constants.js';
10
- /**
11
- * performance tracing categories
12
- */
13
- export const DEFAULT_TRACING_CATEGORIES = [
14
- // Exclude default categories. We'll be selective to minimize trace size
15
- '-*',
16
- // Used instead of 'toplevel' in Chrome 71+
17
- 'disabled-by-default-lighthouse',
18
- // Used for Cumulative Layout Shift metric
19
- 'loading',
20
- // All compile/execute events are captured by parent events in devtools.timeline..
21
- // But the v8 category provides some nice context for only <0.5% of the trace size
22
- 'v8',
23
- // Same situation here. This category is there for RunMicrotasks only, but with other teams
24
- // accidentally excluding microtasks, we don't want to assume a parent event will always exist
25
- 'v8.execute',
26
- // For extracting UserTiming marks/measures
27
- 'blink.user_timing',
28
- // Not mandatory but not used much
29
- 'blink.console',
30
- // Most of the events we need are from these two categories
31
- 'devtools.timeline',
32
- 'disabled-by-default-devtools.timeline',
33
- // Up to 450 (https://goo.gl/rBfhn4) JPGs added to the trace
34
- 'disabled-by-default-devtools.screenshot',
35
- // This doesn't add its own events, but adds a `stackTrace` property to devtools.timeline events
36
- 'disabled-by-default-devtools.timeline.stack',
37
- // Additional categories used by devtools. Not used by Lighthouse, but included to facilitate
38
- // loading traces from Lighthouse into the Performance panel.
39
- 'disabled-by-default-devtools.timeline.frame',
40
- 'latencyInfo',
41
- // CPU sampling profiler data only enabled for debugging purposes
42
- // 'disabled-by-default-v8.cpu_profiler',
43
- // 'disabled-by-default-v8.cpu_profiler.hires',
44
- ];
45
- /**
46
- * ignored urls in request logger
47
- */
48
- export const IGNORED_URLS = [
49
- 'data:,', // empty pages
50
- 'about:', // new tabs
51
- 'chrome-extension://' // all chrome extensions
52
- ];
53
- export const FRAME_LOAD_START_TIMEOUT = 2000;
54
- export const TRACING_TIMEOUT = 15000;
55
- export const MAX_TRACE_WAIT_TIME = 45000;
56
- export const DEFAULT_NETWORK_THROTTLING_STATE = 'online';
57
- export const DEFAULT_FORM_FACTOR = 'desktop';
58
- export const UNSUPPORTED_ERROR_MESSAGE = ('Can\'t connect to Chrome DevTools! The @wdio/lighthouse-service currently only supports Chrome and Chromium!\n\n' +
59
- 'Given that cloud vendors don\'t expose access to the Chrome DevTools Protocol this service also usually only works when ' +
60
- 'running tests locally or through a Selenium Grid (https://www.selenium.dev/documentation/grid/) v4 or higher.');
61
- export const NETWORK_STATES = {
62
- offline: {
63
- offline: true,
64
- latency: 0,
65
- downloadThroughput: 0,
66
- uploadThroughput: 0
67
- },
68
- GPRS: {
69
- offline: false,
70
- downloadThroughput: 50 * 1024 / 8,
71
- uploadThroughput: 20 * 1024 / 8,
72
- latency: 500
73
- },
74
- 'Regular 2G': {
75
- offline: false,
76
- downloadThroughput: 250 * 1024 / 8,
77
- uploadThroughput: 50 * 1024 / 8,
78
- latency: 300
79
- },
80
- 'Good 2G': {
81
- offline: false,
82
- downloadThroughput: 450 * 1024 / 8,
83
- uploadThroughput: 150 * 1024 / 8,
84
- latency: 150
85
- },
86
- 'Regular 3G': {
87
- offline: false,
88
- latency: throttling.mobileRegular3G.requestLatencyMs,
89
- // DevTools expects throughput in bytes per second rather than kbps
90
- downloadThroughput: Math.floor(throttling.mobileRegular3G.downloadThroughputKbps * 1024 / 8),
91
- uploadThroughput: Math.floor(throttling.mobileRegular3G.uploadThroughputKbps * 1024 / 8)
92
- },
93
- 'Good 3G': {
94
- offline: false,
95
- latency: throttling.mobileSlow4G.requestLatencyMs,
96
- // DevTools expects throughput in bytes per second rather than kbps
97
- downloadThroughput: Math.floor(throttling.mobileSlow4G.downloadThroughputKbps * 1024 / 8),
98
- uploadThroughput: Math.floor(throttling.mobileSlow4G.uploadThroughputKbps * 1024 / 8)
99
- },
100
- 'Regular 4G': {
101
- offline: false,
102
- downloadThroughput: 4 * 1024 * 1024 / 8,
103
- uploadThroughput: 3 * 1024 * 1024 / 8,
104
- latency: 20
105
- },
106
- 'DSL': {
107
- offline: false,
108
- downloadThroughput: 2 * 1024 * 1024 / 8,
109
- uploadThroughput: 1 * 1024 * 1024 / 8,
110
- latency: 5
111
- },
112
- 'Wifi': {
113
- offline: false,
114
- downloadThroughput: 30 * 1024 * 1024 / 8,
115
- uploadThroughput: 15 * 1024 * 1024 / 8,
116
- latency: 2
117
- },
118
- online: {
119
- offline: false,
120
- latency: 0,
121
- downloadThroughput: -1,
122
- uploadThroughput: -1
123
- }
124
- };
125
- export const CLICK_TRANSITION = 'click transition';
126
- export const DEFAULT_THROTTLE_STATE = {
127
- networkThrottling: DEFAULT_NETWORK_THROTTLING_STATE,
128
- cpuThrottling: 0,
129
- cacheEnabled: false,
130
- formFactor: DEFAULT_FORM_FACTOR
131
- };
132
- export const NETWORK_RECORDER_EVENTS = [
133
- 'Network.requestWillBeSent',
134
- 'Network.requestServedFromCache',
135
- 'Network.responseReceived',
136
- 'Network.dataReceived',
137
- 'Network.loadingFinished',
138
- 'Network.loadingFailed',
139
- 'Network.resourceChangedPriority'
140
- ];
141
- export const PWA_AUDITS = {
142
- isInstallable: InstallableManifest,
143
- serviceWorker: ServiceWorker,
144
- splashScreen: SplashScreen,
145
- themedOmnibox: ThemedOmnibox,
146
- contentWith: ContentWidth,
147
- viewport: Viewport,
148
- appleTouchIcon: AppleTouchIcon,
149
- maskableIcon: MaskableIcon
150
- };
@@ -1,12 +0,0 @@
1
- export default class DevtoolsGatherer {
2
- _logs = [];
3
- onMessage(msgObj) {
4
- this._logs.push(msgObj);
5
- }
6
- /**
7
- * retrieve logs and clean cache
8
- */
9
- getLogs() {
10
- return this._logs.splice(0, this._logs.length);
11
- }
12
- }
@@ -1,66 +0,0 @@
1
- import FRGatherer from 'lighthouse/lighthouse-core/fraggle-rock/gather/session.js';
2
- import pageFunctions from 'lighthouse/lighthouse-core/lib/page-functions.js';
3
- import NetworkRecorder from 'lighthouse/lighthouse-core/lib/network-recorder.js';
4
- import InstallabilityErrors from 'lighthouse/lighthouse-core/gather/gatherers/installability-errors.js';
5
- import WebAppManifest from 'lighthouse/lighthouse-core/gather/gatherers/web-app-manifest.js';
6
- import LinkElements from 'lighthouse/lighthouse-core/gather/gatherers/link-elements.js';
7
- import ViewportDimensions from 'lighthouse/lighthouse-core/gather/gatherers/viewport-dimensions.js';
8
- import serviceWorkers from 'lighthouse/lighthouse-core/gather/driver/service-workers.js';
9
- import collectMetaElements from '../scripts/collectMetaElements.js';
10
- import { NETWORK_RECORDER_EVENTS } from '../constants.js';
11
- export default class PWAGatherer {
12
- _session;
13
- _page;
14
- _driver;
15
- _frGatherer;
16
- _networkRecorder;
17
- _networkRecords = [];
18
- constructor(_session, _page, _driver) {
19
- this._session = _session;
20
- this._page = _page;
21
- this._driver = _driver;
22
- this._frGatherer = new FRGatherer(this._session);
23
- /**
24
- * setup network recorder
25
- */
26
- this._networkRecorder = new NetworkRecorder();
27
- NETWORK_RECORDER_EVENTS.forEach((method) => {
28
- this._session.on(method, (params) => this._networkRecorder.dispatch({ method, params }));
29
- });
30
- /**
31
- * clean up network records after every page load
32
- */
33
- this._page.on('load', () => {
34
- this._networkRecords = this._networkRecorder.getRawRecords();
35
- delete this._networkRecorder;
36
- this._networkRecorder = new NetworkRecorder();
37
- });
38
- }
39
- async gatherData() {
40
- const pageUrl = await this._page?.url();
41
- const passContext = {
42
- url: pageUrl,
43
- driver: this._driver
44
- };
45
- const loadData = {
46
- networkRecords: this._networkRecords
47
- };
48
- const linkElements = new LinkElements();
49
- const viewportDimensions = new ViewportDimensions();
50
- const { registrations } = await serviceWorkers.getServiceWorkerRegistrations(this._frGatherer);
51
- const { versions } = await serviceWorkers.getServiceWorkerVersions(this._frGatherer);
52
- return {
53
- URL: { requestedUrl: pageUrl, finalUrl: pageUrl },
54
- WebAppManifest: await WebAppManifest.getWebAppManifest(this._frGatherer, pageUrl),
55
- InstallabilityErrors: await InstallabilityErrors.getInstallabilityErrors(this._frGatherer),
56
- MetaElements: await this._driver.evaluate(collectMetaElements, {
57
- args: [],
58
- useIsolation: true,
59
- deps: [pageFunctions.getElementsInDocument],
60
- }),
61
- ViewportDimensions: await viewportDimensions.afterPass(passContext),
62
- ServiceWorker: { versions, registrations },
63
- LinkElements: await linkElements.afterPass(passContext, loadData)
64
- };
65
- }
66
- }