Files
discourse/test/run-qunit.js
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

340 lines
8.4 KiB
JavaScript
Raw Normal View History

2019-03-20 16:32:05 +11:00
/*eslint no-console: ["error", { allow: ["log", "error"] }] */
// Chrome QUnit Test Runner
// Author: David Taylor
// Requires chrome-launcher and chrome-remote-interface from npm
// An up-to-date version of chrome is also required
2013-06-18 13:44:20 -04:00
2021-01-27 12:39:20 +01:00
let args = process.argv.slice(2);
2015-08-25 10:42:19 +02:00
2018-04-23 14:41:29 +10:00
if (args.length < 1 || args.length > 3) {
console.log("Usage: node run-qunit.js <URL> <timeout> <result_file>");
process.exit(1);
2013-06-18 13:44:20 -04:00
}
2018-11-27 17:40:55 +11:00
const chromeLauncher = require("chrome-launcher");
const CDP = require("chrome-remote-interface");
2013-06-18 13:44:20 -04:00
2018-04-23 14:41:29 +10:00
const QUNIT_RESULT = args[2];
2018-11-27 17:40:55 +11:00
const fs = require("fs");
2018-04-23 14:41:29 +10:00
if (QUNIT_RESULT) {
(async () => {
await fs.stat(QUNIT_RESULT, (err, stats) => {
2020-09-23 12:52:11 +02:00
if (stats && stats.isFile()) {
fs.unlink(QUNIT_RESULT, (unlinkErr) => {
2019-03-20 16:32:05 +11:00
if (unlinkErr) {
console.log("Error deleting " + QUNIT_RESULT + " " + unlinkErr);
}
});
2020-09-23 12:52:11 +02:00
}
2018-04-23 14:41:29 +10:00
});
})();
}
async function runAllTests() {
function launchChrome() {
const options = {
chromeFlags: [
"--disable-gpu",
"--headless=new",
"--no-sandbox",
"--disable-dev-shm-usage",
"--mute-audio",
2020-09-23 12:52:11 +02:00
"--window-size=1440,900",
"--enable-precise-memory-info",
2020-09-23 12:52:11 +02:00
],
2018-04-23 14:41:29 +10:00
};
if (process.env.REMOTE_DEBUG) {
options.port = 9222;
}
return chromeLauncher.launch(options);
2013-06-18 13:44:20 -04:00
}
2018-04-23 14:41:29 +10:00
let chrome = await launchChrome();
let protocol = null;
let connectAttempts = 0;
while (!protocol) {
// Workaround for intermittent CI error caused by
// https://github.com/GoogleChrome/chrome-launcher/issues/145
try {
protocol = await CDP({ port: chrome.port, host: "127.0.0.1" });
} catch (e) {
if (e.message === "No inspectable targets" && connectAttempts < 50) {
connectAttempts++;
console.log(
"Unable to establish connection to chrome target - trying again..."
);
2020-09-23 12:52:11 +02:00
// eslint-disable-next-line
await new Promise((resolve) => setTimeout(resolve, 100));
} else {
throw e;
}
}
}
2018-04-23 14:41:29 +10:00
const { Inspector, Page, Runtime, Log } = protocol;
// eslint-disable-next-line
await Promise.all([
Inspector.enable(),
Page.enable(),
Runtime.enable(),
Log.enable(),
]);
// Documentation https://chromedevtools.github.io/devtools-protocol/tot/Log/#type-LogEntry
Log.entryAdded(({ entry }) => {
let message = `${new Date(entry.timestamp).toISOString()} - (type: ${
entry.source
}/${entry.level}) message: ${entry.text}`;
if (entry.url) {
message += `, url: ${entry.url}`;
}
console.log(message);
});
2018-04-23 14:41:29 +10:00
2020-09-23 12:52:11 +02:00
Inspector.targetCrashed((entry) => {
console.log("Chrome target crashed:");
console.log(entry);
});
2018-04-23 14:41:29 +10:00
2020-09-23 12:52:11 +02:00
Runtime.exceptionThrown((exceptionInfo) => {
console.log(exceptionInfo.exceptionDetails.exception.description);
});
2020-09-23 12:52:11 +02:00
Runtime.consoleAPICalled((response) => {
2018-11-27 17:40:55 +11:00
const message = response["args"][0].value;
2018-04-23 14:41:29 +10:00
2020-08-05 13:43:14 -04:00
// Not finished yet, don't add a newline
2022-03-10 20:43:17 +01:00
if (message?.startsWith?.("↪")) {
2018-04-23 14:41:29 +10:00
process.stdout.write(message);
2022-03-10 20:43:17 +01:00
} else if (message?.startsWith?.("AUTOSPEC:")) {
2018-04-23 14:41:29 +10:00
fs.appendFileSync(QUNIT_RESULT, `${message.slice(10)}\n`);
} else {
2022-03-10 20:43:17 +01:00
console.log(...response["args"].map((m) => m.value));
2018-04-23 14:41:29 +10:00
}
});
let url = args[0] + "&qunit_disable_auto_start=1";
const apiKey = process.env.ADMIN_API_KEY;
const apiUsername = process.env.ADMIN_API_USERNAME;
if (apiKey && apiUsername) {
const { Fetch } = protocol;
await Fetch.enable();
const urlObj = new URL(url);
Fetch.requestPaused((data) => {
const requestURL = new URL(data.request.url);
2022-04-02 21:15:38 +02:00
if (requestURL.hostname !== urlObj.hostname) {
Fetch.continueRequest({
requestId: data.requestId,
});
return;
}
Fetch.continueRequest({
requestId: data.requestId,
headers: [
{ name: "Api-Key", value: apiKey },
{ name: "Api-Username", value: apiUsername },
],
});
});
}
console.log("navigate to", url);
Page.navigate({ url });
2018-04-23 14:41:29 +10:00
Page.loadEventFired(async () => {
2020-08-05 16:27:06 -04:00
let qff = process.env.QUNIT_FAIL_FAST;
await Runtime.evaluate({
2020-08-05 13:43:14 -04:00
expression:
`const QUNIT_FAIL_FAST = ` +
2020-08-05 16:27:06 -04:00
(qff === "1" || qff === "true").toString() +
2020-09-23 12:52:11 +02:00
";",
2020-08-05 13:43:14 -04:00
});
await Runtime.evaluate({
2020-09-23 12:52:11 +02:00
expression: `(${qunit_script})();`,
});
2022-07-17 20:48:36 +02:00
if (args[0].includes("report_requests=1")) {
await Runtime.evaluate({
2020-09-23 12:52:11 +02:00
expression: "QUnit.config.logAllRequests = true",
});
}
2018-04-23 14:41:29 +10:00
const timeout = parseInt(args[1] || 300000, 10);
2021-01-27 12:39:20 +01:00
let start = Date.now();
2018-04-23 14:41:29 +10:00
2021-01-27 12:39:20 +01:00
let interval;
2018-04-23 14:41:29 +10:00
2020-09-23 12:52:11 +02:00
let runTests = async function () {
2018-04-23 14:41:29 +10:00
if (Date.now() > start + timeout) {
console.error("\n\nTests timed out\n");
2018-04-23 14:41:29 +10:00
protocol.close();
chrome.kill();
process.exit(124);
}
2018-11-27 17:40:55 +11:00
let numFails = await Runtime.evaluate({
2020-09-23 12:52:11 +02:00
expression: `(${check_script})()`,
2018-11-27 17:40:55 +11:00
});
2018-04-23 14:41:29 +10:00
2018-11-27 17:40:55 +11:00
if (numFails && numFails.result && numFails.result.type !== "undefined") {
2018-04-23 14:41:29 +10:00
clearInterval(interval);
protocol.close();
chrome.kill();
if (numFails.result.value > 0) {
process.exit(1);
} else {
process.exit();
}
}
};
interval = setInterval(runTests, 250);
});
}
2020-09-23 12:52:11 +02:00
runAllTests().catch((e) => {
2018-04-23 14:41:29 +10:00
console.log("Failed to run tests: " + e);
process.exit(1);
2019-12-11 16:50:31 +00:00
});
// The following functions are converted to strings
// And then sent to chrome to be evaluated
2013-06-18 13:44:20 -04:00
function logQUnit() {
2022-04-02 21:15:38 +02:00
const QUnit = window.QUnit;
2020-08-05 13:43:14 -04:00
let testErrors = [];
let assertionErrors = [];
2013-06-18 13:44:20 -04:00
console.log("\nRunning: " + JSON.stringify(QUnit.urlParams) + "\n");
2018-04-23 14:41:29 +10:00
let durations = {};
2020-08-05 13:43:14 -04:00
let inTest = false;
2020-09-23 12:52:11 +02:00
QUnit.testStart(function (context) {
2020-08-05 13:43:14 -04:00
console.log("↪ " + context.module + "::" + context.name);
inTest = true;
});
2020-09-23 12:52:11 +02:00
QUnit.testDone(function (context) {
2018-04-23 14:41:29 +10:00
durations[context.module + "::" + context.name] = context.runtime;
2013-06-18 13:44:20 -04:00
if (context.failed) {
2020-08-05 13:43:14 -04:00
const msg =
" Test Failed: " +
context.name +
assertionErrors.join(" ") +
"\n" +
context.source;
2013-06-18 13:44:20 -04:00
testErrors.push(msg);
assertionErrors = [];
2020-08-05 13:43:14 -04:00
// Pass QUNIT_FAIL_FAST on the command line to quit after the first failure
2020-09-23 12:52:11 +02:00
// eslint-disable-next-line
2020-08-05 13:43:14 -04:00
if (QUNIT_FAIL_FAST) {
QUnit.config.queue.length = 0;
}
if (inTest) {
console.log(" [✘]");
}
2013-06-18 13:44:20 -04:00
} else {
2020-08-05 13:43:14 -04:00
if (inTest) {
console.log(" [✔]");
}
2013-06-18 13:44:20 -04:00
}
2020-08-05 13:43:14 -04:00
inTest = false;
2013-06-18 13:44:20 -04:00
});
2020-09-23 12:52:11 +02:00
QUnit.log(function (context) {
2018-11-27 17:40:55 +11:00
if (context.result) {
return;
}
2013-06-18 13:44:20 -04:00
2021-01-27 12:39:20 +01:00
let msg = "\n Assertion Failed:";
2013-06-18 13:44:20 -04:00
if (context.message) {
msg += " " + context.message;
}
if (context.expected) {
2018-11-27 17:40:55 +11:00
msg +=
"\n Expected: " + context.expected + ", Actual: " + context.actual;
2013-06-18 13:44:20 -04:00
}
assertionErrors.push(msg);
});
2020-09-23 12:52:11 +02:00
QUnit.done(function (context) {
2015-08-25 10:42:19 +02:00
console.log("\n");
2013-06-18 13:44:20 -04:00
2018-04-23 14:41:29 +10:00
console.log("Slowest tests");
console.log("----------------------------------------------");
2020-09-23 12:52:11 +02:00
let ary = Object.keys(durations).map((key) => ({
key,
2020-09-23 12:52:11 +02:00
value: durations[key],
2018-11-27 17:40:55 +11:00
}));
ary.sort((p1, p2) => p2.value - p1.value);
2020-09-23 12:52:11 +02:00
ary.slice(0, 30).forEach((pair) => {
2018-04-23 14:41:29 +10:00
console.log(pair.key + ": " + pair.value + "ms");
});
console.log("\n");
if (testErrors.length) {
console.log("Test Errors");
console.log("----------------------------------------------");
testErrors.forEach((e) => {
console.error(e);
});
console.log("\n");
}
2021-01-27 12:39:20 +01:00
let stats = [
2013-06-18 13:44:20 -04:00
"Time: " + context.runtime + "ms",
"Total: " + context.total,
"Passed: " + context.passed,
2020-09-23 12:52:11 +02:00
"Failed: " + context.failed,
2013-06-18 13:44:20 -04:00
];
console.log(stats.join(", "));
2018-04-23 14:41:29 +10:00
if (context.failed) {
console.log("\nUse this filter to run in the same order:");
2020-08-05 13:43:14 -04:00
console.log(
2020-08-05 16:27:06 -04:00
"QUNIT_FAIL_FAST=1 QUNIT_SEED=" +
2020-08-05 13:43:14 -04:00
QUnit.config.seed +
" rake qunit:test\n"
);
console.log("If you have a web environment running, you can visit:");
console.log(
"http://localhost:3000/qunit?hidepassed&seed=" +
QUnit.config.seed +
"\n\n"
);
}
2013-06-18 13:44:20 -04:00
window.qunitDone = context;
});
2022-04-02 21:15:38 +02:00
QUnit.start();
2013-06-18 13:44:20 -04:00
}
2018-04-23 14:41:29 +10:00
let qunit_script = logQUnit.toString();
if (QUNIT_RESULT) {
2018-11-27 17:40:55 +11:00
qunit_script = qunit_script.replace(
"/* QUNIT_RESULT */",
"console.log(`AUTOSPEC: ${context.module}:::${context.testId}:::${context.name}`);"
);
2018-04-23 14:41:29 +10:00
}
function check() {
2018-11-27 17:40:55 +11:00
if (window.qunitDone) {
return window.qunitDone.failed;
}
}
2018-04-23 14:41:29 +10:00
const check_script = check.toString();