@wdio/devtools-service
Version:
A WebdriverIO service that allows you to run Chrome DevTools commands in your tests
159 lines (158 loc) • 6.47 kB
JavaScript
import CommandHandler from './commands.js';
import { setUnsupportedCommand, getLighthouseDriver } from './utils.js';
import { DEFAULT_THROTTLE_STATE, NETWORK_STATES } from './constants.js';
export default class DevToolsService {
_options;
_command = [];
_browser;
constructor(_options) {
this._options = _options;
}
async before(caps, specs, browser) {
this._browser = browser;
return await this._setupHandler();
}
async onReload() {
if (!this._browser) {
return;
}
return this._setupHandler();
}
async beforeCommand(commandName, params) {
return Promise.all(this._command.map(async (c) => await c._beforeCmd(commandName, params)));
}
async afterCommand(commandName) {
if (commandName === 'switchToWindow') {
await this._setupHandler();
}
return Promise.all(this._command.map(async (c) => await c._afterCmd(commandName)));
}
async after() {
for (const c of this._command) {
await c._logCoverage();
}
}
/**
* set flag to run performance audits for page transitions
*/
_enablePerformanceAudits({ networkThrottling, cpuThrottling, cacheEnabled, formFactor } = DEFAULT_THROTTLE_STATE) {
if (!NETWORK_STATES[networkThrottling]) {
throw new Error(`Network throttling profile "${networkThrottling}" is unknown, choose between ${Object.keys(NETWORK_STATES).join(', ')}`);
}
if (typeof cpuThrottling !== 'number') {
throw new Error(`CPU throttling rate needs to be typeof number but was "${typeof cpuThrottling}"`);
}
if (this._command.length === 1) {
this._command[0].enablePerformanceAudits({ networkThrottling, cpuThrottling, cacheEnabled, formFactor });
}
else {
for (const c of this._command) {
c.enablePerformanceAudits({ networkThrottling, cpuThrottling, cacheEnabled, formFactor });
}
}
}
/**
* custom command to disable performance audits
*/
_disablePerformanceAudits() {
if (this._command.length === 1) {
this._command[0].disablePerformanceAudits();
}
else {
for (const c of this._command) {
c.disablePerformanceAudits();
}
}
}
/**
* set device emulation
*/
async _emulateDevice(device, deviceOptions) {
if (this._command.length === 1) {
return await this._command[0].emulateDevice(device, deviceOptions);
}
return Promise.all(this._command.map(async (c) => await c.emulateDevice(device, deviceOptions)));
}
async _setThrottlingProfile(networkThrottling = DEFAULT_THROTTLE_STATE.networkThrottling, cpuThrottling = DEFAULT_THROTTLE_STATE.cpuThrottling, cacheEnabled = DEFAULT_THROTTLE_STATE.cacheEnabled) {
if (this._command.length === 1) {
this._command[0].setThrottlingProfile(networkThrottling, cpuThrottling, cacheEnabled);
}
else {
for (const c of this._command) {
c.setThrottlingProfile(networkThrottling, cpuThrottling, cacheEnabled);
}
}
}
async _checkPWA(auditsToBeRun) {
if (this._command.length === 1) {
return await this._command[0].checkPWA(auditsToBeRun);
}
return Promise.all(this._command.map(async (c) => await c.checkPWA(auditsToBeRun)));
}
async _getCoverageReport() {
if (this._command.length === 1) {
return this._command[0].getCoverageReport();
}
return await Promise.all(this._command.map(c => c.getCoverageReport()));
}
_cdp(domain, command, args = {}) {
if (this._command.length === 1) {
return this._command[0].cdp(domain, command, args);
}
return Promise.all(this._command.map(async (c) => await c.cdp(domain, command, args)));
}
async _setupHandler() {
if (!this._browser) {
return;
}
/**
* In case of switchToWindow, needs to not add more commands to the array
*/
this._command.length = 0;
/**
* To avoid if-else, gather all browser instances into an array
*/
const browsers = Object.keys(this._browser).includes('sessionId') ?
[this._browser] :
this._browser.instances.map(i => this._browser.getInstance(i));
for (const browser of browsers) {
const puppeteer = await browser.getPuppeteer().catch(() => undefined);
if (!puppeteer) {
return setUnsupportedCommand(browser);
}
/* istanbul ignore next */
if (!puppeteer) {
throw new Error('Could not initiate Puppeteer instance');
}
const url = await browser.getUrl();
const target = url !== 'data:,' ?
await puppeteer.waitForTarget(
/* istanbul ignore next */
(t) => t.url().includes(url)) :
await puppeteer.waitForTarget(
/* istanbul ignore next */
(t) => t.type() === 'page' || Boolean(t.browserContext().id));
/* istanbul ignore next */
if (!target) {
throw new Error('No page target found');
}
const page = await target.page() || null;
/* istanbul ignore next */
if (!page) {
throw new Error('No page found');
}
const session = await target.createCDPSession();
const driver = await getLighthouseDriver(session, target);
const cmd = new CommandHandler(session, page, driver, this._options, browser);
await cmd._initCommand();
this._command.push(cmd);
}
this._browser.addCommand('enablePerformanceAudits', this._enablePerformanceAudits.bind(this));
this._browser.addCommand('disablePerformanceAudits', this._disablePerformanceAudits.bind(this));
this._browser.addCommand('emulateDevice', this._emulateDevice.bind(this));
this._browser.addCommand('checkPWA', this._checkPWA.bind(this));
this._browser.addCommand('getCoverageReport', this._getCoverageReport.bind(this));
this._browser.addCommand('cdp', this._cdp.bind(this));
}
}
export * from './types.js';