Archived
1
0

Merge commit 'be3e8236086165e5e45a5a10783823874b3f3ebd' as 'lib/vscode'

This commit is contained in:
Joe Previte
2020-12-15 15:52:33 -07:00
4649 changed files with 1311795 additions and 0 deletions

View File

@ -0,0 +1,263 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//@ts-check
const path = require('path');
const glob = require('glob');
const fs = require('fs');
const events = require('events');
const mocha = require('mocha');
const MochaJUnitReporter = require('mocha-junit-reporter');
const url = require('url');
const minimatch = require('minimatch');
const playwright = require('playwright');
// opts
const defaultReporterName = process.platform === 'win32' ? 'list' : 'spec';
const optimist = require('optimist')
// .describe('grep', 'only run tests matching <pattern>').alias('grep', 'g').alias('grep', 'f').string('grep')
.describe('build', 'run with build output (out-build)').boolean('build')
.describe('run', 'only run tests matching <relative_file_path>').string('run')
.describe('glob', 'only run tests matching <glob_pattern>').string('glob')
.describe('debug', 'do not run browsers headless').boolean('debug')
.describe('browser', 'browsers in which tests should run').string('browser').default('browser', ['chromium', 'firefox', 'webkit'])
.describe('reporter', 'the mocha reporter').string('reporter').default('reporter', defaultReporterName)
.describe('reporter-options', 'the mocha reporter options').string('reporter-options').default('reporter-options', '')
.describe('tfs', 'tfs').string('tfs')
.describe('help', 'show the help').alias('help', 'h');
// logic
const argv = optimist.argv;
if (argv.help) {
optimist.showHelp();
process.exit(0);
}
const withReporter = (function () {
if (argv.tfs) {
{
return (browserType, runner) => {
new mocha.reporters.Spec(runner);
new MochaJUnitReporter(runner, {
reporterOptions: {
testsuitesTitle: `${argv.tfs} ${process.platform}`,
mochaFile: process.env.BUILD_ARTIFACTSTAGINGDIRECTORY ? path.join(process.env.BUILD_ARTIFACTSTAGINGDIRECTORY, `test-results/${process.platform}-${process.arch}-${browserType}-${argv.tfs.toLowerCase().replace(/[^\w]/g, '-')}-results.xml`) : undefined
}
});
}
}
} else {
const reporterPath = path.join(path.dirname(require.resolve('mocha')), 'lib', 'reporters', argv.reporter);
let ctor;
try {
ctor = require(reporterPath);
} catch (err) {
try {
ctor = require(argv.reporter);
} catch (err) {
ctor = process.platform === 'win32' ? mocha.reporters.List : mocha.reporters.Spec;
console.warn(`could not load reporter: ${argv.reporter}, using ${ctor.name}`);
}
}
function parseReporterOption(value) {
let r = /^([^=]+)=(.*)$/.exec(value);
return r ? { [r[1]]: r[2] } : {};
}
let reporterOptions = argv['reporter-options'];
reporterOptions = typeof reporterOptions === 'string' ? [reporterOptions] : reporterOptions;
reporterOptions = reporterOptions.reduce((r, o) => Object.assign(r, parseReporterOption(o)), {});
return (_, runner) => new ctor(runner, { reporterOptions })
}
})()
const outdir = argv.build ? 'out-build' : 'out';
const out = path.join(__dirname, `../../../${outdir}`);
function ensureIsArray(a) {
return Array.isArray(a) ? a : [a];
}
const testModules = (async function () {
const excludeGlob = '**/{node,electron-sandbox,electron-browser,electron-main}/**/*.test.js';
let isDefaultModules = true;
let promise;
if (argv.run) {
// use file list (--run)
isDefaultModules = false;
promise = Promise.resolve(ensureIsArray(argv.run).map(file => {
file = file.replace(/^src/, 'out');
file = file.replace(/\.ts$/, '.js');
return path.relative(out, file);
}));
} else {
// glob patterns (--glob)
const defaultGlob = '**/*.test.js';
const pattern = argv.glob || defaultGlob
isDefaultModules = pattern === defaultGlob;
promise = new Promise((resolve, reject) => {
glob(pattern, { cwd: out }, (err, files) => {
if (err) {
reject(err);
} else {
resolve(files)
}
});
});
}
return promise.then(files => {
const modules = [];
for (let file of files) {
if (!minimatch(file, excludeGlob)) {
modules.push(file.replace(/\.js$/, ''));
} else if (!isDefaultModules) {
console.warn(`DROPPONG ${file} because it cannot be run inside a browser`);
}
}
return modules;
})
})();
async function runTestsInBrowser(testModules, browserType) {
const args = process.platform === 'linux' && browserType === 'chromium' ? ['--no-sandbox'] : undefined; // disable sandbox to run chrome on certain Linux distros
const browser = await playwright[browserType].launch({ headless: !Boolean(argv.debug), args });
const context = await browser.newContext();
const page = await context.newPage();
const target = url.pathToFileURL(path.join(__dirname, 'renderer.html'));
if (argv.build) {
target.search = `?build=true`;
}
await page.goto(target.href);
const emitter = new events.EventEmitter();
await page.exposeFunction('mocha_report', (type, data1, data2) => {
emitter.emit(type, data1, data2)
});
page.on('console', async msg => {
console[msg.type()](msg.text(), await Promise.all(msg.args().map(async arg => await arg.jsonValue())));
});
withReporter(browserType, new EchoRunner(emitter, browserType.toUpperCase()));
// collection failures for console printing
const fails = [];
emitter.on('fail', (test, err) => {
if (err.stack) {
const regex = /(vs\/.*\.test)\.js/;
for (let line of String(err.stack).split('\n')) {
const match = regex.exec(line);
if (match) {
fails.push(match[1]);
break;
}
}
}
});
try {
// @ts-expect-error
await page.evaluate(modules => loadAndRun(modules), testModules);
} catch (err) {
console.error(err);
}
await browser.close();
if (fails.length > 0) {
return `to DEBUG, open ${browserType.toUpperCase()} and navigate to ${target.href}?${fails.map(module => `m=${module}`).join('&')}`;
}
}
class EchoRunner extends events.EventEmitter {
constructor(event, title = '') {
super();
event.on('start', () => this.emit('start'));
event.on('end', () => this.emit('end'));
event.on('suite', (suite) => this.emit('suite', EchoRunner.deserializeSuite(suite, title)));
event.on('suite end', (suite) => this.emit('suite end', EchoRunner.deserializeSuite(suite, title)));
event.on('test', (test) => this.emit('test', EchoRunner.deserializeRunnable(test)));
event.on('test end', (test) => this.emit('test end', EchoRunner.deserializeRunnable(test)));
event.on('hook', (hook) => this.emit('hook', EchoRunner.deserializeRunnable(hook)));
event.on('hook end', (hook) => this.emit('hook end', EchoRunner.deserializeRunnable(hook)));
event.on('pass', (test) => this.emit('pass', EchoRunner.deserializeRunnable(test)));
event.on('fail', (test, err) => this.emit('fail', EchoRunner.deserializeRunnable(test, title), EchoRunner.deserializeError(err)));
event.on('pending', (test) => this.emit('pending', EchoRunner.deserializeRunnable(test)));
}
static deserializeSuite(suite, titleExtra) {
return {
root: suite.root,
suites: suite.suites,
tests: suite.tests,
title: titleExtra && suite.title ? `${suite.title} - /${titleExtra}/` : suite.title,
fullTitle: () => suite.fullTitle,
timeout: () => suite.timeout,
retries: () => suite.retries,
enableTimeouts: () => suite.enableTimeouts,
slow: () => suite.slow,
bail: () => suite.bail
};
}
static deserializeRunnable(runnable, titleExtra) {
return {
title: runnable.title,
fullTitle: () => titleExtra && runnable.fullTitle ? `${runnable.fullTitle} - /${titleExtra}/` : runnable.fullTitle,
async: runnable.async,
slow: () => runnable.slow,
speed: runnable.speed,
duration: runnable.duration
};
}
static deserializeError(err) {
const inspect = err.inspect;
err.inspect = () => inspect;
return err;
}
}
testModules.then(async modules => {
// run tests in selected browsers
const browserTypes = Array.isArray(argv.browser)
? argv.browser : [argv.browser];
const promises = browserTypes.map(async browserType => {
try {
return await runTestsInBrowser(modules, browserType);
} catch (err) {
console.error(err);
process.exit(1);
}
});
// aftermath
let didFail = false;
const messages = await Promise.all(promises);
for (let msg of messages) {
if (msg) {
didFail = true;
console.log(msg);
}
}
process.exit(didFail ? 1 : 0);
}).catch(err => {
console.error(err);
});

