Skip to content

Commit

Permalink
WIP: Implement reporters and collect console.error/warn/window.onerror
Browse files Browse the repository at this point in the history
  • Loading branch information
Krinkle committed Jan 23, 2025
1 parent da1e629 commit 09d7fc7
Show file tree
Hide file tree
Showing 16 changed files with 739 additions and 224 deletions.
13 changes: 11 additions & 2 deletions .github/workflows/CI.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,17 @@ jobs:

- run: npm test

- name: Check system browsers
run: node bin/qtap.js -v -b firefox -b chrome -b chromium -b edge test/pass.html
- name: Check system browsers (Firefox)
run: node bin/qtap.js -v -b firefox test/pass.html

- name: Check system browsers (Chrome)
run: node bin/qtap.js -v -b chrome test/pass.html

- name: Check system browsers (Chromium)
run: node bin/qtap.js -v -b chromium test/pass.html

- name: Check system browsers (Edge)
run: node bin/qtap.js -v -b edge test/pass.html

- name: Check system browsers (Safari)
if: ${{ runner.os == 'macOS' }}
Expand Down
6 changes: 4 additions & 2 deletions bin/qtap.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ program
},
60
)
.option('-r, --reporter <reporter>')
.option('-w, --watch', 'Watch files for changes and re-run the test suite.')
.option('-v, --verbose', 'Enable verbose debug logging.')
.option('-V, --version', 'Display version number.')
Expand All @@ -74,13 +75,14 @@ if (opts.version) {
});

