mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Merge from vscode 718331d6f3ebd1b571530ab499edb266ddd493d5
This commit is contained in:
@@ -1,32 +1,36 @@
|
||||
# Tests
|
||||
# VSCode Tests
|
||||
|
||||
## Run
|
||||
## Contents
|
||||
|
||||
The best way to run the Code tests is from the terminal. To make development changes to unit tests you need to be running `yarn run watch`. See [Development Workflow](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#incremental-build) for more details. From the `azuredatastudio` folder run:
|
||||
|
||||
**OS X and Linux**
|
||||
|
||||
./scripts/test.sh
|
||||
|
||||
**Windows**
|
||||
|
||||
scripts\test
|
||||
This folder contains the various test runners for VSCode. Please refer to the documentation within for how to run them:
|
||||
* `unit`: our suite of unit tests
|
||||
* `integration`: our suite of API tests
|
||||
* `smoke`: our suite of automated UI tests
|
||||
* `ui`: our suite of manual UI tests
|
||||
|
||||
|
||||
## Debug
|
||||
|
||||
To debug tests use `--debug` when running the test script. Also, the set of tests can be reduced with the `--run` and `--runGlob` flags. Both require a file path/pattern. Like so:
|
||||
### Unit Tests (Electron-runner)
|
||||
|
||||
./scripts/test.sh --debug --runGrep **/extHost*.test.js
|
||||
```
|
||||
./scripts/test.[sh|bat]
|
||||
```
|
||||
|
||||
## Coverage
|
||||
All unit tests are run inside a electron-browser environment which access to DOM and Nodejs api. This is the closest to the enviroment in which VS Code itself ships. Notes:
|
||||
|
||||
The following command will create a `coverage` folder at the root of the workspace:
|
||||
- use the `--debug` to see an electron window with dev tools which allows for debugging
|
||||
- to run only a subset of tests use the `--run` or `--glob` options
|
||||
|
||||
**OS X and Linux**
|
||||
### Unit Tests (Browser-runner)
|
||||
|
||||
./scripts/test.sh --coverage
|
||||
```
|
||||
yarn test-browser --browser webkit --browser chromium
|
||||
```
|
||||
|
||||
**Windows**
|
||||
Unit tests from layers `common` and `browser` are run inside `chromium`, `webkit`, and (soon’ish) `firefox` (using playwright). This complements our electron-based unit test runner and adds more coverage of supported platforms. Notes:
|
||||
|
||||
- these tests are part of the continuous build, that means you might have test failures that only happen with webkit on _windows_ or _chromium_ on linux
|
||||
- you can these tests locally via yarn `test-browser --browser chromium --browser webkit`
|
||||
- to debug, open `<vscode>/test/unit/browser/renderer.html` inside a browser and use the `?m=<amd_module>`-query to specify what AMD module to load, e.g `file:///Users/jrieken/Code/vscode/test/unit/browser/renderer.html?m=vs/base/test/common/strings.test` runs all tests from `strings.test.ts`
|
||||
- to run only a subset of tests use the `--run` or `--glob` options
|
||||
|
||||
scripts\test --coverage
|
||||
|
||||
@@ -20,20 +20,19 @@
|
||||
"prepublishOnly": "npm run copy-package-version"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/debug": "4.1.5",
|
||||
"@types/mkdirp": "0.5.1",
|
||||
"@types/ncp": "2.0.1",
|
||||
"@types/node": "8.0.33",
|
||||
"@types/puppeteer": "^1.19.0",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/tmp": "0.1.0",
|
||||
"concurrently": "^3.5.1",
|
||||
"cpx": "^1.5.0",
|
||||
"typescript": "2.9.2",
|
||||
"typescript": "3.7.5",
|
||||
"watch": "^1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1",
|
||||
"ncp": "^2.0.0",
|
||||
"puppeteer": "^1.19.0",
|
||||
"tmp": "0.1.0",
|
||||
"vscode-uri": "^2.0.3"
|
||||
}
|
||||
|
||||
@@ -133,6 +133,7 @@ export class Application {
|
||||
extraArgs,
|
||||
remote: this.options.remote,
|
||||
web: this.options.web,
|
||||
browser: this.options.browser,
|
||||
headless: this.options.headless
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import * as fs from 'fs';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import { tmpName } from 'tmp';
|
||||
import { IDriver, connect as connectElectronDriver, IDisposable, IElement, Thenable } from './driver';
|
||||
import { connect as connectPuppeteerDriver, launch } from './puppeteerDriver';
|
||||
import { connect as connectPlaywrightDriver, launch } from './playwrightDriver';
|
||||
import { Logger } from './logger';
|
||||
import { ncp } from 'ncp';
|
||||
import { URI } from 'vscode-uri';
|
||||
@@ -101,6 +101,8 @@ export interface SpawnOptions {
|
||||
remote?: boolean;
|
||||
/** Run in the web */
|
||||
web?: boolean;
|
||||
/** A specific browser to use (requires web: true) */
|
||||
browser?: 'chromium' | 'webkit' | 'firefox';
|
||||
/** Run in headless mode (only applies when web is true) */
|
||||
headless?: boolean;
|
||||
}
|
||||
@@ -120,68 +122,69 @@ export async function spawn(options: SpawnOptions): Promise<Code> {
|
||||
const outPath = codePath ? getBuildOutPath(codePath) : getDevOutPath();
|
||||
const handle = await createDriverHandle();
|
||||
|
||||
const args = [
|
||||
options.workspacePath,
|
||||
'--skip-getting-started',
|
||||
'--skip-release-notes',
|
||||
'--sticky-quickopen',
|
||||
'--disable-telemetry',
|
||||
'--disable-updates',
|
||||
'--disable-crash-reporter',
|
||||
`--extensions-dir=${options.extensionsPath}`,
|
||||
`--user-data-dir=${options.userDataDir}`,
|
||||
'--driver', handle
|
||||
];
|
||||
|
||||
const env = process.env;
|
||||
|
||||
if (options.remote) {
|
||||
// Replace workspace path with URI
|
||||
args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`;
|
||||
|
||||
if (codePath) {
|
||||
// running against a build: copy the test resolver extension
|
||||
const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver');
|
||||
if (!fs.existsSync(testResolverExtPath)) {
|
||||
const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver');
|
||||
await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c()));
|
||||
}
|
||||
}
|
||||
args.push('--enable-proposed-api=vscode.vscode-test-resolver');
|
||||
const remoteDataDir = `${options.userDataDir}-server`;
|
||||
mkdirp.sync(remoteDataDir);
|
||||
env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir;
|
||||
}
|
||||
|
||||
if (!codePath) {
|
||||
args.unshift(repoPath);
|
||||
}
|
||||
|
||||
if (options.verbose) {
|
||||
args.push('--driver-verbose');
|
||||
}
|
||||
|
||||
if (options.log) {
|
||||
args.push('--log', options.log);
|
||||
}
|
||||
|
||||
if (options.extraArgs) {
|
||||
args.push(...options.extraArgs);
|
||||
}
|
||||
|
||||
let child: cp.ChildProcess | undefined;
|
||||
let connectDriver: typeof connectElectronDriver;
|
||||
|
||||
if (options.web) {
|
||||
await launch(args);
|
||||
connectDriver = connectPuppeteerDriver.bind(connectPuppeteerDriver, !!options.headless);
|
||||
await launch(options.userDataDir, options.workspacePath, options.codePath);
|
||||
connectDriver = connectPlaywrightDriver.bind(connectPlaywrightDriver, !!options.headless, options.browser);
|
||||
} else {
|
||||
const env = process.env;
|
||||
|
||||
const args = [
|
||||
options.workspacePath,
|
||||
'--skip-getting-started',
|
||||
'--skip-release-notes',
|
||||
'--sticky-quickopen',
|
||||
'--disable-telemetry',
|
||||
'--disable-updates',
|
||||
'--disable-crash-reporter',
|
||||
`--extensions-dir=${options.extensionsPath}`,
|
||||
`--user-data-dir=${options.userDataDir}`,
|
||||
'--driver', handle
|
||||
];
|
||||
|
||||
if (options.remote) {
|
||||
// Replace workspace path with URI
|
||||
args[0] = `--${options.workspacePath.endsWith('.code-workspace') ? 'file' : 'folder'}-uri=vscode-remote://test+test/${URI.file(options.workspacePath).path}`;
|
||||
|
||||
if (codePath) {
|
||||
// running against a build: copy the test resolver extension
|
||||
const testResolverExtPath = path.join(options.extensionsPath, 'vscode-test-resolver');
|
||||
if (!fs.existsSync(testResolverExtPath)) {
|
||||
const orig = path.join(repoPath, 'extensions', 'vscode-test-resolver');
|
||||
await new Promise((c, e) => ncp(orig, testResolverExtPath, err => err ? e(err) : c()));
|
||||
}
|
||||
}
|
||||
args.push('--enable-proposed-api=vscode.vscode-test-resolver');
|
||||
const remoteDataDir = `${options.userDataDir}-server`;
|
||||
mkdirp.sync(remoteDataDir);
|
||||
env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir;
|
||||
}
|
||||
|
||||
if (!codePath) {
|
||||
args.unshift(repoPath);
|
||||
}
|
||||
|
||||
if (options.verbose) {
|
||||
args.push('--driver-verbose');
|
||||
}
|
||||
|
||||
if (options.log) {
|
||||
args.push('--log', options.log);
|
||||
}
|
||||
|
||||
if (options.extraArgs) {
|
||||
args.push(...options.extraArgs);
|
||||
}
|
||||
|
||||
const spawnOptions: cp.SpawnOptions = { env };
|
||||
child = cp.spawn(electronPath, args, spawnOptions);
|
||||
instances.add(child);
|
||||
child.once('exit', () => instances.delete(child!));
|
||||
connectDriver = connectElectronDriver;
|
||||
}
|
||||
|
||||
return connect(connectDriver, child, outPath, handle, options.logger);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ export class Editor {
|
||||
const line = `${editor} .view-lines > .view-line:nth-child(${lineNumber})`;
|
||||
const textarea = `${editor} textarea`;
|
||||
|
||||
await this.code.waitAndClick(line, 0, 0);
|
||||
await this.code.waitAndClick(line, 1, 1);
|
||||
await this.code.waitForActiveElement(textarea);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,27 +17,27 @@ export class Editors {
|
||||
}
|
||||
}
|
||||
|
||||
async selectTab(tabName: string, untitled: boolean = false): Promise<void> {
|
||||
await this.code.waitAndClick(`.tabs-container div.tab[aria-label="${tabName}, tab"]`);
|
||||
await this.waitForEditorFocus(tabName, untitled);
|
||||
async selectTab(fileName: string): Promise<void> {
|
||||
await this.code.waitAndClick(`.tabs-container div.tab[data-resource-name$="${fileName}"]`);
|
||||
await this.waitForEditorFocus(fileName);
|
||||
}
|
||||
|
||||
async waitForActiveEditor(filename: string): Promise<any> {
|
||||
const selector = `.editor-instance .monaco-editor[data-uri$="${filename}"] textarea`;
|
||||
async waitForActiveEditor(fileName: string): Promise<any> {
|
||||
const selector = `.editor-instance .monaco-editor[data-uri$="${fileName}"] textarea`;
|
||||
return this.code.waitForActiveElement(selector);
|
||||
}
|
||||
|
||||
async waitForEditorFocus(fileName: string, untitled: boolean = false): Promise<void> {
|
||||
async waitForEditorFocus(fileName: string): Promise<void> {
|
||||
await this.waitForActiveTab(fileName);
|
||||
await this.waitForActiveEditor(fileName);
|
||||
}
|
||||
|
||||
async waitForActiveTab(fileName: string, isDirty: boolean = false): Promise<void> {
|
||||
await this.code.waitForElement(`.tabs-container div.tab.active${isDirty ? '.dirty' : ''}[aria-selected="true"][aria-label="${fileName}, tab"]`);
|
||||
await this.code.waitForElement(`.tabs-container div.tab.active${isDirty ? '.dirty' : ''}[aria-selected="true"][data-resource-name$="${fileName}"]`);
|
||||
}
|
||||
|
||||
async waitForTab(fileName: string, isDirty: boolean = false): Promise<void> {
|
||||
await this.code.waitForElement(`.tabs-container div.tab${isDirty ? '.dirty' : ''}[aria-label="${fileName}, tab"]`);
|
||||
await this.code.waitForElement(`.tabs-container div.tab${isDirty ? '.dirty' : ''}[data-resource-name$="${fileName}"]`);
|
||||
}
|
||||
|
||||
async newUntitledFile(): Promise<void> {
|
||||
@@ -47,6 +47,6 @@ export class Editors {
|
||||
await this.code.dispatchKeybinding('ctrl+n');
|
||||
}
|
||||
|
||||
await this.waitForEditorFocus('Untitled-1', true);
|
||||
await this.waitForEditorFocus('Untitled-1');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,18 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as puppeteer from 'puppeteer';
|
||||
import * as playwright from 'playwright';
|
||||
import { ChildProcess, spawn } from 'child_process';
|
||||
import { join } from 'path';
|
||||
import { mkdir } from 'fs';
|
||||
import { promisify } from 'util';
|
||||
import { IDriver, IDisposable } from './driver';
|
||||
import { URI } from 'vscode-uri';
|
||||
|
||||
const width = 1200;
|
||||
const height = 800;
|
||||
|
||||
const vscodeToPuppeteerKey: { [key: string]: string } = {
|
||||
const vscodeToPlaywrightKey: { [key: string]: string } = {
|
||||
cmd: 'Meta',
|
||||
ctrl: 'Control',
|
||||
shift: 'Shift',
|
||||
@@ -26,7 +27,7 @@ const vscodeToPuppeteerKey: { [key: string]: string } = {
|
||||
home: 'Home'
|
||||
};
|
||||
|
||||
function buildDriver(browser: puppeteer.Browser, page: puppeteer.Page): IDriver {
|
||||
function buildDriver(browser: playwright.Browser, page: playwright.Page): IDriver {
|
||||
const driver: IDriver = {
|
||||
_serviceBrand: undefined,
|
||||
getWindowIds: () => {
|
||||
@@ -45,8 +46,8 @@ function buildDriver(browser: puppeteer.Browser, page: puppeteer.Page): IDriver
|
||||
const keys = chord.split('+');
|
||||
const keysDown: string[] = [];
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (keys[i] in vscodeToPuppeteerKey) {
|
||||
keys[i] = vscodeToPuppeteerKey[keys[i]];
|
||||
if (keys[i] in vscodeToPlaywrightKey) {
|
||||
keys[i] = vscodeToPlaywrightKey[keys[i]];
|
||||
}
|
||||
await page.keyboard.down(keys[i]);
|
||||
keysDown.push(keys[i]);
|
||||
@@ -68,7 +69,7 @@ function buildDriver(browser: puppeteer.Browser, page: puppeteer.Page): IDriver
|
||||
await driver.click(windowId, selector, 0, 0);
|
||||
await timeout(100);
|
||||
},
|
||||
setValue: async (windowId, selector, text) => page.evaluate(`window.driver.setValue('${selector}', '${text}')`),
|
||||
setValue: async (windowId, selector, text) => page.evaluate(`window.driver.setValue('${selector}', '${text}')`).then(undefined),
|
||||
getTitle: (windowId) => page.evaluate(`window.driver.getTitle()`),
|
||||
isActiveElement: (windowId, selector) => page.evaluate(`window.driver.isActiveElement('${selector}')`),
|
||||
getElements: (windowId, selector, recursive) => page.evaluate(`window.driver.getElements('${selector}', ${recursive})`),
|
||||
@@ -86,25 +87,32 @@ function timeout(ms: number): Promise<void> {
|
||||
|
||||
// function runInDriver(call: string, args: (string | boolean)[]): Promise<any> {}
|
||||
|
||||
let args: string[] | undefined;
|
||||
let server: ChildProcess | undefined;
|
||||
let endpoint: string | undefined;
|
||||
let workspacePath: string | undefined;
|
||||
|
||||
export async function launch(_args: string[]): Promise<void> {
|
||||
args = _args;
|
||||
const agentFolder = args.filter(e => e.includes('--user-data-dir='))[0].replace('--user-data-dir=', '');
|
||||
export async function launch(userDataDir: string, _workspacePath: string, codeServerPath = process.env.VSCODE_REMOTE_SERVER_PATH): Promise<void> {
|
||||
workspacePath = _workspacePath;
|
||||
const agentFolder = userDataDir;
|
||||
await promisify(mkdir)(agentFolder);
|
||||
const env = {
|
||||
VSCODE_AGENT_FOLDER: agentFolder,
|
||||
VSCODE_REMOTE_SERVER_PATH: codeServerPath,
|
||||
...process.env
|
||||
};
|
||||
let serverLocation: string | undefined;
|
||||
if (codeServerPath) {
|
||||
serverLocation = join(codeServerPath, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
|
||||
} else {
|
||||
serverLocation = join(__dirname, '..', '..', '..', `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`);
|
||||
}
|
||||
server = spawn(
|
||||
join(args[0], `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`),
|
||||
serverLocation,
|
||||
['--browser', 'none', '--driver', 'web'],
|
||||
{ env }
|
||||
);
|
||||
server.stderr.on('data', e => console.log('Server stderr: ' + e));
|
||||
server.stdout.on('data', e => console.log('Server stdout: ' + e));
|
||||
server.stderr?.on('data', error => console.log(`Server stderr: ${error}`));
|
||||
server.stdout?.on('data', data => console.log(`Server stdout: ${data}`));
|
||||
process.on('exit', teardown);
|
||||
process.on('SIGINT', teardown);
|
||||
process.on('SIGTERM', teardown);
|
||||
@@ -120,7 +128,7 @@ function teardown(): void {
|
||||
|
||||
function waitForEndpoint(): Promise<string> {
|
||||
return new Promise<string>(r => {
|
||||
server!.stdout.on('data', (d: Buffer) => {
|
||||
server!.stdout?.on('data', (d: Buffer) => {
|
||||
const matches = d.toString('ascii').match(/Web UI available at (.+)/);
|
||||
if (matches !== null) {
|
||||
r(matches[1]);
|
||||
@@ -129,20 +137,18 @@ function waitForEndpoint(): Promise<string> {
|
||||
});
|
||||
}
|
||||
|
||||
export function connect(headless: boolean, outPath: string, handle: string): Promise<{ client: IDisposable, driver: IDriver }> {
|
||||
export function connect(headless: boolean, engine: 'chromium' | 'webkit' | 'firefox' = 'chromium'): Promise<{ client: IDisposable, driver: IDriver }> {
|
||||
return new Promise(async (c) => {
|
||||
const browser = await puppeteer.launch({
|
||||
const browser = await playwright[engine].launch({
|
||||
// Run in Edge dev on macOS
|
||||
// executablePath: '/Applications/Microsoft\ Edge\ Dev.app/Contents/MacOS/Microsoft\ Edge\ Dev',
|
||||
headless,
|
||||
slowMo: 80,
|
||||
args: [`--window-size=${width},${height}`]
|
||||
headless
|
||||
});
|
||||
const page = (await browser.pages())[0];
|
||||
const page = (await browser.defaultContext().pages())[0];
|
||||
await page.setViewport({ width, height });
|
||||
await page.goto(`${endpoint}&folder=${args![1]}`);
|
||||
await page.goto(`${endpoint}&folder=vscode-remote://localhost:9888${URI.file(workspacePath!).path}`);
|
||||
const result = {
|
||||
client: { dispose: () => teardown },
|
||||
client: { dispose: () => browser.close() && teardown() },
|
||||
driver: buildDriver(browser, page)
|
||||
};
|
||||
c(result);
|
||||
@@ -12,7 +12,7 @@ export const enum ProblemSeverity {
|
||||
|
||||
export class Problems {
|
||||
|
||||
static PROBLEMS_VIEW_SELECTOR = '.panel.markers-panel';
|
||||
static PROBLEMS_VIEW_SELECTOR = '.panel .markers-panel';
|
||||
|
||||
constructor(private code: Code) { }
|
||||
|
||||
|
||||
@@ -109,11 +109,12 @@ export class Search extends Viewlet {
|
||||
}
|
||||
|
||||
async waitForResultText(text: string): Promise<void> {
|
||||
await this.code.waitForTextContent(`${VIEWLET} .messages .message>p`, text);
|
||||
// The label can end with " - " depending on whether the search editor is enabled
|
||||
await this.code.waitForTextContent(`${VIEWLET} .messages .message>span`, undefined, result => result.startsWith(text));
|
||||
}
|
||||
|
||||
async waitForNoResultText(): Promise<void> {
|
||||
await this.code.waitForElement(`${VIEWLET} .messages[aria-hidden="true"] .message>p`);
|
||||
await this.code.waitForElement(`${VIEWLET} .messages[aria-hidden="true"] .message>span`);
|
||||
}
|
||||
|
||||
private async waitForInputFocus(selector: string): Promise<void> {
|
||||
|
||||
@@ -20,8 +20,6 @@ export const enum StatusBarElement {
|
||||
export class StatusBar {
|
||||
|
||||
private readonly mainSelector = 'div[id="workbench.parts.statusbar"]';
|
||||
private readonly leftSelector = '.statusbar-item.left';
|
||||
private readonly rightSelector = '.statusbar-item.right';
|
||||
|
||||
constructor(private code: Code) { }
|
||||
|
||||
@@ -44,23 +42,23 @@ export class StatusBar {
|
||||
private getSelector(element: StatusBarElement): string {
|
||||
switch (element) {
|
||||
case StatusBarElement.BRANCH_STATUS:
|
||||
return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-git-branch`;
|
||||
return `.statusbar-item[id="status.scm"] .codicon.codicon-git-branch`;
|
||||
case StatusBarElement.SYNC_STATUS:
|
||||
return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-sync`;
|
||||
return `.statusbar-item[id="status.scm"] .codicon.codicon-sync`;
|
||||
case StatusBarElement.PROBLEMS_STATUS:
|
||||
return `${this.mainSelector} ${this.leftSelector} .codicon.codicon-error`;
|
||||
return `.statusbar-item[id="status.problems"]`;
|
||||
case StatusBarElement.SELECTION_STATUS:
|
||||
return `${this.mainSelector} ${this.rightSelector}[title="Go to Line"]`;
|
||||
return `.statusbar-item[id="status.editor.selection"]`;
|
||||
case StatusBarElement.INDENTATION_STATUS:
|
||||
return `${this.mainSelector} ${this.rightSelector}[title="Select Indentation"]`;
|
||||
return `.statusbar-item[id="status.editor.indentation"]`;
|
||||
case StatusBarElement.ENCODING_STATUS:
|
||||
return `${this.mainSelector} ${this.rightSelector}[title="Select Encoding"]`;
|
||||
return `.statusbar-item[id="status.editor.encoding"]`;
|
||||
case StatusBarElement.EOL_STATUS:
|
||||
return `${this.mainSelector} ${this.rightSelector}[title="Select End of Line Sequence"]`;
|
||||
return `.statusbar-item[id="status.editor.eol"]`;
|
||||
case StatusBarElement.LANGUAGE_STATUS:
|
||||
return `${this.mainSelector} ${this.rightSelector}[title="Select Language Mode"]`;
|
||||
return `.statusbar-item[id="status.editor.mode"]`;
|
||||
case StatusBarElement.FEEDBACK_ICON:
|
||||
return `${this.mainSelector} .statusbar-item.right[id="status.feedback"]`;
|
||||
return `.statusbar-item[id="status.feedback"]`;
|
||||
default:
|
||||
throw new Error(element);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,6 @@
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"out",
|
||||
"tools",
|
||||
"tools"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/debug@4.1.5":
|
||||
version "4.1.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
|
||||
integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
|
||||
|
||||
"@types/mkdirp@0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.1.tgz#ea887cd024f691c1ca67cce20b7606b053e43b0f"
|
||||
@@ -21,17 +26,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.1.tgz#3b5c3a26393c19b400844ac422bd0f631a94d69d"
|
||||
integrity sha512-aK9jxMypeSrhiYofWWBf/T7O+KwaiAHzM4sveCdWPn71lzUSMimRnKzhXDKfKwV1kWoBo2P1aGgaIYGLf9/ljw==
|
||||
|
||||
"@types/node@8.0.33":
|
||||
version "8.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd"
|
||||
integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A==
|
||||
|
||||
"@types/puppeteer@^1.19.0":
|
||||
version "1.19.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/puppeteer/-/puppeteer-1.19.1.tgz#942ca62288953a0f5fbbc25c103b5f2ba28b60ab"
|
||||
integrity sha512-ReWZvoEfMiJIA3AG+eM+nCx5GKrU2ANVYY5TC0nbpeiTCtnJbcqnmBbR8TkXMBTvLBYcuTOAELbTcuX73siDNQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
"@types/node@^12.11.7":
|
||||
version "12.12.26"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9"
|
||||
integrity sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==
|
||||
|
||||
"@types/tmp@0.1.0":
|
||||
version "0.1.0"
|
||||
@@ -43,13 +41,6 @@ abbrev@1:
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
agent-base@^4.3.0:
|
||||
version "4.3.0"
|
||||
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
|
||||
integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==
|
||||
dependencies:
|
||||
es6-promisify "^5.0.0"
|
||||
|
||||
ansi-regex@^2.0.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
|
||||
@@ -130,11 +121,6 @@ async-each@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
|
||||
integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
|
||||
|
||||
async-limiter@~1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd"
|
||||
integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==
|
||||
|
||||
atob@^2.1.1:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
@@ -204,11 +190,6 @@ braces@^2.3.1:
|
||||
split-string "^3.0.2"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
buffer-from@^1.0.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
|
||||
integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
|
||||
|
||||
cache-base@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
|
||||
@@ -304,16 +285,6 @@ concat-map@0.0.1:
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
concat-stream@1.6.2:
|
||||
version "1.6.2"
|
||||
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
|
||||
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
|
||||
dependencies:
|
||||
buffer-from "^1.0.0"
|
||||
inherits "^2.0.3"
|
||||
readable-stream "^2.2.2"
|
||||
typedarray "^0.0.6"
|
||||
|
||||
concurrently@^3.5.1:
|
||||
version "3.6.1"
|
||||
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-3.6.1.tgz#2f95baec5c4051294dfbb55b57a3b98a3e2b45ec"
|
||||
@@ -371,27 +342,20 @@ date-fns@^1.23.0:
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.30.1.tgz#2e71bf0b119153dbb4cc4e88d9ea5acfb50dc05c"
|
||||
integrity sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==
|
||||
|
||||
debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
|
||||
debug@^2.2.0, debug@^2.3.3:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.1.0, debug@^3.2.6:
|
||||
debug@^3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
debug@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
|
||||
integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
@@ -446,18 +410,6 @@ error-ex@^1.3.1:
|
||||
dependencies:
|
||||
is-arrayish "^0.2.1"
|
||||
|
||||
es6-promise@^4.0.3:
|
||||
version "4.2.8"
|
||||
resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
|
||||
integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
|
||||
|
||||
es6-promisify@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203"
|
||||
integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=
|
||||
dependencies:
|
||||
es6-promise "^4.0.3"
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
@@ -533,23 +485,6 @@ extglob@^2.0.4:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.1"
|
||||
|
||||
extract-zip@^1.6.6:
|
||||
version "1.6.7"
|
||||
resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.6.7.tgz#a840b4b8af6403264c8db57f4f1a74333ef81fe9"
|
||||
integrity sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=
|
||||
dependencies:
|
||||
concat-stream "1.6.2"
|
||||
debug "2.6.9"
|
||||
mkdirp "0.5.1"
|
||||
yauzl "2.4.1"
|
||||
|
||||
fd-slicer@~1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65"
|
||||
integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=
|
||||
dependencies:
|
||||
pend "~1.2.0"
|
||||
|
||||
filename-regex@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
|
||||
@@ -729,14 +664,6 @@ hosted-git-info@^2.1.4:
|
||||
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.4.tgz#44119abaf4bc64692a16ace34700fed9c03e2546"
|
||||
integrity sha512-pzXIvANXEFrc5oFFXRMkbLPQ2rXRoDERwDLyrcUxGhaZhgP54BBSl9Oheh7Vv0T090cszWBxPjkQQ5Sq1PbBRQ==
|
||||
|
||||
https-proxy-agent@^2.2.1:
|
||||
version "2.2.3"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz#fb6cd98ed5b9c35056b5a73cd01a8a721d7193d1"
|
||||
integrity sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==
|
||||
dependencies:
|
||||
agent-base "^4.3.0"
|
||||
debug "^3.1.0"
|
||||
|
||||
iconv-lite@^0.4.4:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
@@ -759,7 +686,7 @@ inflight@^1.0.4:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3:
|
||||
inherits@2, inherits@^2.0.1, inherits@~2.0.3:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
@@ -1042,11 +969,6 @@ micromatch@^3.1.10:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.2"
|
||||
|
||||
mime@^2.0.3:
|
||||
version "2.4.4"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
|
||||
integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
|
||||
|
||||
minimatch@^3.0.2, minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
@@ -1087,7 +1009,7 @@ mixin-deep@^1.2.0:
|
||||
for-in "^1.0.2"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
mkdirp@^0.5.0, mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
|
||||
@@ -1310,11 +1232,6 @@ path-type@^3.0.0:
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
pend@~1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50"
|
||||
integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
@@ -1335,30 +1252,6 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
progress@^2.0.1:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
|
||||
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
|
||||
|
||||
proxy-from-env@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee"
|
||||
integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=
|
||||
|
||||
puppeteer@^1.19.0:
|
||||
version "1.19.0"
|
||||
resolved "https://registry.yarnpkg.com/puppeteer/-/puppeteer-1.19.0.tgz#e3b7b448c2c97933517078d7a2c53687361bebea"
|
||||
integrity sha512-2S6E6ygpoqcECaagDbBopoSOPDv0pAZvTbnBgUY+6hq0/XDFDOLEMNlHF/SKJlzcaZ9ckiKjKDuueWI3FN/WXw==
|
||||
dependencies:
|
||||
debug "^4.1.0"
|
||||
extract-zip "^1.6.6"
|
||||
https-proxy-agent "^2.2.1"
|
||||
mime "^2.0.3"
|
||||
progress "^2.0.1"
|
||||
proxy-from-env "^1.0.0"
|
||||
rimraf "^2.6.1"
|
||||
ws "^6.1.0"
|
||||
|
||||
randomatic@^3.0.0:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-3.1.1.tgz#b776efc59375984e36c537b2f51a1f0aff0da1ed"
|
||||
@@ -1387,7 +1280,7 @@ read-pkg@^3.0.0:
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^3.0.0"
|
||||
|
||||
readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2:
|
||||
readable-stream@^2.0.2, readable-stream@^2.0.6:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
|
||||
integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
|
||||
@@ -1746,15 +1639,10 @@ tree-kill@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a"
|
||||
integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==
|
||||
|
||||
typedarray@^0.0.6:
|
||||
version "0.0.6"
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
||||
typescript@3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
union-value@^1.0.0:
|
||||
version "1.0.1"
|
||||
@@ -1822,21 +1710,7 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
ws@^6.1.0:
|
||||
version "6.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb"
|
||||
integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
yallist@^3.0.0, yallist@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
|
||||
integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
|
||||
|
||||
yauzl@2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005"
|
||||
integrity sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=
|
||||
dependencies:
|
||||
fd-slicer "~1.0.1"
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
var express = require('express');
|
||||
var glob = require('glob');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
var port = 8887;
|
||||
var root = path.dirname(__dirname);
|
||||
|
||||
function template(str, env) {
|
||||
return str.replace(/{{\s*([\w_\-]+)\s*}}/g, function (all, part) {
|
||||
return env[part];
|
||||
});
|
||||
}
|
||||
|
||||
var app = express();
|
||||
|
||||
app.use('/out', express.static(path.join(root, 'out')));
|
||||
app.use('/test', express.static(path.join(root, 'test')));
|
||||
app.use('/node_modules', express.static(path.join(root, 'node_modules')));
|
||||
|
||||
app.get('/', function (req, res) {
|
||||
glob('**/vs/{base,platform,editor}/**/test/{common,browser}/**/*.test.js', {
|
||||
cwd: path.join(root, 'out'),
|
||||
// ignore: ['**/test/{node,electron*}/**/*.js']
|
||||
}, function (err, files) {
|
||||
if (err) { return res.sendStatus(500); }
|
||||
|
||||
var modules = files
|
||||
.map(function (file) { return file.replace(/\.js$/, ''); });
|
||||
|
||||
fs.readFile(path.join(__dirname, 'index.html'), 'utf8', function (err, templateString) {
|
||||
if (err) { return res.sendStatus(500); }
|
||||
|
||||
res.send(template(templateString, {
|
||||
modules: JSON.stringify(modules)
|
||||
}));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
app.listen(port, function () {
|
||||
console.log('http://localhost:8887/');
|
||||
});
|
||||
5
test/integration/browser/.gitignore
vendored
Normal file
5
test/integration/browser/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.DS_Store
|
||||
npm-debug.log
|
||||
Thumbs.db
|
||||
node_modules/
|
||||
out/
|
||||
13
test/integration/browser/README.md
Normal file
13
test/integration/browser/README.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# VS Code Integration test
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
|
||||
# Dev (Electron)
|
||||
scripts/test-integration.sh
|
||||
|
||||
# Dev (Web)
|
||||
node test/integration/browser/out/index.js
|
||||
|
||||
```
|
||||
18
test/integration/browser/package.json
Normal file
18
test/integration/browser/package.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"name": "code-oss-dev-integration-test",
|
||||
"version": "0.1.0",
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"postinstall": "npm run compile",
|
||||
"compile": "yarn tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/mkdirp": "0.5.1",
|
||||
"@types/node": "^12.11.7",
|
||||
"@types/rimraf": "2.0.2",
|
||||
"@types/tmp": "^0.1.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"tmp": "0.0.33",
|
||||
"typescript": "3.7.5"
|
||||
}
|
||||
}
|
||||
116
test/integration/browser/src/index.ts
Normal file
116
test/integration/browser/src/index.ts
Normal file
@@ -0,0 +1,116 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as cp from 'child_process';
|
||||
import * as playwright from 'playwright';
|
||||
import * as url from 'url';
|
||||
import * as tmp from 'tmp';
|
||||
import * as rimraf from 'rimraf';
|
||||
|
||||
const optimist = require('optimist')
|
||||
.describe('workspacePath', 'path to the workspace to open in the test').string()
|
||||
.describe('extensionDevelopmentPath', 'path to the extension to test').string()
|
||||
.describe('extensionTestsPath', 'path to the extension tests').string()
|
||||
.describe('debug', 'do not run browsers headless').boolean('debug')
|
||||
.describe('browser', 'browser in which integration tests should run').string('browser').default('browser', 'chromium')
|
||||
.describe('help', 'show the help').alias('help', 'h');
|
||||
|
||||
if (optimist.argv.help) {
|
||||
optimist.showHelp();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const width = 1200;
|
||||
const height = 800;
|
||||
|
||||
async function runTestsInBrowser(browserType: string, endpoint: string): Promise<void> {
|
||||
const browser = await playwright[browserType].launch({ headless: !Boolean(optimist.argv.debug) });
|
||||
const page = (await browser.defaultContext().pages())[0];
|
||||
await page.setViewport({ width, height });
|
||||
|
||||
const host = url.parse(endpoint).host;
|
||||
const protocol = 'vscode-remote';
|
||||
|
||||
const testWorkspaceUri = url.format({ pathname: path.resolve(optimist.argv.workspacePath), protocol, host, slashes: true });
|
||||
const testExtensionUri = url.format({ pathname: path.resolve(optimist.argv.extensionDevelopmentPath), protocol, host, slashes: true });
|
||||
const testFilesUri = url.format({ pathname: path.resolve(optimist.argv.extensionTestsPath), protocol, host, slashes: true });
|
||||
|
||||
const folderParam = testWorkspaceUri;
|
||||
const payloadParam = `[["extensionDevelopmentPath","${testExtensionUri}"],["extensionTestsPath","${testFilesUri}"]]`;
|
||||
|
||||
await page.goto(`${endpoint}&folder=${folderParam}&payload=${payloadParam}`);
|
||||
|
||||
await page.exposeFunction('codeAutomationLog', (type: string, args: any[]) => {
|
||||
console[type](...args);
|
||||
});
|
||||
|
||||
page.on('console', async (msg: playwright.ConsoleMessage) => {
|
||||
const msgText = msg.text();
|
||||
if (msgText.indexOf('vscode:exit') >= 0) {
|
||||
await browser.close();
|
||||
process.exit(msgText === 'vscode:exit 0' ? 0 : 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function launchServer(): Promise<string> {
|
||||
|
||||
// Ensure a tmp user-data-dir is used for the tests
|
||||
const tmpDir = tmp.dirSync({ prefix: 't' });
|
||||
const testDataPath = tmpDir.name;
|
||||
process.once('exit', () => rimraf.sync(testDataPath));
|
||||
|
||||
const userDataDir = path.join(testDataPath, 'd');
|
||||
|
||||
const env = {
|
||||
VSCODE_AGENT_FOLDER: userDataDir,
|
||||
...process.env
|
||||
};
|
||||
|
||||
let serverLocation: string;
|
||||
if (process.env.VSCODE_REMOTE_SERVER_PATH) {
|
||||
serverLocation = path.join(process.env.VSCODE_REMOTE_SERVER_PATH, `server.${process.platform === 'win32' ? 'cmd' : 'sh'}`);
|
||||
} else {
|
||||
serverLocation = path.join(__dirname, '..', '..', '..', '..', `resources/server/web.${process.platform === 'win32' ? 'bat' : 'sh'}`);
|
||||
|
||||
process.env.VSCODE_DEV = '1';
|
||||
}
|
||||
|
||||
let serverProcess = cp.spawn(
|
||||
serverLocation,
|
||||
['--browser', 'none', '--driver', 'web'],
|
||||
{ env }
|
||||
);
|
||||
|
||||
serverProcess?.stderr?.on('data', error => console.log(`Server stderr: ${error}`));
|
||||
|
||||
if (optimist.argv.debug) {
|
||||
serverProcess?.stdout?.on('data', data => console.log(`Server stdout: ${data}`));
|
||||
}
|
||||
|
||||
function teardownServer() {
|
||||
if (serverProcess) {
|
||||
serverProcess.kill();
|
||||
}
|
||||
}
|
||||
|
||||
process.on('exit', teardownServer);
|
||||
process.on('SIGINT', teardownServer);
|
||||
process.on('SIGTERM', teardownServer);
|
||||
|
||||
return new Promise(c => {
|
||||
serverProcess?.stdout?.on('data', data => {
|
||||
const matches = data.toString('ascii').match(/Web UI available at (.+)/);
|
||||
if (matches !== null) {
|
||||
c(matches[1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
launchServer().then(async endpoint => {
|
||||
return runTestsInBrowser(optimist.argv.browser, endpoint);
|
||||
}, console.error);
|
||||
21
test/integration/browser/tsconfig.json
Normal file
21
test/integration/browser/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"noImplicitAny": false,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"target": "es2017",
|
||||
"strictNullChecks": true,
|
||||
"noUnusedParameters": false,
|
||||
"noUnusedLocals": true,
|
||||
"outDir": "out",
|
||||
"sourceMap": true,
|
||||
"lib": [
|
||||
"es2016",
|
||||
"dom"
|
||||
]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
||||
148
test/integration/browser/yarn.lock
Normal file
148
test/integration/browser/yarn.lock
Normal file
@@ -0,0 +1,148 @@
|
||||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@types/events@*":
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
|
||||
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
|
||||
|
||||
"@types/glob@*":
|
||||
version "7.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
|
||||
integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
|
||||
dependencies:
|
||||
"@types/events" "*"
|
||||
"@types/minimatch" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/minimatch@*":
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||
|
||||
"@types/mkdirp@0.5.1":
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.5.1.tgz#ea887cd024f691c1ca67cce20b7606b053e43b0f"
|
||||
integrity sha512-XA4vNO6GCBz8Smq0hqSRo4yRWMqr4FPQrWjhJt6nKskzly4/p87SfuJMFYGRyYb6jo2WNIQU2FDBsY5r1BibUA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/node@*":
|
||||
version "13.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4"
|
||||
integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ==
|
||||
|
||||
"@types/node@^12.11.7":
|
||||
version "12.12.26"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.26.tgz#213e153babac0ed169d44a6d919501e68f59dea9"
|
||||
integrity sha512-UmUm94/QZvU5xLcUlNR8hA7Ac+fGpO1EG/a8bcWVz0P0LqtxFmun9Y2bbtuckwGboWJIT70DoWq1r3hb56n3DA==
|
||||
|
||||
"@types/rimraf@2.0.2":
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-2.0.2.tgz#7f0fc3cf0ff0ad2a99bb723ae1764f30acaf8b6e"
|
||||
integrity sha512-Hm/bnWq0TCy7jmjeN5bKYij9vw5GrDFWME4IuxV08278NtU/VdGbzsBohcCUJ7+QMqmUq5hpRKB39HeQWJjztQ==
|
||||
dependencies:
|
||||
"@types/glob" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/tmp@^0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd"
|
||||
integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
|
||||
dependencies:
|
||||
balanced-match "^1.0.0"
|
||||
concat-map "0.0.1"
|
||||
|
||||
concat-map@0.0.1:
|
||||
version "0.0.1"
|
||||
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
|
||||
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
|
||||
|
||||
fs.realpath@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
|
||||
|
||||
glob@^7.1.3:
|
||||
version "7.1.6"
|
||||
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
|
||||
integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
|
||||
dependencies:
|
||||
fs.realpath "^1.0.0"
|
||||
inflight "^1.0.4"
|
||||
inherits "2"
|
||||
minimatch "^3.0.4"
|
||||
once "^1.3.0"
|
||||
path-is-absolute "^1.0.0"
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
|
||||
dependencies:
|
||||
once "^1.3.0"
|
||||
wrappy "1"
|
||||
|
||||
inherits@2:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
minimatch@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
|
||||
integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
once@^1.3.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
|
||||
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
os-tmpdir@~1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
|
||||
|
||||
path-is-absolute@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
|
||||
integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
|
||||
|
||||
rimraf@^2.6.1:
|
||||
version "2.7.1"
|
||||
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
|
||||
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
|
||||
dependencies:
|
||||
glob "^7.1.3"
|
||||
|
||||
tmp@0.0.33:
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
|
||||
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
typescript@3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
@@ -1,21 +1,28 @@
|
||||
# VS Code Smoke Test
|
||||
|
||||
Make sure you are on **Node v10.x**.
|
||||
Make sure you are on **Node v12.x**.
|
||||
|
||||
### Run
|
||||
|
||||
```bash
|
||||
# Install Dependencies and Compile
|
||||
yarn --cwd test/smoke
|
||||
yarn --cwd test/automation
|
||||
|
||||
# Dev
|
||||
# Dev (Electron)
|
||||
yarn smoketest
|
||||
|
||||
# Build
|
||||
yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --stable-build PATH_TO_LAST_STABLE_BUILD_PARENT_FOLDER
|
||||
# Dev (Web)
|
||||
yarn smoketest --web --browser <chromium|firefox|webkit>
|
||||
|
||||
# Remote
|
||||
yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --remote
|
||||
# Build (Electron)
|
||||
yarn smoketest --build <path latest built version> --stable-build <path to previous stable version>
|
||||
|
||||
# Build (Web - read instructions below)
|
||||
yarn smoketest --build <path to web server folder> --web --browser <chromium|firefox|webkit>
|
||||
|
||||
# Remote (Electron)
|
||||
yarn smoketest --build <path latest built version> --remote
|
||||
```
|
||||
|
||||
### Run for a release
|
||||
@@ -27,18 +34,33 @@ git checkout release/1.22
|
||||
yarn --cwd test/smoke
|
||||
```
|
||||
|
||||
#### Electron
|
||||
|
||||
In addition to the new build to be released you will need the previous stable build so that the smoketest can test the data migration.
|
||||
The recommended way to make these builds available for the smoketest is by downloading their archive version (\*.zip) and extracting
|
||||
them into two folders. Pass the folder paths to the smoketest as follows:
|
||||
|
||||
```bash
|
||||
yarn smoketest --build PATH_TO_NEW_RELEASE_PARENT_FOLDER --stable-build PATH_TO_LAST_STABLE_RELEASE_PARENT_FOLDER
|
||||
yarn smoketest --build <path latest built version> --stable-build <path to previous stable version>
|
||||
```
|
||||
|
||||
#### Web
|
||||
|
||||
**macOS**: if you have downloaded the server with web bits, make sure to run the following command before unzipping it to avoid security issues on startup:
|
||||
|
||||
```bash
|
||||
xattr -d com.apple.quarantine <path to server with web folder zip>
|
||||
```
|
||||
|
||||
There is no support for testing an old version to a new one yet, so simply configure the `--build` command line argument to point to
|
||||
the web server folder which includes the web client bits (e.g. `vscode-server-darwin-web` for macOS).
|
||||
|
||||
**Note**: make sure to point to the server that includes the client bits!
|
||||
|
||||
### Debug
|
||||
|
||||
- `--verbose` logs all the low level driver calls made to Code;
|
||||
- `-f PATTERN` filters the tests to be run. You can also use pretty much any mocha argument;
|
||||
- `-f PATTERN` (alias `-g PATTERN`) filters the tests to be run. You can also use pretty much any mocha argument;
|
||||
- `--screenshots SCREENSHOT_DIR` captures screenshots when tests fail.
|
||||
|
||||
### Develop
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"rimraf": "^2.6.1",
|
||||
"strip-json-comments": "^2.0.1",
|
||||
"tmp": "0.0.33",
|
||||
"typescript": "2.9.2",
|
||||
"typescript": "3.7.5",
|
||||
"watch": "^1.0.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,9 +28,6 @@ export function setup() {
|
||||
});
|
||||
|
||||
it('verifies that warning becomes an error once setting changed', async function () {
|
||||
// settings might take a while to update?
|
||||
this.timeout(40000);
|
||||
|
||||
const app = this.app as Application;
|
||||
await app.workbench.settingsEditor.addUserSetting('css.lint.emptyRules', '"error"');
|
||||
await app.workbench.quickopen.openFile('style.css');
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import * as http from 'http';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as stripJsonComments from 'strip-json-comments';
|
||||
import { Application } from '../../../../automation';
|
||||
|
||||
export function setup() {
|
||||
describe('Debug', () => {
|
||||
it('configure launch json', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.openDebugViewlet();
|
||||
await app.workbench.quickopen.openFile('app.js');
|
||||
await app.workbench.quickopen.runCommand('Debug: Open launch.json');
|
||||
|
||||
const launchJsonPath = path.join(app.workspacePathOrFolder, '.vscode', 'launch.json');
|
||||
const content = fs.readFileSync(launchJsonPath, 'utf8');
|
||||
const config = JSON.parse(stripJsonComments(content));
|
||||
config.configurations[0].protocol = 'inspector';
|
||||
fs.writeFileSync(launchJsonPath, JSON.stringify(config, undefined, 4), 'utf8');
|
||||
|
||||
// force load from disk since file events are sometimes missing
|
||||
await app.workbench.quickopen.runCommand('File: Revert File');
|
||||
await app.workbench.editor.waitForEditorContents('launch.json', contents => /"protocol": "inspector"/.test(contents));
|
||||
|
||||
assert.equal(config.configurations[0].request, 'launch');
|
||||
assert.equal(config.configurations[0].type, 'node');
|
||||
if (process.platform === 'win32') {
|
||||
assert.equal(config.configurations[0].program, '${workspaceFolder}\\bin\\www');
|
||||
} else {
|
||||
assert.equal(config.configurations[0].program, '${workspaceFolder}/bin/www');
|
||||
}
|
||||
});
|
||||
|
||||
it('breakpoints', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.quickopen.openFile('index.js');
|
||||
await app.workbench.debug.setBreakpointOnLine(6);
|
||||
});
|
||||
|
||||
let port: number;
|
||||
it('start debugging', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
port = await app.workbench.debug.startDebugging();
|
||||
|
||||
await new Promise((c, e) => {
|
||||
const request = http.get(`http://localhost:${port}`);
|
||||
request.on('error', e);
|
||||
app.workbench.debug.waitForStackFrame(sf => /index\.js$/.test(sf.name) && sf.lineNumber === 6, 'looking for index.js and line 6').then(c, e);
|
||||
});
|
||||
});
|
||||
|
||||
it('focus stack frames and variables', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.waitForVariableCount(4, 5);
|
||||
|
||||
await app.workbench.debug.focusStackFrame('layer.js', 'looking for layer.js');
|
||||
await app.workbench.debug.waitForVariableCount(5, 6);
|
||||
|
||||
await app.workbench.debug.focusStackFrame('route.js', 'looking for route.js');
|
||||
await app.workbench.debug.waitForVariableCount(3, 4);
|
||||
|
||||
await app.workbench.debug.focusStackFrame('index.js', 'looking for index.js');
|
||||
await app.workbench.debug.waitForVariableCount(4, 5);
|
||||
});
|
||||
|
||||
it('stepOver, stepIn, stepOut', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.stepIn();
|
||||
|
||||
const first = await app.workbench.debug.waitForStackFrame(sf => /response\.js$/.test(sf.name), 'looking for response.js');
|
||||
await app.workbench.debug.stepOver();
|
||||
|
||||
await app.workbench.debug.waitForStackFrame(sf => /response\.js$/.test(sf.name) && sf.lineNumber === first.lineNumber + 1, `looking for response.js and line ${first.lineNumber + 1}`);
|
||||
await app.workbench.debug.stepOut();
|
||||
|
||||
await app.workbench.debug.waitForStackFrame(sf => /index\.js$/.test(sf.name) && sf.lineNumber === 7, `looking for index.js and line 7`);
|
||||
});
|
||||
|
||||
it('continue', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.continue();
|
||||
|
||||
await new Promise((c, e) => {
|
||||
const request = http.get(`http://localhost:${port}`);
|
||||
request.on('error', e);
|
||||
app.workbench.debug.waitForStackFrame(sf => /index\.js$/.test(sf.name) && sf.lineNumber === 6, `looking for index.js and line 6`).then(c, e);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it('debug console', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.waitForReplCommand('2 + 2', r => r === '4');
|
||||
});
|
||||
|
||||
it('debug console link', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.waitForReplCommand('"./app.js:5:1"', r => r.includes('app.js'));
|
||||
await app.workbench.debug.waitForLink();
|
||||
});
|
||||
|
||||
it('stop debugging', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.debug.stopDebugging();
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as cp from 'child_process';
|
||||
import { Application } from '../../../../automation';
|
||||
|
||||
const DIFF_EDITOR_LINE_INSERT = '.monaco-diff-editor .editor.modified .line-insert';
|
||||
const SYNC_STATUSBAR = 'div[id="workbench.parts.statusbar"] .statusbar-item[title$="Synchronize Changes"]';
|
||||
|
||||
export function setup() {
|
||||
describe('Git', () => {
|
||||
before(async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
cp.execSync('git config user.name testuser', { cwd: app.workspacePathOrFolder });
|
||||
cp.execSync('git config user.email monacotools@microsoft.com', { cwd: app.workspacePathOrFolder });
|
||||
});
|
||||
|
||||
it('reflects working tree changes', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.scm.openSCMViewlet();
|
||||
|
||||
await app.workbench.quickopen.openFile('app.js');
|
||||
await app.workbench.editor.waitForTypeInEditor('app.js', '.foo{}');
|
||||
await app.workbench.editors.saveOpenedFile();
|
||||
|
||||
await app.workbench.quickopen.openFile('index.pug');
|
||||
await app.workbench.editor.waitForTypeInEditor('index.pug', 'hello world');
|
||||
await app.workbench.editors.saveOpenedFile();
|
||||
|
||||
await app.workbench.scm.refreshSCMViewlet();
|
||||
await app.workbench.scm.waitForChange('app.js', 'Modified');
|
||||
await app.workbench.scm.waitForChange('index.pug', 'Modified');
|
||||
});
|
||||
|
||||
it('opens diff editor', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.scm.openSCMViewlet();
|
||||
await app.workbench.scm.openChange('app.js');
|
||||
await app.code.waitForElement(DIFF_EDITOR_LINE_INSERT);
|
||||
});
|
||||
|
||||
it('stages correctly', async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.scm.openSCMViewlet();
|
||||
await app.workbench.scm.waitForChange('app.js', 'Modified');
|
||||
|
||||
await app.workbench.scm.stage('app.js');
|
||||
await app.workbench.scm.openChange('app.js');
|
||||
await new Promise(c => setTimeout(c, 1000));
|
||||
await app.workbench.scm.unstage('app.js');
|
||||
});
|
||||
|
||||
it(`stages, commits changes and verifies outgoing change`, async function () {
|
||||
const app = this.app as Application;
|
||||
|
||||
await app.workbench.scm.openSCMViewlet();
|
||||
await app.workbench.scm.waitForChange('app.js', 'Modified');
|
||||
|
||||
await app.workbench.scm.openChange('app.js');
|
||||
await app.workbench.scm.stage('app.js');
|
||||
|
||||
await app.workbench.scm.commit('first commit');
|
||||
await app.code.waitForTextContent(SYNC_STATUSBAR, ' 0↓ 1↑');
|
||||
|
||||
await app.workbench.quickopen.runCommand('Git: Stage All Changes');
|
||||
await app.workbench.scm.waitForChange('index.pug', 'Index Modified');
|
||||
|
||||
await app.workbench.scm.commit('second commit');
|
||||
await app.code.waitForTextContent(SYNC_STATUSBAR, ' 0↓ 2↑');
|
||||
|
||||
cp.execSync('git reset --hard origin/master', { cwd: app.workspacePathOrFolder });
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -12,7 +12,7 @@ export function setup() {
|
||||
await app.workbench.editors.newUntitledFile();
|
||||
|
||||
const untitled = 'Untitled-1';
|
||||
const textToTypeInUntitled = 'Hello, Untitled Code';
|
||||
const textToTypeInUntitled = 'Hello from Untitled';
|
||||
await app.workbench.editor.waitForTypeInEditor(untitled, textToTypeInUntitled);
|
||||
|
||||
const readmeMd = 'readme.md';
|
||||
@@ -25,8 +25,8 @@ export function setup() {
|
||||
await app.workbench.editors.waitForActiveTab(readmeMd, true);
|
||||
await app.workbench.editor.waitForEditorContents(readmeMd, c => c.indexOf(textToType) > -1);
|
||||
|
||||
await app.workbench.editors.waitForTab(untitled, true);
|
||||
await app.workbench.editors.selectTab(untitled, true);
|
||||
await app.workbench.editors.waitForTab(untitled);
|
||||
await app.workbench.editors.selectTab(untitled);
|
||||
await app.workbench.editor.waitForEditorContents(untitled, c => c.indexOf(textToTypeInUntitled) > -1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import { join } from 'path';
|
||||
|
||||
export function setup(stableCodePath: string, testDataPath: string) {
|
||||
|
||||
|
||||
describe('Data Migration: This test MUST run before releasing by providing the --stable-build command line argument', () => {
|
||||
it(`verifies opened editors are restored`, async function () {
|
||||
if (!stableCodePath) {
|
||||
@@ -66,7 +65,7 @@ export function setup(stableCodePath: string, testDataPath: string) {
|
||||
await stableApp.workbench.editors.newUntitledFile();
|
||||
|
||||
const untitled = 'Untitled-1';
|
||||
const textToTypeInUntitled = 'Hello, Untitled Code';
|
||||
const textToTypeInUntitled = 'Hello from Untitled';
|
||||
await stableApp.workbench.editor.waitForTypeInEditor(untitled, textToTypeInUntitled);
|
||||
|
||||
const readmeMd = 'readme.md';
|
||||
@@ -86,7 +85,7 @@ export function setup(stableCodePath: string, testDataPath: string) {
|
||||
await insidersApp.workbench.editor.waitForEditorContents(readmeMd, c => c.indexOf(textToType) > -1);
|
||||
|
||||
await insidersApp.workbench.editors.waitForTab(untitled, true);
|
||||
await insidersApp.workbench.editors.selectTab(untitled, true);
|
||||
await insidersApp.workbench.editors.selectTab(untitled);
|
||||
await insidersApp.workbench.editor.waitForEditorContents(untitled, c => c.indexOf(textToTypeInUntitled) > -1);
|
||||
|
||||
await insidersApp.stop();
|
||||
|
||||
@@ -34,8 +34,6 @@ import { setup as setupDataPreferencesTests } from './areas/preferences/preferen
|
||||
import { setup as setupDataSearchTests } from './areas/search/search.test';
|
||||
import { setup as setupDataCSSTests } from './areas/css/css.test';
|
||||
import { setup as setupDataEditorTests } from './areas/editor/editor.test';
|
||||
import { setup as setupDataDebugTests } from './areas/debug/debug.test';
|
||||
import { setup as setupDataGitTests } from './areas/git/git.test';
|
||||
import { setup as setupDataStatusbarTests } from './areas/statusbar/statusbar.test';
|
||||
import { setup as setupDataExtensionTests } from './areas/extensions/extensions.test';
|
||||
import { setup as setupTerminalTests } from './areas/terminal/terminal.test';
|
||||
@@ -43,8 +41,8 @@ import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.te
|
||||
import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test';
|
||||
import { setup as setupLaunchTests } from './areas/workbench/launch.test';*///{{END}}
|
||||
|
||||
if (!/^v10/.test(process.version)) {
|
||||
console.error('Error: Smoketest must be run using Node 10. Currently running', process.version);
|
||||
if (!/^v10/.test(process.version) && !/^v12/.test(process.version)) {
|
||||
console.error('Error: Smoketest must be run using Node 10/12. Currently running', process.version);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -55,6 +53,7 @@ process.once('exit', () => rimraf.sync(testDataPath));
|
||||
const [, , ...args] = process.argv;
|
||||
const opts = minimist(args, {
|
||||
string: [
|
||||
'browser',
|
||||
'build',
|
||||
'stable-build',
|
||||
'wait-time',
|
||||
@@ -66,7 +65,8 @@ const opts = minimist(args, {
|
||||
'verbose',
|
||||
'remote',
|
||||
'web',
|
||||
'headless'
|
||||
'headless',
|
||||
'ci'
|
||||
],
|
||||
default: {
|
||||
verbose: false
|
||||
@@ -79,7 +79,6 @@ const extensionsPath = path.join(testDataPath, 'extensions-dir');
|
||||
mkdirp.sync(extensionsPath);
|
||||
|
||||
const screenshotsPath = opts.screenshots ? path.resolve(opts.screenshots) : null;
|
||||
|
||||
if (screenshotsPath) {
|
||||
mkdirp.sync(screenshotsPath);
|
||||
}
|
||||
@@ -89,83 +88,109 @@ function fail(errorMessage): void {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (parseInt(process.version.substr(1)) < 6) {
|
||||
fail('Please update your Node version to greater than 6 to run the smoke test.');
|
||||
}
|
||||
|
||||
const repoPath = path.join(__dirname, '..', '..', '..');
|
||||
|
||||
function getDevElectronPath(): string {
|
||||
const buildPath = path.join(repoPath, '.build');
|
||||
const product = require(path.join(repoPath, 'product.json'));
|
||||
let quality: Quality;
|
||||
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return path.join(buildPath, 'electron', `${product.nameLong}.app`, 'Contents', 'MacOS', 'Electron');
|
||||
case 'linux':
|
||||
return path.join(buildPath, 'electron', `${product.applicationName}`);
|
||||
case 'win32':
|
||||
return path.join(buildPath, 'electron', `${product.nameShort}.exe`);
|
||||
default:
|
||||
throw new Error('Unsupported platform.');
|
||||
}
|
||||
}
|
||||
//
|
||||
// #### Electron Smoke Tests ####
|
||||
//
|
||||
if (!opts.web) {
|
||||
|
||||
function getBuildElectronPath(root: string): string {
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return path.join(root, 'Contents', 'MacOS', 'Electron');
|
||||
case 'linux': {
|
||||
const product = require(path.join(root, 'resources', 'app', 'product.json'));
|
||||
return path.join(root, product.applicationName);
|
||||
function getDevElectronPath(): string {
|
||||
const buildPath = path.join(repoPath, '.build');
|
||||
const product = require(path.join(repoPath, 'product.json'));
|
||||
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return path.join(buildPath, 'electron', `${product.nameLong}.app`, 'Contents', 'MacOS', 'Electron');
|
||||
case 'linux':
|
||||
return path.join(buildPath, 'electron', `${product.applicationName}`);
|
||||
case 'win32':
|
||||
return path.join(buildPath, 'electron', `${product.nameShort}.exe`);
|
||||
default:
|
||||
throw new Error('Unsupported platform.');
|
||||
}
|
||||
case 'win32': {
|
||||
const product = require(path.join(root, 'resources', 'app', 'product.json'));
|
||||
return path.join(root, `${product.nameShort}.exe`);
|
||||
}
|
||||
|
||||
function getBuildElectronPath(root: string): string {
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
return path.join(root, 'Contents', 'MacOS', 'Electron');
|
||||
case 'linux': {
|
||||
const product = require(path.join(root, 'resources', 'app', 'product.json'));
|
||||
return path.join(root, product.applicationName);
|
||||
}
|
||||
case 'win32': {
|
||||
const product = require(path.join(root, 'resources', 'app', 'product.json'));
|
||||
return path.join(root, `${product.nameShort}.exe`);
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported platform.');
|
||||
}
|
||||
default:
|
||||
throw new Error('Unsupported platform.');
|
||||
}
|
||||
|
||||
let testCodePath = opts.build;
|
||||
let stableCodePath = opts['stable-build'];
|
||||
let electronPath: string;
|
||||
let stablePath: string | undefined = undefined;
|
||||
|
||||
if (testCodePath) {
|
||||
electronPath = getBuildElectronPath(testCodePath);
|
||||
|
||||
if (stableCodePath) {
|
||||
stablePath = getBuildElectronPath(stableCodePath);
|
||||
}
|
||||
} else {
|
||||
testCodePath = getDevElectronPath();
|
||||
electronPath = testCodePath;
|
||||
process.env.VSCODE_REPOSITORY = repoPath;
|
||||
process.env.VSCODE_DEV = '1';
|
||||
process.env.VSCODE_CLI = '1';
|
||||
}
|
||||
|
||||
if (!fs.existsSync(electronPath || '')) {
|
||||
fail(`Can't find VSCode at ${electronPath}.`);
|
||||
}
|
||||
|
||||
if (typeof stablePath === 'string' && !fs.existsSync(stablePath)) {
|
||||
fail(`Can't find Stable VSCode at ${stablePath}.`);
|
||||
}
|
||||
|
||||
if (process.env.VSCODE_DEV === '1') {
|
||||
quality = Quality.Dev;
|
||||
} else if (electronPath.indexOf('Code - Insiders') >= 0 /* macOS/Windows */ || electronPath.indexOf('code-insiders') /* Linux */ >= 0) {
|
||||
quality = Quality.Insiders;
|
||||
} else {
|
||||
quality = Quality.Stable;
|
||||
}
|
||||
}
|
||||
|
||||
let testCodePath = opts.build;
|
||||
let stableCodePath = opts['stable-build'];
|
||||
let electronPath: string;
|
||||
let stablePath: string | undefined = undefined;
|
||||
//
|
||||
// #### Web Smoke Tests ####
|
||||
//
|
||||
else {
|
||||
const testCodeServerPath = opts.build || process.env.VSCODE_REMOTE_SERVER_PATH;
|
||||
|
||||
if (testCodePath) {
|
||||
electronPath = getBuildElectronPath(testCodePath);
|
||||
|
||||
if (stableCodePath) {
|
||||
stablePath = getBuildElectronPath(stableCodePath);
|
||||
if (typeof testCodeServerPath === 'string' && !fs.existsSync(testCodeServerPath)) {
|
||||
fail(`Can't find Code server at ${testCodeServerPath}.`);
|
||||
}
|
||||
} else {
|
||||
testCodePath = getDevElectronPath();
|
||||
electronPath = testCodePath;
|
||||
process.env.VSCODE_REPOSITORY = repoPath;
|
||||
process.env.VSCODE_DEV = '1';
|
||||
process.env.VSCODE_CLI = '1';
|
||||
}
|
||||
|
||||
if (!opts.web && !fs.existsSync(electronPath || '')) {
|
||||
fail(`Can't find Code at ${electronPath}.`);
|
||||
}
|
||||
if (!testCodeServerPath) {
|
||||
process.env.VSCODE_REPOSITORY = repoPath;
|
||||
process.env.VSCODE_DEV = '1';
|
||||
process.env.VSCODE_CLI = '1';
|
||||
}
|
||||
|
||||
if (typeof stablePath === 'string' && !fs.existsSync(stablePath)) {
|
||||
fail(`Can't find Stable Code at ${stablePath}.`);
|
||||
if (process.env.VSCODE_DEV === '1') {
|
||||
quality = Quality.Dev;
|
||||
} else {
|
||||
quality = Quality.Insiders;
|
||||
}
|
||||
}
|
||||
|
||||
const userDataDir = path.join(testDataPath, 'd');
|
||||
|
||||
let quality: Quality;
|
||||
if (process.env.VSCODE_DEV === '1') {
|
||||
quality = Quality.Dev;
|
||||
} else if (electronPath.indexOf('Code - Insiders') >= 0 /* macOS/Windows */ || electronPath.indexOf('code-insiders') /* Linux */ >= 0) {
|
||||
quality = Quality.Insiders;
|
||||
} else {
|
||||
quality = Quality.Stable;
|
||||
}
|
||||
|
||||
async function setupRepository(): Promise<void> {
|
||||
if (opts['test-repo']) {
|
||||
console.log('*** Copying test project repository:', opts['test-repo']);
|
||||
@@ -228,13 +253,13 @@ function createOptions(): ApplicationOptions {
|
||||
screenshotsPath,
|
||||
remote: opts.remote,
|
||||
web: opts.web,
|
||||
browser: opts.browser,
|
||||
headless: opts.headless
|
||||
};
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
// allow two minutes for setup
|
||||
this.timeout(2 * 60 * 1000);
|
||||
this.timeout(2 * 60 * 1000); // allow two minutes for setup
|
||||
await setup();
|
||||
this.defaultOptions = createOptions();
|
||||
});
|
||||
@@ -250,12 +275,8 @@ after(async function () {
|
||||
|
||||
await new Promise((c, e) => rimraf(testDataPath, { maxBusyTries: 10 }, err => err ? e(err) : c()));
|
||||
});
|
||||
/*//{{SQL CARBON EDIT}}
|
||||
if (!opts.web) {
|
||||
setupDataMigrationTests(stableCodePath, testDataPath);
|
||||
}*/
|
||||
|
||||
describe('Running Code', () => {
|
||||
describe(`VSCode Smoke Tests (${opts.web ? 'Web' : 'Electron'})`, () => {
|
||||
before(async function () {
|
||||
const app = new Application(this.defaultOptions);
|
||||
await app!.start(opts.web ? false : undefined);
|
||||
@@ -300,27 +321,29 @@ describe('Running Code', () => {
|
||||
app.logger.log('*** Test start:', title);
|
||||
});
|
||||
}
|
||||
//{{SQL CARBON EDIT}}
|
||||
runProfilerTests();
|
||||
runQueryEditorTests();
|
||||
/*
|
||||
if (!opts.web) { setupDataLossTests(); }
|
||||
setupDataExplorerTests();
|
||||
if (!opts.web) { setupDataPreferencesTests(); }
|
||||
setupDataSearchTests();
|
||||
setupDataCSSTests();
|
||||
setupDataEditorTests();
|
||||
if (!opts.web) { setupDataDebugTests(); }
|
||||
setupDataGitTests();
|
||||
setupDataStatusbarTests(!!opts.web);
|
||||
setupDataExtensionTests();
|
||||
setupTerminalTests();
|
||||
if (!opts.web) { setupDataMultirootTests(); }
|
||||
setupDataLocalizationTests();
|
||||
*/
|
||||
//{{END}}
|
||||
|
||||
// CI only tests (must be reliable)
|
||||
if (opts.ci) {
|
||||
// TODO@Ben figure out tests that can run continously and reliably
|
||||
}
|
||||
|
||||
// Non-CI execution (all tests)
|
||||
else {
|
||||
/*if (!opts.web) { setupDataMigrationTests(opts['stable-build'], testDataPath); } {{SQL CARBON EDIT}} comment out tests
|
||||
if (!opts.web) { setupDataLossTests(); }
|
||||
setupDataExplorerTests();
|
||||
if (!opts.web) { setupDataPreferencesTests(); }
|
||||
setupDataSearchTests();
|
||||
setupDataCSSTests();
|
||||
setupDataEditorTests();
|
||||
setupDataStatusbarTests(!!opts.web);
|
||||
if (!opts.web) { setupDataExtensionTests(); }
|
||||
setupTerminalTests();
|
||||
if (!opts.web) { setupDataMultirootTests(); }
|
||||
if (!opts.web) { setupDataLocalizationTests(); }
|
||||
if (!opts.web) { setupLaunchTests(); }*/
|
||||
|
||||
runProfilerTests(); // {{SQL CARBON EDIT}} add our tests
|
||||
runQueryEditorTests(); // {{SQL CARBON EDIT}} add our tests
|
||||
}
|
||||
});
|
||||
/*//{{SQL CARBON EDIT}}
|
||||
if (!opts.web) {
|
||||
setupLaunchTests();
|
||||
}*/
|
||||
|
||||
@@ -11,18 +11,14 @@ const suite = 'Smoke Tests';
|
||||
|
||||
const [, , ...args] = process.argv;
|
||||
const opts = minimist(args, {
|
||||
string: [
|
||||
'f'
|
||||
]
|
||||
string: ['f', 'g']
|
||||
});
|
||||
|
||||
const options = {
|
||||
useColors: true,
|
||||
//{{SQL CARBON EDIT}}
|
||||
timeout: 60000 * 2,
|
||||
//{{END}}
|
||||
color: true,
|
||||
timeout: 60000,
|
||||
slow: 30000,
|
||||
grep: opts['f']
|
||||
grep: opts['f'] || opts['g']
|
||||
};
|
||||
|
||||
if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
|
||||
@@ -38,4 +34,4 @@ if (process.env.BUILD_ARTIFACTSTAGINGDIRECTORY) {
|
||||
|
||||
const mocha = new Mocha(options);
|
||||
mocha.addFile('out/main.js');
|
||||
mocha.run(failures => process.exit(failures ? -1 : 0));
|
||||
mocha.run(failures => process.exit(failures ? -1 : 0));
|
||||
|
||||
@@ -2122,10 +2122,10 @@ tree-kill@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36"
|
||||
integrity sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==
|
||||
|
||||
typescript@2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c"
|
||||
integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==
|
||||
typescript@3.7.5:
|
||||
version "3.7.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.5.tgz#0692e21f65fd4108b9330238aac11dd2e177a1ae"
|
||||
integrity sha512-/P5lkRXkWHNAbcJIiHPfRoKqyd7bsyCma1hZNUGfn20qm64T6ZBlrzprymeu918H+mB/0rIg2gGK/BXkhhYgBw==
|
||||
|
||||
union-value@^1.0.0:
|
||||
version "1.0.1"
|
||||
|
||||
49
test/unit/README.md
Normal file
49
test/unit/README.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Unit Tests
|
||||
|
||||
## Run (inside Electron)
|
||||
|
||||
The best way to run the unit tests is from the terminal. To make development changes to unit tests you need to be running `yarn watch`. See [Development Workflow](https://github.com/Microsoft/vscode/wiki/How-to-Contribute#incremental-build) for more details. From the `vscode` folder run:
|
||||
|
||||
**OS X and Linux**
|
||||
|
||||
./scripts/test.sh
|
||||
|
||||
**Windows**
|
||||
|
||||
scripts\test
|
||||
|
||||
|
||||
## Run (inside browser)
|
||||
|
||||
You can run tests inside a browser instance too:
|
||||
|
||||
**OS X and Linux**
|
||||
|
||||
node test/unit/browser/index.js
|
||||
|
||||
**Windows**
|
||||
|
||||
node test\unit\browser\index.js
|
||||
|
||||
|
||||
## Run (with node)
|
||||
|
||||
yarn run mocha --run src/vs/editor/test/browser/controller/cursor.test.ts
|
||||
|
||||
## Debug
|
||||
|
||||
To debug tests use `--debug` when running the test script. Also, the set of tests can be reduced with the `--run` and `--runGlob` flags. Both require a file path/pattern. Like so:
|
||||
|
||||
./scripts/test.sh --debug --runGrep **/extHost*.test.js
|
||||
|
||||
## Coverage
|
||||
|
||||
The following command will create a `coverage` folder at the root of the workspace:
|
||||
|
||||
**OS X and Linux**
|
||||
|
||||
./scripts/test.sh --coverage
|
||||
|
||||
**Windows**
|
||||
|
||||
scripts\test --coverage
|
||||
@@ -273,25 +273,24 @@ assert.notEqual = function notEqual(actual, expected, message) {
|
||||
// assert.deepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.deepEqual = function deepEqual(actual, expected, message) {
|
||||
if (!_deepEqual(actual, expected)) {
|
||||
if (!_deepEqual(actual, expected, false)) {
|
||||
fail(actual, expected, message, 'deepEqual', assert.deepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function _deepEqual(actual, expected) {
|
||||
assert.deepStrictEqual = function deepStrictEqual(actual, expected, message) {
|
||||
if (!_deepEqual(actual, expected, true)) {
|
||||
fail(actual, expected, message, 'deepStrictEqual', assert.deepStrictEqual);
|
||||
}
|
||||
};
|
||||
|
||||
function _deepEqual(actual, expected, strict) {
|
||||
// 7.1. All identical values are equivalent, as determined by ===.
|
||||
if (actual === expected) {
|
||||
return true;
|
||||
// } else if (actual instanceof Buffer && expected instanceof Buffer) {
|
||||
// return compare(actual, expected) === 0;
|
||||
|
||||
// } else if (util.isBuffer(actual) && util.isBuffer(expected)) {
|
||||
// if (actual.length != expected.length) return false;
|
||||
//
|
||||
// for (var i = 0; i < actual.length; i++) {
|
||||
// if (actual[i] !== expected[i]) return false;
|
||||
// }
|
||||
//
|
||||
// return true;
|
||||
//
|
||||
// 7.2. If the expected value is a Date object, the actual value is
|
||||
// equivalent if it is also a Date object that refers to the same time.
|
||||
} else if (util.isDate(actual) && util.isDate(expected)) {
|
||||
@@ -309,8 +308,9 @@ function _deepEqual(actual, expected) {
|
||||
|
||||
// 7.4. Other pairs that do not both pass typeof value == 'object',
|
||||
// equivalence is determined by ==.
|
||||
} else if (!util.isObject(actual) && !util.isObject(expected)) {
|
||||
return actual == expected;
|
||||
} else if ((actual === null || typeof actual !== 'object') &&
|
||||
(expected === null || typeof expected !== 'object')) {
|
||||
return strict ? actual === expected : actual == expected;
|
||||
|
||||
// 7.5 For all other Object pairs, including Array objects, equivalence is
|
||||
// determined by having the same number of owned properties (as verified
|
||||
@@ -319,32 +319,22 @@ function _deepEqual(actual, expected) {
|
||||
// corresponding key, and an identical 'prototype' property. Note: this
|
||||
// accounts for both named and indexed properties on Arrays.
|
||||
} else {
|
||||
return objEquiv(actual, expected);
|
||||
return objEquiv(actual, expected, strict);
|
||||
}
|
||||
}
|
||||
|
||||
var isArguments = function(object) {
|
||||
function isArguments(object) {
|
||||
return Object.prototype.toString.call(object) == '[object Arguments]';
|
||||
};
|
||||
}
|
||||
|
||||
(function() {
|
||||
if (!isArguments(arguments)) {
|
||||
isArguments = function(object) {
|
||||
return object != null &&
|
||||
typeof object === 'object' &&
|
||||
typeof object.callee === 'function' &&
|
||||
typeof object.length === 'number' || false;
|
||||
};
|
||||
}
|
||||
})();
|
||||
|
||||
function objEquiv(a, b) {
|
||||
if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b))
|
||||
function objEquiv(a, b, strict) {
|
||||
if (a === null || a === undefined || b === null || b === undefined)
|
||||
return false;
|
||||
// if one is a primitive, the other must be same
|
||||
if (util.isPrimitive(a) || util.isPrimitive(b))
|
||||
return a === b;
|
||||
if (strict && Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
|
||||
return false;
|
||||
// an identical 'prototype' property.
|
||||
if (a.prototype !== b.prototype) return false;
|
||||
//~~~I've managed to break Object.keys through screwy arguments passing.
|
||||
// Converting to array solves the problem.
|
||||
var aIsArgs = isArguments(a),
|
||||
bIsArgs = isArguments(b);
|
||||
if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs))
|
||||
@@ -352,32 +342,28 @@ function objEquiv(a, b) {
|
||||
if (aIsArgs) {
|
||||
a = pSlice.call(a);
|
||||
b = pSlice.call(b);
|
||||
return _deepEqual(a, b);
|
||||
}
|
||||
try {
|
||||
var ka = Object_keys(a),
|
||||
kb = Object_keys(b),
|
||||
key, i;
|
||||
} catch (e) {//happens when one is a string literal and the other isn't
|
||||
return false;
|
||||
return _deepEqual(a, b, strict);
|
||||
}
|
||||
var ka = Object.keys(a),
|
||||
kb = Object.keys(b),
|
||||
key, i;
|
||||
// having the same number of owned properties (keys incorporates
|
||||
// hasOwnProperty)
|
||||
if (ka.length != kb.length)
|
||||
if (ka.length !== kb.length)
|
||||
return false;
|
||||
//the same set of keys (although not necessarily the same order),
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
//~~~cheap key test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
if (ka[i] != kb[i])
|
||||
if (ka[i] !== kb[i])
|
||||
return false;
|
||||
}
|
||||
//equivalent values for every corresponding key, and
|
||||
//~~~possibly expensive deep test
|
||||
for (i = ka.length - 1; i >= 0; i--) {
|
||||
key = ka[i];
|
||||
if (!_deepEqual(a[key], b[key])) return false;
|
||||
if (!_deepEqual(a[key], b[key], strict)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -386,11 +372,19 @@ function objEquiv(a, b) {
|
||||
// assert.notDeepEqual(actual, expected, message_opt);
|
||||
|
||||
assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
|
||||
if (_deepEqual(actual, expected)) {
|
||||
if (_deepEqual(actual, expected, false)) {
|
||||
fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
|
||||
}
|
||||
};
|
||||
|
||||
assert.notDeepStrictEqual = notDeepStrictEqual;
|
||||
function notDeepStrictEqual(actual, expected, message) {
|
||||
if (_deepEqual(actual, expected, true)) {
|
||||
fail(actual, expected, message, 'notDeepStrictEqual', notDeepStrictEqual);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 9. The strict equality assertion tests strict equality, as determined by ===.
|
||||
// assert.strictEqual(actual, expected, message_opt);
|
||||
|
||||
@@ -428,7 +422,11 @@ function expectedException(actual, expected) {
|
||||
function _throws(shouldThrow, block, expected, message) {
|
||||
var actual;
|
||||
|
||||
if (util.isString(expected)) {
|
||||
if (typeof block !== 'function') {
|
||||
throw new TypeError('block must be a function');
|
||||
}
|
||||
|
||||
if (typeof expected === 'string') {
|
||||
message = expected;
|
||||
expected = null;
|
||||
}
|
||||
@@ -469,6 +467,5 @@ assert.doesNotThrow = function(block, /*optional*/message) {
|
||||
};
|
||||
|
||||
assert.ifError = function(err) { if (err) {throw err;}};
|
||||
|
||||
return assert;
|
||||
});
|
||||
244
test/unit/browser/index.js
Normal file
244
test/unit/browser/index.js
Normal file
@@ -0,0 +1,244 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. 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 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'])
|
||||
.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 () {
|
||||
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-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 browser = await playwright[browserType].launch({ headless: !Boolean(argv.debug) });
|
||||
const page = (await browser.defaultContext().pages())[0]
|
||||
const target = url.pathToFileURL(path.join(__dirname, 'renderer.html'));
|
||||
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(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-ignore
|
||||
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);
|
||||
});
|
||||
140
test/unit/browser/renderer.html
Normal file
140
test/unit/browser/renderer.html
Normal file
@@ -0,0 +1,140 @@
|
||||
<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>
|
||||
|
||||
<script src="../../../out/vs/loader.js"></script>
|
||||
<script>
|
||||
// configure loader
|
||||
const baseUrl = window.location.href;
|
||||
require.config({
|
||||
catchError: true,
|
||||
baseUrl: new URL('../../../src', baseUrl).href,
|
||||
paths: {
|
||||
'vs': new URL('../../../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
|
||||
}
|
||||
});
|
||||
</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>
|
||||
@@ -12,7 +12,7 @@ const iLibSourceMaps = require('istanbul-lib-source-maps');
|
||||
const iLibReport = require('istanbul-lib-report');
|
||||
const iReports = require('istanbul-reports');
|
||||
|
||||
const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '..'));
|
||||
const REPO_PATH = toUpperDriveLetter(path.join(__dirname, '../../'));
|
||||
|
||||
exports.initialize = function (loaderConfig) {
|
||||
const instrumenter = iLibInstrument.createInstrumenter();
|
||||
@@ -48,7 +48,7 @@ exports.createReport = function (isSingle) {
|
||||
transformed.data = newData;
|
||||
|
||||
const context = iLibReport.createContext({
|
||||
dir: path.join(__dirname, `../.build/coverage${isSingle ? '-single' : ''}`),
|
||||
dir: path.join(REPO_PATH, `.build/coverage${isSingle ? '-single' : ''}`),
|
||||
coverageMap: transformed
|
||||
});
|
||||
const tree = context.getTree('flat');
|
||||
@@ -18,7 +18,7 @@ const optimist = require('optimist')
|
||||
.describe('grep', 'only run tests matching <pattern>').alias('grep', 'g').alias('grep', 'f').string('grep')
|
||||
.describe('invert', 'uses the inverse of the match specified by grep').alias('invert', 'i').string('invert')
|
||||
.describe('run', 'only run tests from <file>').string('run')
|
||||
.describe('runGlob', 'only run tests matching <file_pattern>').alias('runGlob', 'runGrep').string('runGlob')
|
||||
.describe('runGlob', 'only run tests matching <file_pattern>').alias('runGlob', 'glob').alias('runGlob', 'runGrep').string('runGlob')
|
||||
.describe('build', 'run with build output (out-build)').boolean('build')
|
||||
.describe('coverage', 'generate coverage report').boolean('coverage')
|
||||
.describe('debug', 'open dev tools, keep window open, reuse app data').string('debug')
|
||||
@@ -3,12 +3,12 @@
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>VSCode Tests</title>
|
||||
<link href="../../node_modules/mocha/mocha.css" rel="stylesheet" />
|
||||
<link href="../../../node_modules/mocha/mocha.css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="mocha"></div>
|
||||
<script src="../../node_modules/mocha/mocha.js"></script>
|
||||
<script src="../../../node_modules/mocha/mocha.js"></script>
|
||||
|
||||
<script>
|
||||
|
||||
@@ -10,7 +10,7 @@ const assert = require('assert');
|
||||
const path = require('path');
|
||||
const glob = require('glob');
|
||||
const util = require('util');
|
||||
const bootstrap = require('../../src/bootstrap');
|
||||
const bootstrap = require('../../../src/bootstrap');
|
||||
const coverage = require('../coverage');
|
||||
|
||||
require('reflect-metadata'); // {{SQL CARBON EDIT}}
|
||||
@@ -26,7 +26,7 @@ let _out;
|
||||
|
||||
function initLoader(opts) {
|
||||
let outdir = opts.build ? 'out-build' : 'out';
|
||||
_out = path.join(__dirname, `../../${outdir}`);
|
||||
_out = path.join(__dirname, `../../../${outdir}`);
|
||||
|
||||
// setup loader
|
||||
loader = require(`${_out}/vs/loader`);
|
||||
@@ -34,7 +34,7 @@ function initLoader(opts) {
|
||||
nodeRequire: require,
|
||||
nodeMain: __filename,
|
||||
catchError: true,
|
||||
baseUrl: bootstrap.uriFromPath(path.join(__dirname, '../../src')),
|
||||
baseUrl: bootstrap.uriFromPath(path.join(__dirname, '../../../src')),
|
||||
paths: {
|
||||
'vs': `../${outdir}/vs`,
|
||||
'sql': `../${outdir}/sql`, // {{SQL CARBON EDIT}}
|
||||
@@ -11,42 +11,40 @@ const path = require('path');
|
||||
const glob = require('glob');
|
||||
const jsdom = require('jsdom-no-contextify');
|
||||
const TEST_GLOB = '**/test/**/*.test.js';
|
||||
const coverage = require('./coverage');
|
||||
const coverage = require('../coverage');
|
||||
|
||||
require('reflect-metadata'); // {{SQL CARBON EDIT}}
|
||||
|
||||
var optimist = require('optimist')
|
||||
const optimist = require('optimist')
|
||||
.usage('Run the Code tests. All mocha options apply.')
|
||||
.describe('build', 'Run from out-build').boolean('build')
|
||||
.describe('run', 'Run a single file').string('run')
|
||||
.describe('coverage', 'Generate a coverage report').boolean('coverage')
|
||||
.describe('only-monaco-editor', 'Run only monaco editor tests').boolean('only-monaco-editor')
|
||||
.describe('browser', 'Run tests in a browser').boolean('browser')
|
||||
.alias('h', 'help').boolean('h')
|
||||
.describe('h', 'Show help');
|
||||
|
||||
var argv = optimist.argv;
|
||||
const argv = optimist.argv;
|
||||
|
||||
if (argv.help) {
|
||||
optimist.showHelp();
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
var out = argv.build ? 'out-build' : 'out';
|
||||
var loader = require('../' + out + '/vs/loader');
|
||||
var src = path.join(path.dirname(__dirname), out);
|
||||
const REPO_ROOT = path.join(__dirname, '../../../');
|
||||
const out = argv.build ? 'out-build' : 'out';
|
||||
const loader = require(`../../../${out}/vs/loader`);
|
||||
const src = path.join(REPO_ROOT, out);
|
||||
|
||||
function main() {
|
||||
process.on('uncaughtException', function (e) {
|
||||
console.error(e.stack || e);
|
||||
});
|
||||
|
||||
var loaderConfig = {
|
||||
const loaderConfig = {
|
||||
nodeRequire: require,
|
||||
nodeMain: __filename,
|
||||
baseUrl: path.join(path.dirname(__dirname), 'src'),
|
||||
baseUrl: path.join(REPO_ROOT, 'src'),
|
||||
paths: {
|
||||
'vs/css': '../test/css.mock',
|
||||
'vs/css': '../test/unit/node/css.mock',
|
||||
'vs': `../${out}/vs`,
|
||||
'sql': `../${out}/sql`, // {{SQL CARBON EDIT}}
|
||||
'lib': `../${out}/lib`,
|
||||
@@ -93,17 +91,17 @@ function main() {
|
||||
global.navigator = global.window.navigator;
|
||||
global.XMLHttpRequest = global.window.XMLHttpRequest;
|
||||
|
||||
var didErr = false;
|
||||
var write = process.stderr.write;
|
||||
let didErr = false;
|
||||
const write = process.stderr.write;
|
||||
process.stderr.write = function (data) {
|
||||
didErr = didErr || !!data;
|
||||
write.apply(process.stderr, arguments);
|
||||
};
|
||||
|
||||
var loadFunc = null;
|
||||
let loadFunc = null;
|
||||
|
||||
if (argv.runGlob) {
|
||||
loadFunc = cb => {
|
||||
loadFunc = (cb) => {
|
||||
const doRun = tests => {
|
||||
const modulesToLoad = tests.map(test => {
|
||||
if (path.isAbsolute(test)) {
|
||||
@@ -118,41 +116,19 @@ function main() {
|
||||
glob(argv.runGlob, { cwd: src }, function (err, files) { doRun(files); });
|
||||
};
|
||||
} else if (argv.run) {
|
||||
var tests = (typeof argv.run === 'string') ? [argv.run] : argv.run;
|
||||
var modulesToLoad = tests.map(function (test) {
|
||||
const tests = (typeof argv.run === 'string') ? [argv.run] : argv.run;
|
||||
const modulesToLoad = tests.map(function (test) {
|
||||
test = test.replace(/^src/, 'out');
|
||||
test = test.replace(/\.ts$/, '.js');
|
||||
return path.relative(src, path.resolve(test)).replace(/(\.js)|(\.js\.map)$/, '').replace(/\\/g, '/');
|
||||
});
|
||||
loadFunc = cb => {
|
||||
loadFunc = (cb) => {
|
||||
define(modulesToLoad, () => cb(null), cb);
|
||||
};
|
||||
} else if (argv['only-monaco-editor']) {
|
||||
loadFunc = function (cb) {
|
||||
glob(TEST_GLOB, { cwd: src }, function (err, files) {
|
||||
var modulesToLoad = files.map(function (file) {
|
||||
return file.replace(/\.js$/, '');
|
||||
});
|
||||
modulesToLoad = modulesToLoad.filter(function (module) {
|
||||
if (/^vs\/workbench\//.test(module)) {
|
||||
return false;
|
||||
}
|
||||
// platform tests drag in the workbench.
|
||||
// see https://github.com/Microsoft/vscode/commit/12eaba2f64c69247de105c3d9c47308ac6e44bc9
|
||||
// and cry a little
|
||||
if (/^vs\/platform\//.test(module)) {
|
||||
return false;
|
||||
}
|
||||
return !/(\/|\\)node(\/|\\)/.test(module);
|
||||
});
|
||||
console.log(JSON.stringify(modulesToLoad, null, '\t'));
|
||||
define(modulesToLoad, function () { cb(null); }, cb);
|
||||
});
|
||||
};
|
||||
} else {
|
||||
loadFunc = function (cb) {
|
||||
loadFunc = (cb) => {
|
||||
glob(TEST_GLOB, { cwd: src }, function (err, files) {
|
||||
var modulesToLoad = files.map(function (file) {
|
||||
const modulesToLoad = files.map(function (file) {
|
||||
return file.replace(/\.js$/, '');
|
||||
});
|
||||
define(modulesToLoad, function () { cb(null); }, cb);
|
||||
@@ -178,7 +154,7 @@ function main() {
|
||||
}
|
||||
|
||||
// report failing test for every unexpected error during any of the tests
|
||||
var unexpectedErrors = [];
|
||||
let unexpectedErrors = [];
|
||||
suite('Errors', function () {
|
||||
test('should not have unexpected errors in tests', function () {
|
||||
if (unexpectedErrors.length) {
|
||||
@@ -199,7 +175,7 @@ function main() {
|
||||
event.preventDefault();
|
||||
});
|
||||
errors.setUnexpectedErrorHandler(function (err) {
|
||||
let stack = (err && err.stack) || (new Error().stack);
|
||||
const stack = (err && err.stack) || (new Error().stack);
|
||||
unexpectedErrors.push((err && err.message ? err.message : err) + '\n' + stack);
|
||||
});
|
||||
|
||||
49
test/unit/node/browser.js
Normal file
49
test/unit/node/browser.js
Normal file
@@ -0,0 +1,49 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
const yaserver = require('yaserver');
|
||||
const http = require('http');
|
||||
const glob = require('glob');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
|
||||
const REPO_ROOT = path.join(__dirname, '../../../');
|
||||
const PORT = 8887;
|
||||
|
||||
function template(str, env) {
|
||||
return str.replace(/{{\s*([\w_\-]+)\s*}}/g, function (all, part) {
|
||||
return env[part];
|
||||
});
|
||||
}
|
||||
|
||||
yaserver.createServer({ rootDir: REPO_ROOT }).then((staticServer) => {
|
||||
const server = http.createServer((req, res) => {
|
||||
if (req.url === '' || req.url === '/') {
|
||||
glob('**/vs/{base,platform,editor}/**/test/{common,browser}/**/*.test.js', {
|
||||
cwd: path.join(REPO_ROOT, 'out'),
|
||||
// ignore: ['**/test/{node,electron*}/**/*.js']
|
||||
}, function (err, files) {
|
||||
if (err) { console.log(err); process.exit(0); }
|
||||
|
||||
var modules = files
|
||||
.map(function (file) { return file.replace(/\.js$/, ''); });
|
||||
|
||||
fs.readFile(path.join(__dirname, 'index.html'), 'utf8', function (err, templateString) {
|
||||
if (err) { console.log(err); process.exit(0); }
|
||||
|
||||
res.end(template(templateString, {
|
||||
modules: JSON.stringify(modules)
|
||||
}));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
return staticServer.handle(req, res);
|
||||
}
|
||||
});
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log(`http://localhost:${PORT}/`);
|
||||
});
|
||||
});
|
||||
@@ -16,7 +16,7 @@
|
||||
require.config({
|
||||
baseUrl: '/out',
|
||||
paths: {
|
||||
assert: '/test/assert.js',
|
||||
assert: '/test/unit/assert.js',
|
||||
sinon: '/node_modules/sinon/pkg/sinon-1.17.7.js'
|
||||
}
|
||||
});
|
||||
@@ -26,4 +26,4 @@
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
Reference in New Issue
Block a user