Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/test/unit/node/index.js
3520 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
//@ts-check
7
'use strict';
8
9
process.env.MOCHA_COLORS = '1'; // Force colors (note that this must come before any mocha imports)
10
11
import * as assert from 'assert';
12
import Mocha from 'mocha';
13
import * as path from 'path';
14
import * as fs from 'fs';
15
import glob from 'glob';
16
import minimatch from 'minimatch';
17
import minimist from 'minimist';
18
import * as module from 'module';
19
import { fileURLToPath, pathToFileURL } from 'url';
20
import semver from 'semver';
21
22
/**
23
* @type {{ build: boolean; run: string; runGlob: string; coverage: boolean; help: boolean; coverageFormats: string | string[]; coveragePath: string; }}
24
*/
25
const args = minimist(process.argv.slice(2), {
26
boolean: ['build', 'coverage', 'help'],
27
string: ['run', 'coveragePath', 'coverageFormats'],
28
alias: {
29
h: 'help'
30
},
31
default: {
32
build: false,
33
coverage: false,
34
help: false
35
},
36
description: {
37
build: 'Run from out-build',
38
run: 'Run a single file',
39
coverage: 'Generate a coverage report',
40
coveragePath: 'Path to coverage report to generate',
41
coverageFormats: 'Coverage formats to generate',
42
help: 'Show help'
43
}
44
});
45
46
if (args.help) {
47
console.log(`Usage: node test/unit/node/index [options]
48
49
Options:
50
--build Run from out-build
51
--run <file> Run a single file
52
--coverage Generate a coverage report
53
--help Show help`);
54
process.exit(0);
55
}
56
57
const TEST_GLOB = '**/test/**/*.test.js';
58
59
const excludeGlobs = [
60
'**/{browser,electron-browser,electron-main,electron-utility}/**/*.test.js',
61
'**/vs/platform/environment/test/node/nativeModules.test.js', // native modules are compiled against Electron and this test would fail with node.js
62
'**/vs/base/parts/storage/test/node/storage.test.js', // same as above, due to direct dependency to sqlite native module
63
'**/vs/workbench/contrib/testing/test/**' // flaky (https://github.com/microsoft/vscode/issues/137853)
64
];
65
66
const REPO_ROOT = fileURLToPath(new URL('../../../', import.meta.url));
67
const out = args.build ? 'out-build' : 'out';
68
const src = path.join(REPO_ROOT, out);
69
const baseUrl = pathToFileURL(src);
70
71
//@ts-ignore
72
const requiredNodeVersion = semver.parse(/^target="(.*)"$/m.exec(fs.readFileSync(path.join(REPO_ROOT, 'remote', '.npmrc'), 'utf8'))[1]);
73
const currentNodeVersion = semver.parse(process.version);
74
//@ts-ignore
75
if (currentNodeVersion?.major < requiredNodeVersion?.major) {
76
console.error(`node.js unit tests require a major node.js version of ${requiredNodeVersion?.major} (your version is: ${currentNodeVersion?.major})`);
77
process.exit(1);
78
}
79
80
function main() {
81
82
// VSCODE_GLOBALS: package/product.json
83
const _require = module.createRequire(import.meta.url);
84
globalThis._VSCODE_PRODUCT_JSON = _require(`${REPO_ROOT}/product.json`);
85
globalThis._VSCODE_PACKAGE_JSON = _require(`${REPO_ROOT}/package.json`);
86
87
// VSCODE_GLOBALS: file root
88
globalThis._VSCODE_FILE_ROOT = baseUrl.href;
89
90
if (args.build) {
91
// when running from `out-build`, ensure to load the default
92
// messages file, because all `nls.localize` calls have their
93
// english values removed and replaced by an index.
94
globalThis._VSCODE_NLS_MESSAGES = _require(`${REPO_ROOT}/${out}/nls.messages.json`);
95
}
96
97
// Test file operations that are common across platforms. Used for test infra, namely snapshot tests
98
Object.assign(globalThis, {
99
// __analyzeSnapshotInTests: takeSnapshotAndCountClasses,
100
__readFileInTests: (/** @type {string} */ path) => fs.promises.readFile(path, 'utf-8'),
101
__writeFileInTests: (/** @type {string} */ path, /** @type {BufferEncoding} */ contents) => fs.promises.writeFile(path, contents),
102
__readDirInTests: (/** @type {string} */ path) => fs.promises.readdir(path),
103
__unlinkInTests: (/** @type {string} */ path) => fs.promises.unlink(path),
104
__mkdirPInTests: (/** @type {string} */ path) => fs.promises.mkdir(path, { recursive: true }),
105
});
106
107
process.on('uncaughtException', function (e) {
108
console.error(e.stack || e);
109
});
110
111
/**
112
* @param modules
113
* @param onLoad
114
* @param onError
115
*/
116
const loader = function (modules, onLoad, onError) {
117
const loads = modules.map(mod => import(`${baseUrl}/${mod}.js`).catch(err => {
118
console.error(`FAILED to load ${mod} as ${baseUrl}/${mod}.js`);
119
throw err;
120
}));
121
Promise.all(loads).then(onLoad, onError);
122
};
123
124
125
let didErr = false;
126
const write = process.stderr.write;
127
process.stderr.write = function (...args) {
128
didErr = didErr || !!args[0];
129
return write.apply(process.stderr, args);
130
};
131
132
133
const runner = new Mocha({
134
ui: 'tdd'
135
});
136
137
/**
138
* @param modules
139
*/
140
async function loadModules(modules) {
141
for (const file of modules) {
142
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_PRE_REQUIRE, globalThis, file, runner);
143
const m = await new Promise((resolve, reject) => loader([file], resolve, reject));
144
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_REQUIRE, m, file, runner);
145
runner.suite.emit(Mocha.Suite.constants.EVENT_FILE_POST_REQUIRE, globalThis, file, runner);
146
}
147
}
148
149
/** @type { null|((callback:(err:any)=>void)=>void) } */
150
let loadFunc = null;
151
152
if (args.runGlob) {
153
loadFunc = (cb) => {
154
const doRun = /** @param tests */(tests) => {
155
const modulesToLoad = tests.map(test => {
156
if (path.isAbsolute(test)) {
157
test = path.relative(src, path.resolve(test));
158
}
159
160
return test.replace(/(\.js)|(\.d\.ts)|(\.js\.map)$/, '');
161
});
162
loadModules(modulesToLoad).then(() => cb(null), cb);
163
};
164
165
glob(args.runGlob, { cwd: src }, function (err, files) { doRun(files); });
166
};
167
} else if (args.run) {
168
const tests = (typeof args.run === 'string') ? [args.run] : args.run;
169
const modulesToLoad = tests.map(function (test) {
170
test = test.replace(/^src/, 'out');
171
test = test.replace(/\.ts$/, '.js');
172
return path.relative(src, path.resolve(test)).replace(/(\.js)|(\.js\.map)$/, '').replace(/\\/g, '/');
173
});
174
loadFunc = (cb) => {
175
loadModules(modulesToLoad).then(() => cb(null), cb);
176
};
177
} else {
178
loadFunc = (cb) => {
179
glob(TEST_GLOB, { cwd: src }, function (err, files) {
180
/** @type {string[]} */
181
const modules = [];
182
for (const file of files) {
183
if (!excludeGlobs.some(excludeGlob => minimatch(file, excludeGlob))) {
184
modules.push(file.replace(/\.js$/, ''));
185
}
186
}
187
loadModules(modules).then(() => cb(null), cb);
188
});
189
};
190
}
191
192
loadFunc(function (err) {
193
if (err) {
194
console.error(err);
195
return process.exit(1);
196
}
197
198
process.stderr.write = write;
199
200
if (!args.run && !args.runGlob) {
201
// set up last test
202
Mocha.suite('Loader', function () {
203
test('should not explode while loading', function () {
204
assert.ok(!didErr, `should not explode while loading: ${didErr}`);
205
});
206
});
207
}
208
209
// report failing test for every unexpected error during any of the tests
210
const unexpectedErrors = [];
211
Mocha.suite('Errors', function () {
212
test('should not have unexpected errors in tests', function () {
213
if (unexpectedErrors.length) {
214
unexpectedErrors.forEach(function (stack) {
215
console.error('');
216
console.error(stack);
217
});
218
219
assert.ok(false);
220
}
221
});
222
});
223
224
// replace the default unexpected error handler to be useful during tests
225
import(`${baseUrl}/vs/base/common/errors.js`).then(errors => {
226
errors.setUnexpectedErrorHandler(function (err) {
227
const stack = (err && err.stack) || (new Error().stack);
228
unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack);
229
});
230
231
// fire up mocha
232
runner.run(failures => process.exit(failures ? 1 : 0));
233
});
234
});
235
}
236
237
main();
238
239