try {
const exitCode = await qtap.run(opts.browser, program.args, {
const result = await qtap.runWaitFor(opts.browser, program.args, {
config: opts.config,
timeout: opts.timeout,
connectTimeout: opts.connectTimeout,
reporter: opts.reporter,
verbose: opts.verbose
});
process.exit(exitCode);
process.exit(result.exitCode);
} catch (e) {
console.error(e);
process.exit(1);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"eslint": "~8.57.1",
"eslint-config-semistandard": "~17.0.0",
"eslint-plugin-qunit": "^8.1.2",
"qunit": "2.23.1",
"qunit": "2.24.0",
"semistandard": "~17.0.0",
"typescript": "5.7.3"
},
Expand Down
79 changes: 39 additions & 40 deletions src/browsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ async function firefox (url, signals, logger) {
const profileDir = LocalBrowser.makeTempDir(signals, logger);
const args = [url, '-profile', profileDir, '-no-remote', '-wait-for-browser'];
if (!QTAP_DEBUG) {
firefox.displayName = 'Headless Firefox';
args.push('-headless');
}

Expand Down Expand Up @@ -157,54 +158,52 @@ async function firefox (url, signals, logger) {
firefox.displayName = 'Firefox';

/**
* @param {Function} getPaths
* @param {string} url
* @param {Object<string,AbortSignal>} signals
* @param {Logger} logger
* @param {string} displayName
* @param {() => Generator} getPaths
* @return {Browser}
*/
async function chromiumGeneric (getPaths, url, signals, logger) {
// https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
const dataDir = LocalBrowser.makeTempDir(signals, logger);
const args = [
'--user-data-dir=' + dataDir,
'--no-default-browser-check',
'--no-first-run',
'--disable-default-apps',
'--disable-popup-blocking',
'--disable-translate',
'--disable-background-timer-throttling',
...(QTAP_DEBUG ? [] : [
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage'
]),
...(process.env.CHROMIUM_FLAGS ? process.env.CHROMIUM_FLAGS.split(/\s+/) : (
process.env.CI ? ['--no-sandbox'] : [])
),
url
];
await LocalBrowser.spawn(getPaths(), args, signals, logger);
function makeChromium (displayName, getPaths) {
/** @type {Browser} - https://github.com/microsoft/TypeScript/issues/22063 */
const chromium = async function (url, signals, logger) {
chromium.displayName = QTAP_DEBUG ? displayName : `Headless ${displayName}`;
// https://github.com/GoogleChrome/chrome-launcher/blob/main/docs/chrome-flags-for-tools.md
const dataDir = LocalBrowser.makeTempDir(signals, logger);
const args = [
'--user-data-dir=' + dataDir,
'--no-default-browser-check',
'--no-first-run',
'--disable-default-apps',
'--disable-popup-blocking',
'--disable-translate',
'--disable-background-timer-throttling',
...(QTAP_DEBUG ? [] : [
'--headless',
'--disable-gpu',
'--disable-dev-shm-usage'
]),
...(process.env.CHROMIUM_FLAGS ? process.env.CHROMIUM_FLAGS.split(/\s+/) : (
process.env.CI ? ['--no-sandbox'] : [])
),
url
];
await LocalBrowser.spawn(getPaths(), args, signals, logger);
};
return chromium;
}

const chrome = chromiumGeneric.bind(null, getChromePaths);
chrome.displayName = 'Chrome';

const chromium = chromiumGeneric.bind(null, getChromiumPaths);
chromium.displayName = 'Chromium';

const edge = chromiumGeneric.bind(null, getEdgePaths);
edge.displayName = 'Edge';

const chromiumAny = chromiumGeneric.bind(null, concatGenFn(getChromiumPaths, getChromePaths, getEdgePaths));
chromiumAny.displayName = 'Chromium';
const chrome = makeChromium('Chrome', getChromePaths);
const chromium = makeChromium('Chromium', getChromiumPaths);
const edge = makeChromium('Edge', getEdgePaths);
const chromiumAny = makeChromium('Chromium', concatGenFn(getChromiumPaths, getChromePaths, getEdgePaths));

/** @type {Browser} - https://github.com/microsoft/TypeScript/issues/22063 */
const detect = async function (url, signals, logger) {
for (const fn of [firefox, chrome, chromium, edge, safari]) {
detect.displayName = fn.displayName || fn.name;
logger.debug('detect_try', detect.displayName);
logger.debug('detect_try', fn.name);
try {
await fn(url, signals, logger);
const browerPromise = fn(url, signals, logger);
detect.displayName = fn.displayName || fn.name;
await browerPromise;
return;
} catch (e) {
if (e instanceof CommandNotFoundError) {
Expand Down
66 changes: 46 additions & 20 deletions src/client.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
/* eslint-disable no-undef, no-var -- Browser code */
/* eslint-disable no-var -- Browser code */
/* global XMLHttpRequest, QUnit */
// @ts-nocheck

export function fnToStr (fn, qtapUrl) {
export function fnToStr (fn, qtapTapUrl, qtapStderrUrl) {
return fn
.toString()
.replace(/\/\/.+$/gm, '')
.replace(/\n|^\s+/gm, ' ')
.replace(
"'{{QTAP_URL}}'",
JSON.stringify(qtapUrl)
/'{{QTAP_TAP_URL}}'/g,
JSON.stringify(qtapTapUrl)
)
.replace(
/'{{QTAP_STDERR_URL}}'/g,
JSON.stringify(qtapStderrUrl)
);
}

// See ARCHITECTURE.md#qtap-internal-client-send
export function qtapClientHead () {
// Support QUnit 3.0+: Enable TAP reporter, declaratively.
// Support QUnit 2.24+: Enable TAP reporter, declaratively.
window.qunit_config_reporters_tap = true;

// See ARCHITECTURE.md#qtap-internal-client-send
var qtapNativeLog = console.log;
// Support IE 9: console.log.apply is undefined.
// Don't bother with Function.apply.call. Skip super call instead.
var console = window.console || (window.console = {});
var qtapNativeLog = console.log && console.log.apply ? console.log : function () {};
var qtapNativeWarn = console.warn && console.warn.apply ? console.warn : function () {};
var qtapNativeError = console.error && console.error.apply ? console.error : function () {};

var qtapBuffer = '';
var qtapShouldSend = true;
function qtapSend () {
Expand All @@ -32,30 +43,45 @@ export function qtapClientHead () {
qtapSend();
}
};
xhr.open('POST', '{{QTAP_URL}}', true);
xhr.open('POST', '{{QTAP_TAP_URL}}', true);
xhr.send(body);
}
console.log = function qtapLog (str) {
function qtapWrite (str) {
qtapBuffer += str + '\n';
if (qtapShouldSend) {
qtapShouldSend = false;
setTimeout(qtapSend, 0);
}
}

console.log = function qtapConsoleLog (str) {
if (typeof str === 'string') {
qtapBuffer += str + '\n';
if (qtapShouldSend) {
qtapShouldSend = false;
setTimeout(qtapSend, 0);
}
qtapWrite(str);
}
return qtapNativeLog.apply(this, arguments);
return qtapNativeLog.apply(console, arguments);
};

console.warn = function qtapConsoleWarn (str) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '{{QTAP_STDERR_URL}}', true);
xhr.send(String(str));
return qtapNativeWarn.apply(console, arguments);
};

console.error = function qtapConsoleError (str) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '{{QTAP_STDERR_URL}}', true);
xhr.send(String(str));
return qtapNativeError.apply(console, arguments);
};

// TODO: Forward console.warn, console.error, and onerror to server.
// TODO: Report window.onerror as TAP comment, visible by default.
// TODO: Report console.warn/console.error in --verbose mode.
window.addEventListener('error', function (error) {
console.log('Script error: ' + (error.message || 'Unknown error'));
console.error((error.message || 'Unknown error'));
});
}

export function qtapClientBody () {
// Support QUnit 2.16 - 2.22: Enable TAP reporter, procedurally.
// Support QUnit 2.16 - 2.23: Enable TAP reporter, procedurally.
if (typeof QUnit !== 'undefined' && QUnit.reporters && QUnit.reporters.tap && (!QUnit.config.reporters || !QUnit.config.reporters.tap)) {
QUnit.reporters.tap.init(QUnit);
}
Expand Down
Loading

0 comments on commit 09d7fc7

Please sign in to comment.