View File

@ -0,0 +1,148 @@
<html>
<head>
<meta charset="utf-8">
<title>VSCode Tests</title>
<link href="../../../node_modules/mocha/mocha.css" rel="stylesheet" />
</head>
<body>
<div id="mocha"></div>
<script src="../../../node_modules/mocha/mocha.js"></script>
<script>
// !!! DO NOT CHANGE !!!
// Our unit tests may run in environments without
// display (e.g. from builds) and tests may by
// accident bring up native dialogs or even open
// windows. This we cannot allow as it may crash
// the test run.
// !!! DO NOT CHANGE !!!
window.open = function () { throw new Error('window.open() is not supported in tests!'); };
window.alert = function () { throw new Error('window.alert() is not supported in tests!'); }
window.confirm = function () { throw new Error('window.confirm() is not supported in tests!'); }
// Ignore uncaught cancelled promise errors
window.addEventListener('unhandledrejection', e => {
const name = e && e.reason && e.reason.name;
if (name === 'Canceled') {
e.preventDefault();
e.stopPropagation();
}
});
mocha.setup({
ui: 'tdd',
timeout: 5000
});
</script>
<!-- Depending on --build or not, load loader from known locations -->
<script src="../../../out/vs/loader.js"></script>
<script src="../../../out-build/vs/loader.js"></script>
<script>
const urlParams = new URLSearchParams(window.location.search);
const isBuild = urlParams.get('build');
// configure loader
const baseUrl = window.location.href;
require.config({
catchError: true,
baseUrl: new URL('../../../src', baseUrl).href,
paths: {
vs: new URL(`../../../${!!isBuild ? 'out-build' : 'out'}/vs`, baseUrl).href,
assert: new URL('../assert.js', baseUrl).href,
sinon: new URL('../../../node_modules/sinon/pkg/sinon-1.17.7.js', baseUrl).href,
xterm: new URL('../../../node_modules/xterm/lib/xterm.js', baseUrl).href,
'iconv-lite-umd': new URL('../../../node_modules/iconv-lite-umd/lib/iconv-lite-umd.js', baseUrl).href,
jschardet: new URL('../../../node_modules/jschardet/dist/jschardet.min.js', baseUrl).href
}
});
</script>
<script>
function serializeSuite(suite) {
return {
root: suite.root,
suites: suite.suites.map(serializeSuite),
tests: suite.tests.map(serializeRunnable),
title: suite.title,
fullTitle: suite.fullTitle(),
timeout: suite.timeout(),
retries: suite.retries(),
enableTimeouts: suite.enableTimeouts(),
slow: suite.slow(),
bail: suite.bail()
};
}
function serializeRunnable(runnable) {
return {
title: runnable.title,
fullTitle: runnable.fullTitle(),
async: runnable.async,
slow: runnable.slow(),
speed: runnable.speed,
duration: runnable.duration
};
}
function serializeError(err) {
return {
message: err.message,
stack: err.stack,
actual: err.actual,
expected: err.expected,
uncaught: err.uncaught,
showDiff: err.showDiff,
inspect: typeof err.inspect === 'function' ? err.inspect() : ''
};
}
function PlaywrightReporter(runner) {
runner.on('start', () => window.mocha_report('start'));
runner.on('end', () => window.mocha_report('end'));
runner.on('suite', suite => window.mocha_report('suite', serializeSuite(suite)));
runner.on('suite end', suite => window.mocha_report('suite end', serializeSuite(suite)));
runner.on('test', test => window.mocha_report('test', serializeRunnable(test)));
runner.on('test end', test => window.mocha_report('test end', serializeRunnable(test)));
runner.on('hook', hook => window.mocha_report('hook', serializeRunnable(hook)));
runner.on('hook end', hook => window.mocha_report('hook end', serializeRunnable(hook)));
runner.on('pass', test => window.mocha_report('pass', serializeRunnable(test)));
runner.on('fail', (test, err) => window.mocha_report('fail', serializeRunnable(test), serializeError(err)));
runner.on('pending', test => window.mocha_report('pending', serializeRunnable(test)));
};
window.loadAndRun = async function loadAndRun(modules, manual = false) {
// load
await Promise.all(modules.map(module => new Promise((resolve, reject) => {
require([module], resolve, err => {
console.log("BAD " + module + JSON.stringify(err, undefined, '\t'));
// console.log(module);
resolve({});
});
})));
// await new Promise((resolve, reject) => {
// require(modules, resolve, err => {
// console.log(err);
// reject(err);
// });
// });
// run
return new Promise((resolve, reject) => {
if (!manual) {
mocha.reporter(PlaywrightReporter);
}
mocha.run(failCount => resolve(failCount === 0));
});
}
const modules = new URL(window.location.href).searchParams.getAll('m');
if (Array.isArray(modules) && modules.length > 0) {
console.log('MANUALLY running tests', modules);
loadAndRun(modules, true).then(() => console.log('done'), err => console.log(err));
}
</script>
</body>
</html>