@itwin/certa
Version:
A mocha-based integration test runner
103 lines • 5.88 kB
JavaScript
;
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