parent
d89fdcbfa8
commit
17f6bcb7d2
|
@ -5,6 +5,8 @@
|
||||||
|
|
||||||
/*eslint-env mocha*/
|
/*eslint-env mocha*/
|
||||||
|
|
||||||
|
// @ts-check
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
|
@ -24,7 +26,7 @@ const fs = require('fs');
|
||||||
function createSpy(element, cnt) {
|
function createSpy(element, cnt) {
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
if (logging) {
|
if (logging) {
|
||||||
console.log(`calling ${element}: ` + args.slice(0, cnt).join(',') + (withStacks ? (`\n` + new Error().stack.split('\n').slice(2).join('\n')) : ''));
|
console.log(`calling ${element}: ` + args.slice(0, cnt).join(',') + (withStacks ? (`\n` + new Error().stack?.split('\n').slice(2).join('\n')) : ''));
|
||||||
}
|
}
|
||||||
return originals[element].call(this, ...args);
|
return originals[element].call(this, ...args);
|
||||||
};
|
};
|
||||||
|
@ -88,9 +90,18 @@ Object.assign(globalThis, {
|
||||||
|
|
||||||
const IS_CI = !!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY;
|
const IS_CI = !!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY;
|
||||||
const _tests_glob = '**/test/**/*.test.js';
|
const _tests_glob = '**/test/**/*.test.js';
|
||||||
let loader;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads one or N modules.
|
||||||
|
* @type {{
|
||||||
|
* (module: string|string[]): Promise<any>|Promise<any[]>;
|
||||||
|
* _out: string;
|
||||||
|
* }}
|
||||||
|
*/
|
||||||
|
let loadFn;
|
||||||
|
|
||||||
const _loaderErrors = [];
|
const _loaderErrors = [];
|
||||||
let _out;
|
|
||||||
|
|
||||||
function initNls(opts) {
|
function initNls(opts) {
|
||||||
if (opts.build) {
|
if (opts.build) {
|
||||||
|
@ -101,20 +112,17 @@ function initNls(opts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initLoader(opts) {
|
function initLoadFn(opts) {
|
||||||
const outdir = opts.build ? 'out-build' : 'out';
|
const outdir = opts.build ? 'out-build' : 'out';
|
||||||
_out = path.join(__dirname, `../../../${outdir}`);
|
const out = path.join(__dirname, `../../../${outdir}`);
|
||||||
|
|
||||||
const baseUrl = pathToFileURL(path.join(__dirname, `../../../${outdir}/`));
|
const baseUrl = pathToFileURL(path.join(__dirname, `../../../${outdir}/`));
|
||||||
globalThis._VSCODE_FILE_ROOT = baseUrl.href;
|
globalThis._VSCODE_FILE_ROOT = baseUrl.href;
|
||||||
|
|
||||||
// set loader
|
// set loader
|
||||||
/**
|
function importModules(modules) {
|
||||||
* @param {string[]} modules
|
const moduleArray = Array.isArray(modules) ? modules : [modules];
|
||||||
* @param {(...args:any[]) => void} callback
|
const tasks = moduleArray.map(mod => {
|
||||||
*/
|
|
||||||
function esmRequire(modules, callback, errorback) {
|
|
||||||
const tasks = modules.map(mod => {
|
|
||||||
const url = new URL(`./${mod}.js`, baseUrl).href;
|
const url = new URL(`./${mod}.js`, baseUrl).href;
|
||||||
return import(url).catch(err => {
|
return import(url).catch(err => {
|
||||||
console.log(mod, url);
|
console.log(mod, url);
|
||||||
|
@ -124,35 +132,33 @@ function initLoader(opts) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(tasks).then(modules => callback(...modules)).catch(errorback);
|
return Array.isArray(modules)
|
||||||
|
? Promise.all(tasks)
|
||||||
|
: tasks[0];
|
||||||
}
|
}
|
||||||
|
importModules._out = out;
|
||||||
loader = { require: esmRequire };
|
loadFn = importModules;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createCoverageReport(opts) {
|
async function createCoverageReport(opts) {
|
||||||
if (opts.coverage) {
|
if (!opts.coverage) {
|
||||||
return coverage.createReport(opts.run || opts.runGlob);
|
return undefined;
|
||||||
}
|
}
|
||||||
return Promise.resolve(undefined);
|
return coverage.createReport(opts.run || opts.runGlob);
|
||||||
}
|
|
||||||
|
|
||||||
function loadWorkbenchTestingUtilsModule() {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
loader.require(['vs/workbench/test/common/utils'], resolve, reject);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadModules(modules) {
|
async function loadModules(modules) {
|
||||||
for (const file of modules) {
|
for (const file of modules) {
|
||||||
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, mocha);
|
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, mocha);
|
||||||
const m = await new Promise((resolve, reject) => loader.require([file], resolve, reject));
|
const m = await loadFn(file);
|
||||||
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, mocha);
|
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, mocha);
|
||||||
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, mocha);
|
mocha.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, mocha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadTestModules(opts) {
|
const globAsync = util.promisify(glob);
|
||||||
|
|
||||||
|
async function loadTestModules(opts) {
|
||||||
|
|
||||||
if (opts.run) {
|
if (opts.run) {
|
||||||
const files = Array.isArray(opts.run) ? opts.run : [opts.run];
|
const files = Array.isArray(opts.run) ? opts.run : [opts.run];
|
||||||
|
@ -164,17 +170,9 @@ function loadTestModules(opts) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const pattern = opts.runGlob || _tests_glob;
|
const pattern = opts.runGlob || _tests_glob;
|
||||||
|
const files = await globAsync(pattern, { cwd: loadFn._out });
|
||||||
return new Promise((resolve, reject) => {
|
const modules = files.map(file => file.replace(/\.js$/, ''));
|
||||||
glob(pattern, { cwd: _out }, (err, files) => {
|
return loadModules(modules);
|
||||||
if (err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const modules = files.map(file => file.replace(/\.js$/, ''));
|
|
||||||
resolve(modules);
|
|
||||||
});
|
|
||||||
}).then(loadModules);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type Mocha.Test */
|
/** @type Mocha.Test */
|
||||||
|
@ -220,7 +218,7 @@ async function loadTests(opts) {
|
||||||
console[consoleFn.name] = function (msg) {
|
console[consoleFn.name] = function (msg) {
|
||||||
if (!currentTest) {
|
if (!currentTest) {
|
||||||
consoleFn.apply(console, arguments);
|
consoleFn.apply(console, arguments);
|
||||||
} else if (!_allowedTestOutput.some(a => a.test(msg)) && !_allowedTestsWithOutput.has(currentTest.title) && !_allowedSuitesWithOutput.has(currentTest.parent?.title)) {
|
} else if (!_allowedTestOutput.some(a => a.test(msg)) && !_allowedTestsWithOutput.has(currentTest.title) && !_allowedSuitesWithOutput.has(currentTest.parent?.title ?? '')) {
|
||||||
_testsWithUnexpectedOutput = true;
|
_testsWithUnexpectedOutput = true;
|
||||||
consoleFn.apply(console, arguments);
|
consoleFn.apply(console, arguments);
|
||||||
}
|
}
|
||||||
|
@ -242,79 +240,74 @@ async function loadTests(opts) {
|
||||||
'Search Model: Search reports timed telemetry on search when error is called'
|
'Search Model: Search reports timed telemetry on search when error is called'
|
||||||
]);
|
]);
|
||||||
|
|
||||||
loader.require(['vs/base/common/errors'], function (errors) {
|
const errors = await loadFn('vs/base/common/errors');
|
||||||
|
const onUnexpectedError = function (err) {
|
||||||
|
if (err.name === 'Canceled') {
|
||||||
|
return; // ignore canceled errors that are common
|
||||||
|
}
|
||||||
|
|
||||||
const onUnexpectedError = function (err) {
|
let stack = (err ? err.stack : null);
|
||||||
if (err.name === 'Canceled') {
|
if (!stack) {
|
||||||
return; // ignore canceled errors that are common
|
stack = new Error().stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
let stack = (err ? err.stack : null);
|
_unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack);
|
||||||
if (!stack) {
|
};
|
||||||
stack = new Error().stack;
|
|
||||||
}
|
|
||||||
|
|
||||||
_unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack);
|
process.on('uncaughtException', error => onUnexpectedError(error));
|
||||||
};
|
process.on('unhandledRejection', (reason, promise) => {
|
||||||
|
onUnexpectedError(reason);
|
||||||
|
promise.catch(() => { });
|
||||||
|
});
|
||||||
|
window.addEventListener('unhandledrejection', event => {
|
||||||
|
event.preventDefault(); // Do not log to test output, we show an error later when test ends
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
process.on('uncaughtException', error => onUnexpectedError(error));
|
if (!_allowedTestsWithUnhandledRejections.has(currentTest.title)) {
|
||||||
process.on('unhandledRejection', (reason, promise) => {
|
onUnexpectedError(event.reason);
|
||||||
onUnexpectedError(reason);
|
}
|
||||||
promise.catch(() => { });
|
|
||||||
});
|
|
||||||
window.addEventListener('unhandledrejection', event => {
|
|
||||||
event.preventDefault(); // Do not log to test output, we show an error later when test ends
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
if (!_allowedTestsWithUnhandledRejections.has(currentTest.title)) {
|
|
||||||
onUnexpectedError(event.reason);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
errors.setUnexpectedErrorHandler(onUnexpectedError);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
errors.setUnexpectedErrorHandler(onUnexpectedError);
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
return loadWorkbenchTestingUtilsModule().then((workbenchTestingModule) => {
|
const { assertCleanState } = await loadFn('vs/workbench/test/common/utils');
|
||||||
const assertCleanState = workbenchTestingModule.assertCleanState;
|
|
||||||
|
|
||||||
suite('Tests are using suiteSetup and setup correctly', () => {
|
suite('Tests are using suiteSetup and setup correctly', () => {
|
||||||
test('assertCleanState - check that registries are clean at the start of test running', () => {
|
test('assertCleanState - check that registries are clean at the start of test running', () => {
|
||||||
assertCleanState();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
setup(async () => {
|
|
||||||
await perTestCoverage?.startTest();
|
|
||||||
});
|
|
||||||
|
|
||||||
teardown(async () => {
|
|
||||||
await perTestCoverage?.finishTest(currentTest.file, currentTest.fullTitle());
|
|
||||||
|
|
||||||
// should not have unexpected output
|
|
||||||
if (_testsWithUnexpectedOutput && !opts.dev) {
|
|
||||||
assert.ok(false, 'Error: Unexpected console output in test run. Please ensure no console.[log|error|info|warn] usage in tests or runtime errors.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// should not have unexpected errors
|
|
||||||
const errors = _unexpectedErrors.concat(_loaderErrors);
|
|
||||||
if (errors.length) {
|
|
||||||
for (const error of errors) {
|
|
||||||
console.error(`Error: Test run should not have unexpected errors:\n${error}`);
|
|
||||||
}
|
|
||||||
assert.ok(false, 'Error: Test run should not have unexpected errors.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
suiteTeardown(() => { // intentionally not in teardown because some tests only cleanup in suiteTeardown
|
|
||||||
|
|
||||||
// should have cleaned up in registries
|
|
||||||
assertCleanState();
|
assertCleanState();
|
||||||
});
|
});
|
||||||
|
|
||||||
return loadTestModules(opts);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setup(async () => {
|
||||||
|
await perTestCoverage?.startTest();
|
||||||
|
});
|
||||||
|
|
||||||
|
teardown(async () => {
|
||||||
|
await perTestCoverage?.finishTest(currentTest.file, currentTest.fullTitle());
|
||||||
|
|
||||||
|
// should not have unexpected output
|
||||||
|
if (_testsWithUnexpectedOutput && !opts.dev) {
|
||||||
|
assert.ok(false, 'Error: Unexpected console output in test run. Please ensure no console.[log|error|info|warn] usage in tests or runtime errors.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// should not have unexpected errors
|
||||||
|
const errors = _unexpectedErrors.concat(_loaderErrors);
|
||||||
|
if (errors.length) {
|
||||||
|
for (const error of errors) {
|
||||||
|
console.error(`Error: Test run should not have unexpected errors:\n${error}`);
|
||||||
|
}
|
||||||
|
assert.ok(false, 'Error: Test run should not have unexpected errors.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
suiteTeardown(() => { // intentionally not in teardown because some tests only cleanup in suiteTeardown
|
||||||
|
|
||||||
|
// should have cleaned up in registries
|
||||||
|
assertCleanState();
|
||||||
|
});
|
||||||
|
|
||||||
|
return loadTestModules(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serializeSuite(suite) {
|
function serializeSuite(suite) {
|
||||||
|
@ -403,42 +396,41 @@ class IPCReporter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTests(opts) {
|
async function runTests(opts) {
|
||||||
// this *must* come before loadTests, or it doesn't work.
|
// this *must* come before loadTests, or it doesn't work.
|
||||||
if (opts.timeout !== undefined) {
|
if (opts.timeout !== undefined) {
|
||||||
mocha.timeout(opts.timeout);
|
mocha.timeout(opts.timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
return loadTests(opts).then(() => {
|
await loadTests(opts);
|
||||||
|
|
||||||
if (opts.grep) {
|
if (opts.grep) {
|
||||||
mocha.grep(opts.grep);
|
mocha.grep(opts.grep);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opts.dev) {
|
if (!opts.dev) {
|
||||||
mocha.reporter(IPCReporter);
|
// @ts-expect-error
|
||||||
}
|
mocha.reporter(IPCReporter);
|
||||||
|
}
|
||||||
|
|
||||||
const runner = mocha.run(() => {
|
const runner = mocha.run(async () => {
|
||||||
createCoverageReport(opts).then(() => {
|
await createCoverageReport(opts)
|
||||||
ipcRenderer.send('all done');
|
ipcRenderer.send('all done');
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
runner.on('test', test => currentTest = test);
|
|
||||||
|
|
||||||
if (opts.dev) {
|
|
||||||
runner.on('fail', (test, err) => {
|
|
||||||
console.error(test.fullTitle());
|
|
||||||
console.error(err.stack);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
runner.on('test', test => currentTest = test);
|
||||||
|
|
||||||
|
if (opts.dev) {
|
||||||
|
runner.on('fail', (test, err) => {
|
||||||
|
console.error(test.fullTitle());
|
||||||
|
console.error(err.stack);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ipcRenderer.on('run', async (_e, opts) => {
|
ipcRenderer.on('run', async (_e, opts) => {
|
||||||
initNls(opts);
|
initNls(opts);
|
||||||
initLoader(opts);
|
initLoadFn(opts);
|
||||||
|
|
||||||
await Promise.resolve(globalThis._VSCODE_TEST_INIT);
|
await Promise.resolve(globalThis._VSCODE_TEST_INIT);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue