UNPKG

@itwin/certa

Version:

A mocha-based integration test runner

103 lines 5.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ChromeTestRunner = void 0; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ const path = require("path"); const playwright_1 = require("playwright"); const SpawnUtils_1 = require("../../utils/SpawnUtils"); const CallbackUtils_1 = require("../../utils/CallbackUtils"); const CoverageUtils_1 = require("../../utils/CoverageUtils"); const MochaRemoteReporter_1 = require("./MochaRemoteReporter"); let browser; let webserverProcess; class ChromeTestRunner { static supportsCoverage = true; static supportsCleanup = true; static async initialize(config) { // Go ahead and launch playwright now - the VS Code debugger gets confused if it can't at least see the chrome instance right away. const options = { args: config.chromeOptions.args, headless: !config.debug, }; if (config.debug) options.args?.push(`--disable-gpu`, `--remote-debugging-port=${config.ports.frontendDebugging}`); browser = await playwright_1.chromium.launch(options); const webserverEnv = { CERTA_PORT: `${config.ports.frontend}`, // eslint-disable-line @typescript-eslint/naming-convention CERTA_PATH: path.join(__dirname, "../../../public/index.html"), // eslint-disable-line @typescript-eslint/naming-convention CERTA_PUBLIC_DIRS: JSON.stringify(config.chromeOptions.publicDirs), // eslint-disable-line @typescript-eslint/naming-convention }; webserverProcess = (0, SpawnUtils_1.spawnChildProcess)("node", [require.resolve("./webserver")], webserverEnv, true); // Don't continue until the webserver is started and listening. const webserverExited = new Promise((_resolve, reject) => webserverProcess.once("exit", () => reject(new Error("Webserver exited!")))); const webserverStarted = new Promise((resolve) => webserverProcess.once("message", resolve)); const actualPort = await Promise.race([webserverExited, webserverStarted]); if (actualPort !== config.ports.frontend) console.warn(`CERTA: Port ${config.ports.frontend} was already in use, so serving test resources on port ${actualPort}`); process.env.CERTA_PORT = String(actualPort); } static async runTests(config) { // FIXME: Do we really want to always enforce this behavior? if (process.env.CI || process.env.TF_BUILD) config.mochaOptions.forbidOnly = true; const { failures, coverage } = await runTestsInPlaywright(config, process.env.CERTA_PORT); webserverProcess.kill(); // Save nyc/istanbul coverage file. if (config.cover) (0, CoverageUtils_1.writeCoverageData)(coverage); process.exitCode = failures; } } exports.ChromeTestRunner = ChromeTestRunner; async function loadScript(page, scriptPath) { return page.addScriptTag({ url: `/@/${scriptPath}` }); } async function runTestsInPlaywright(config, port) { return new Promise(async (resolve, reject) => { try { const page = browser.contexts().pop()?.pages()?.pop() || await browser.newPage(); // Don't let dialogs block tests page.on("dialog", async (dialog) => dialog.dismiss()); // Re-throw any uncaught exceptions from the frontend in the backend page.on("pageerror", reject); // Expose some functions to the frontend that will execute _in the backend context_ await page.exposeFunction("_CertaConsole", (type, args) => console[type](...args)); await page.exposeFunction("_CertaSendToBackend", CallbackUtils_1.executeRegisteredCallback); await page.exposeFunction("_CertaReportResults", (results) => { setTimeout(async () => { await browser.close(); resolve(results); }); }); // Now load the page (and requisite scripts)... const testBundle = (config.cover && config.instrumentedTestBundle) || config.testBundle; await page.goto(`http://localhost:${port}`); await page.addScriptTag({ content: `var _CERTA_CONFIG = ${JSON.stringify(config)};` }); await loadScript(page, require.resolve("../../utils/initLogging.js")); await loadScript(page, require.resolve("mocha/mocha.js")); await loadScript(page, require.resolve("source-map-support/browser-source-map-support.js")); await loadScript(page, require.resolve("../../utils/initSourceMaps.js")); await loadScript(page, require.resolve("./MochaSerializer.js")); await (0, MochaRemoteReporter_1.configureRemoteReporter)(page); await loadScript(page, require.resolve("../../utils/initMocha.js")); await loadScript(page, testBundle); // ...and start the tests await page.evaluate(async () => { // NB: This is being evaluated in the frontend context! Mocha.reporters.Base.color = true; const globals = window; mocha.run((failures) => { const coverage = globals.__coverage__; globals._CertaReportResults({ failures, coverage }); // This will close the browser }); }); } catch (error) { reject(error); // eslint-disable-line @typescript-eslint/prefer-promise-reject-errors } }); } //# sourceMappingURL=ChromeTestRunner.js.map