mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-24 10:38:59 +01:00
eng: add support for snapshot tests (#190444)
* eng: add support for snapshot tests This adds Jest-like support for snapshot testing. Developers can do something like: ```js await assertSnapshot(myComplexObject) ``` The first time this is run, the snapshot expectation file is written to a `__snapshots__` directory beside the test file. Subsequent runs will compare the object to the snapshot, and fail if it doesn't match. You can see an example of this in the test for snapshots themselves! After a successful run, any unused snapshots are cleaned up. On a failed run, a gitignored `.actual` snapshot file is created beside the snapshot for easy processing and inspection. Shortly I will do some integration with the selfhost test extension to allow developers to easily update snapshots from the vscode UI. For #189680 cc @ulugbekna @hediet * fix async stacktraces getting clobbered * random fixes * comment out leak detector, for now * add option to snapshot file extension
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
process.env.MOCHA_COLORS = '1'; // Force colors (note that this must come before any mocha imports)
|
||||
|
||||
const assert = require('assert');
|
||||
const mocha = require('mocha');
|
||||
const Mocha = require('mocha');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const glob = require('glob');
|
||||
@@ -64,6 +64,14 @@ function main() {
|
||||
globalThis._VSCODE_PRODUCT_JSON = require(`${REPO_ROOT}/product.json`);
|
||||
globalThis._VSCODE_PACKAGE_JSON = require(`${REPO_ROOT}/package.json`);
|
||||
|
||||
// Test file operations that are common across platforms. Used for test infra, namely snapshot tests
|
||||
Object.assign(globalThis, {
|
||||
__readFileInTests: (/** @type {string} */ path) => fs.promises.readFile(path, 'utf-8'),
|
||||
__writeFileInTests: (/** @type {string} */ path, /** @type {BufferEncoding} */ contents) => fs.promises.writeFile(path, contents),
|
||||
__readDirInTests: (/** @type {string} */ path) => fs.promises.readdir(path),
|
||||
__unlinkInTests: (/** @type {string} */ path) => fs.promises.unlink(path),
|
||||
__mkdirPInTests: (/** @type {string} */ path) => fs.promises.mkdir(path, { recursive: true }),
|
||||
});
|
||||
|
||||
process.on('uncaughtException', function (e) {
|
||||
console.error(e.stack || e);
|
||||
@@ -127,7 +135,24 @@ function main() {
|
||||
return write.apply(process.stderr, args);
|
||||
};
|
||||
|
||||
/** @type { (callback:(err:any)=>void)=>void } */
|
||||
|
||||
const runner = new Mocha({
|
||||
ui: 'tdd'
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {string[]} modules
|
||||
*/
|
||||
async function loadModules(modules) {
|
||||
for (const file of modules) {
|
||||
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, runner);
|
||||
const m = await new Promise((resolve, reject) => loader([file], resolve, reject));
|
||||
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, runner);
|
||||
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, runner);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type { null|((callback:(err:any)=>void)=>void) } */
|
||||
let loadFunc = null;
|
||||
|
||||
if (argv.runGlob) {
|
||||
@@ -140,7 +165,7 @@ function main() {
|
||||
|
||||
return test.replace(/(\.js)|(\.d\.ts)|(\.js\.map)$/, '');
|
||||
});
|
||||
loader(modulesToLoad, () => cb(null), cb);
|
||||
loadModules(modulesToLoad).then(() => cb(null), cb);
|
||||
};
|
||||
|
||||
glob(argv.runGlob, { cwd: src }, function (err, files) { doRun(files); });
|
||||
@@ -153,7 +178,7 @@ function main() {
|
||||
return path.relative(src, path.resolve(test)).replace(/(\.js)|(\.js\.map)$/, '').replace(/\\/g, '/');
|
||||
});
|
||||
loadFunc = (cb) => {
|
||||
loader(modulesToLoad, () => cb(null), cb);
|
||||
loadModules(modulesToLoad).then(() => cb(null), cb);
|
||||
};
|
||||
} else {
|
||||
loadFunc = (cb) => {
|
||||
@@ -165,7 +190,7 @@ function main() {
|
||||
modules.push(file.replace(/\.js$/, ''));
|
||||
}
|
||||
}
|
||||
loader(modules, function () { cb(null); }, cb);
|
||||
loadModules(modules).then(() => cb(null), cb);
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -180,7 +205,7 @@ function main() {
|
||||
|
||||
if (!argv.run && !argv.runGlob) {
|
||||
// set up last test
|
||||
mocha.suite('Loader', function () {
|
||||
Mocha.suite('Loader', function () {
|
||||
test('should not explode while loading', function () {
|
||||
assert.ok(!didErr, 'should not explode while loading');
|
||||
});
|
||||
@@ -189,7 +214,7 @@ function main() {
|
||||
|
||||
// report failing test for every unexpected error during any of the tests
|
||||
const unexpectedErrors = [];
|
||||
mocha.suite('Errors', function () {
|
||||
Mocha.suite('Errors', function () {
|
||||
test('should not have unexpected errors in tests', function () {
|
||||
if (unexpectedErrors.length) {
|
||||
unexpectedErrors.forEach(function (stack) {
|
||||
@@ -210,7 +235,7 @@ function main() {
|
||||
});
|
||||
|
||||
// fire up mocha
|
||||
mocha.run();
|
||||
runner.run(failures => process.exit(failures ? 1 : 0));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user