Files
react-native-devtools-frontend/test/shared/runner.ts
T
Paul Lewis f57a5e85c0 [e2e] Migrates http/tests/devtools/user-metrics-perf.js to e2e
Original test at https://cs.chromium.org/chromium/src/third_party/blink/web_tests/http/tests/devtools/user-metrics-perf.js?q=http/tests/devtools/user-metrics-perf.js&sq=package:chromium&g=0&l=1

This is a stripped back version of the original layout test, since the
other user metrics e2e tests already test that we get shown events (and
not load events) when switching panels. Therefore this test only checks
that we get load events.

Bug: 1032561, 1046784
Change-Id: I460b3384ac313f75066478c8f809dc59b9b02d41
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2084582
Commit-Queue: Paul Lewis <aerotwist@chromium.org>
Reviewed-by: Tim van der Lippe <tvanderlippe@chromium.org>
2020-03-03 16:18:04 +00:00

292 lines
8.0 KiB
TypeScript

// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/* eslint-disable no-console */
// no-console disabled here as this is a test runner and expects to output to the console
import * as Mocha from 'mocha';
import * as puppeteer from 'puppeteer';
import {spawn} from 'child_process';
import {join} from 'path';
import {store} from './helper.js';
const testListPath = process.env['TEST_LIST'];
const envChromeBinary = process.env['CHROME_BIN'];
const envDebug = !!process.env['DEBUG'];
const envPort = process.env['PORT'] || 9222;
const envNoShuffle = !!process.env['NO_SHUFFLE'];
const envInteractive = !!process.env['INTERACTIVE'];
const interactivePage = 'http://localhost:8090/test/screenshots/interactive/index.html';
const blankPage = 'data:text/html,';
const headless = !envDebug;
const width = 1280;
const height = 720;
let mochaRun: Mocha.Runner;
let exitCode = 0;
function interruptionHandler() {
console.log('\n');
if (mochaRun) {
console.log('Aborting tests');
mochaRun.abort();
}
exitCode = 1;
shutdown();
}
function shutdown() {
console.log('\n');
console.log('Stopping hosted mode server');
hostedModeServer.kill();
console.log(`Exiting with status code ${exitCode}`);
process.exit(exitCode);
}
process.on('SIGINT', interruptionHandler);
process.on('SIGTERM', interruptionHandler);
process.on('uncaughtException', interruptionHandler);
process.stdin.resume();
if (!testListPath) {
throw new Error('Must specify a list of tests in the "TEST_LIST" environment variable.');
}
const launchArgs = [`--remote-debugging-port=${envPort}`];
// 1. Launch Chromium.
const opts: puppeteer.LaunchOptions = {
headless,
executablePath: envChromeBinary,
defaultViewport: null,
};
// Toggle either viewport or window size depending on headless vs not.
if (headless) {
opts.defaultViewport = {width, height};
}
else {
launchArgs.push(`--window-size=${width},${height}`);
}
opts.args = launchArgs;
const launchedBrowser = puppeteer.launch(opts);
const pages: puppeteer.Page[] = [];
// 2. Start DevTools hosted mode.
function handleHostedModeError(data: Error) {
console.log(`Hosted mode server: ${data}`);
interruptionHandler();
}
console.log('Spawning hosted mode server');
const serverScriptPath = join(__dirname, '..', '..', 'scripts', 'hosted_mode', 'server.js');
const cwd = join(__dirname, '..', '..');
const {execPath} = process;
const hostedModeServer = spawn(execPath, [serverScriptPath], { cwd });
hostedModeServer.on('error', handleHostedModeError);
hostedModeServer.stderr.on('data', handleHostedModeError);
interface DevToolsTarget {
url: string;
id: string;
}
// 3. Spin up the test environment
(async function() {
try {
let screenshotPage: puppeteer.Page | undefined;
if (envInteractive) {
const screenshotBrowser = await puppeteer.launch({
headless: false,
executablePath: envChromeBinary,
defaultViewport: null,
args: [`--window-size=${width},${height}`],
});
screenshotPage = await screenshotBrowser.newPage();
await screenshotPage.goto(interactivePage, {waitUntil: ['domcontentloaded']});
}
const browser = await launchedBrowser;
// Load the target page.
const srcPage = await browser.newPage();
await srcPage.goto(blankPage);
pages.push(srcPage);
// Now get the DevTools listings.
const devtools = await browser.newPage();
await devtools.goto(`http://localhost:${envPort}/json`);
// Find the appropriate item to inspect the target page.
const listing = await devtools.$('pre');
const json = await devtools.evaluate(listing => listing.textContent, listing);
const targets: DevToolsTarget[] = JSON.parse(json);
const target = targets.find(target => target.url === blankPage);
if (!target) {
throw new Error(`Unable to find target page: ${blankPage}`);
}
const {id} = target;
await devtools.close();
// Connect to the DevTools frontend.
const frontend = await browser.newPage();
const frontendUrl = `http://localhost:8090/front_end/devtools_app.html?ws=localhost:${envPort}/devtools/page/${id}`;
await frontend.goto(frontendUrl, {waitUntil: ['networkidle2', 'domcontentloaded']});
frontend.on('error', err => {
console.log('Error in Frontend');
console.log(err);
});
frontend.on('pageerror', err => {
console.log('Page Error in Frontend');
console.log(err);
});
const resetPages =
async (opts: {enabledExperiments?: string[], selectedPanel?: {name: string, selector?: string}} = {}) => {
// Reload the target page.
await srcPage.goto(blankPage, {waitUntil: ['domcontentloaded']});
// Clear any local storage settings.
await frontend.evaluate(() => localStorage.clear());
const { enabledExperiments } = opts;
let { selectedPanel } = opts;
await frontend.evaluate(enabledExperiments => {
for (const experiment of enabledExperiments) {
// @ts-ignore
globalThis.Root.Runtime.experiments.setEnabled(experiment, true);
}
}, enabledExperiments || []);
if (selectedPanel) {
await frontend.evaluate(name => {
// @ts-ignore
globalThis.localStorage.setItem('panel-selectedTab', `"${name}"`);
}, selectedPanel.name);
}
// Reload the DevTools frontend and await the elements panel.
await frontend.goto(blankPage, {waitUntil: ['domcontentloaded']});
await frontend.goto(frontendUrl, {waitUntil: ['domcontentloaded']});
// Default to elements if no other panel is defined.
if (!selectedPanel) {
selectedPanel = {
name: 'elements',
selector: '.elements',
};
}
if (!selectedPanel.selector) {
return;
}
// For the unspecified case wait for loading, then wait for the elements panel.
await frontend.waitForSelector(selectedPanel.selector);
};
store(browser, srcPage, frontend, screenshotPage, resetPages);
// 3. Run tests.
do {
if (envDebug) {
logHelp();
}
await waitForInput();
await runTests();
if (envDebug) {
await resetPages();
}
} while (envDebug);
} catch (err) {
console.warn(err);
} finally {
shutdown();
}
})();
async function waitForInput() {
return new Promise(resolve => {
if (!envDebug) {
resolve();
return;
}
process.stdin.setRawMode(true);
process.stdin.resume();
process.stdin.on('data', async str => {
// Listen for ctrl+c to exit.
if (str.toString() === '\x03') {
interruptionHandler();
}
resolve();
});
});
}
async function runTests() {
const {testList} = await import(testListPath!);
const shuffledTests = shuffleTestFiles(testList);
return new Promise(resolve => {
const mocha = new Mocha();
for (const test of shuffledTests) {
mocha.addFile(test);
}
mocha.ui('bdd');
mocha.reporter('list');
mocha.timeout((envDebug || envInteractive) ? 300000 : 4000);
mochaRun = mocha.run();
mochaRun.on('end', () => {
(mocha as any).unloadFiles();
resolve();
});
mochaRun.on('fail', () => {
exitCode = 1;
});
});
}
function logHelp() {
console.log('Running in debug mode.');
console.log(' - Press any key to run the test suite.');
console.log(' - Press ctrl + c to quit.');
hostedModeServer.stdout.on('data', (message: any) => {
console.log(`Hosted mode server: ${message}`);
});
}
function shuffleTestFiles(files: string[]) {
if (envNoShuffle) {
console.log('Running tests unshuffled');
return files;
}
const swap = (arr: string[], a: number, b: number) => {
const temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
};
for (let i = files.length; i >= 0; i--) {
const a = Math.floor(Math.random() * files.length);
const b = Math.floor(Math.random() * files.length);
swap(files, a, b);
}
console.log(`Running tests in the following order:\n${files.join('\n')}`);
return files;
}