Merge VS Code 1.23.1 (#1520)

This commit is contained in:
Matt Irvine
2018-06-05 11:24:51 -07:00
committed by GitHub
parent e3baf5c443
commit 0c58f09e59
3651 changed files with 74249 additions and 48599 deletions

View File

@@ -8,17 +8,12 @@ import * as http from 'http';
import * as path from 'path';
import * as fs from 'fs';
import * as stripJsonComments from 'strip-json-comments';
import { SpectronApplication } from '../../spectron/application';
import { Application } from '../../application';
export function setup() {
describe('Debug', () => {
before(async function () {
const app = this.app as SpectronApplication;
app.suiteName = 'Debug';
});
it('configure launch json', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.debug.openDebugViewlet();
await app.workbench.quickopen.openFile('app.js');
@@ -31,7 +26,6 @@ export function setup() {
fs.writeFileSync(launchJsonPath, JSON.stringify(config, undefined, 4), 'utf8');
await app.workbench.editor.waitForEditorContents('launch.json', contents => /"protocol": "inspector"/.test(contents));
await app.screenCapturer.capture('launch.json file');
assert.equal(config.configurations[0].request, 'launch');
assert.equal(config.configurations[0].type, 'node');
@@ -43,66 +37,61 @@ export function setup() {
});
it('breakpoints', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.quickopen.openFile('index.js');
await app.workbench.debug.setBreakpointOnLine(6);
await app.screenCapturer.capture('breakpoints are set');
});
let port: number;
it('start debugging', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
// TODO@isidor
await new Promise(c => setTimeout(c, 100));
port = await app.workbench.debug.startDebugging();
await app.screenCapturer.capture('debugging has started');
await new Promise((c, e) => {
const request = http.get(`http://localhost:${port}`);
request.on('error', e);
app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, 'looking for index.js and line 6').then(c, e);
});
await app.screenCapturer.capture('debugging is paused');
});
it('focus stack frames and variables', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables');
await app.workbench.debug.waitForVariableCount(4);
await app.workbench.debug.focusStackFrame('layer.js', 'looking for layer.js');
await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 5, 'there should be 5 local variables');
await app.workbench.debug.waitForVariableCount(5);
await app.workbench.debug.focusStackFrame('route.js', 'looking for route.js');
await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 3, 'there should be 3 local variables');
await app.workbench.debug.waitForVariableCount(3);
await app.workbench.debug.focusStackFrame('index.js', 'looking for index.js');
await app.client.waitFor(() => app.workbench.debug.getLocalVariableCount(), c => c === 4, 'there should be 4 local variables');
await app.workbench.debug.waitForVariableCount(4);
});
it('stepOver, stepIn, stepOut', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.debug.stepIn();
await app.screenCapturer.capture('debugging has stepped in');
const first = await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js', 'looking for response.js');
await app.workbench.debug.stepOver();
await app.screenCapturer.capture('debugging has stepped over');
await app.workbench.debug.waitForStackFrame(sf => sf.name === 'response.js' && sf.lineNumber === first.lineNumber + 1, `looking for response.js and line ${first.lineNumber + 1}`);
await app.workbench.debug.stepOut();
await app.screenCapturer.capture('debugging has stepped out');
await app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 7, `looking for index.js and line 7`);
});
it('continue', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.debug.continue();
await app.screenCapturer.capture('debugging has continued');
await new Promise((c, e) => {
const request = http.get(`http://localhost:${port}`);
@@ -110,20 +99,18 @@ export function setup() {
app.workbench.debug.waitForStackFrame(sf => sf.name === 'index.js' && sf.lineNumber === 6, `looking for index.js and line 6`).then(c, e);
});
await app.screenCapturer.capture('debugging is paused');
});
it('debug console', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.debug.waitForReplCommand('2 + 2', r => r === '4');
});
it('stop debugging', async function () {
const app = this.app as SpectronApplication;
const app = this.app as Application;
await app.workbench.debug.stopDebugging();
await app.screenCapturer.capture('debugging has stopped');
});
});
}

View File

@@ -3,13 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { SpectronApplication } from '../../spectron/application';
import { Viewlet } from '../workbench/viewlet';
import { Commands } from '../workbench/workbench';
import { Code, findElement } from '../../vscode/code';
import { Editors } from '../editor/editors';
import { Editor } from '../editor/editor';
import { IElement } from '../../vscode/driver';
const VIEWLET = 'div[id="workbench.view.debug"]';
const DEBUG_VIEW = `${VIEWLET} .debug-view-content`;
const CONFIGURE = `div[id="workbench.parts.sidebar"] .actions-container .configure`;
const START = `.icon[title="Start Debugging"]`;
const STOP = `.debug-actions-widget .debug-action.stop`;
const STEP_OVER = `.debug-actions-widget .debug-action.step-over`;
const STEP_IN = `.debug-actions-widget .debug-action.step-into`;
@@ -20,152 +23,120 @@ const BREAKPOINT_GLYPH = '.debug-breakpoint';
const PAUSE = `.debug-actions-widget .debug-action.pause`;
const DEBUG_STATUS_BAR = `.statusbar.debugging`;
const NOT_DEBUG_STATUS_BAR = `.statusbar:not(debugging)`;
const TOOLBAR_HIDDEN = `.debug-actions-widget.builder-hidden`;
const TOOLBAR_HIDDEN = `.debug-actions-widget.monaco-builder-hidden`;
const STACK_FRAME = `${VIEWLET} .monaco-tree-row .stack-frame`;
const SPECIFIC_STACK_FRAME = filename => `${STACK_FRAME} .file[title$="${filename}"]`;
const VARIABLE = `${VIEWLET} .debug-variables .monaco-tree-row .expression`;
const CONSOLE_OUTPUT = `.repl .output.expression`;
const CONSOLE_OUTPUT = `.repl .output.expression .value`;
const CONSOLE_INPUT_OUTPUT = `.repl .input-output-pair .output.expression .value`;
const REPL_FOCUSED = '.repl-input-wrapper .monaco-editor textarea';
export interface IStackFrame {
id: string;
name: string;
lineNumber: number;
}
function toStackFrame(element: IElement): IStackFrame {
const name = findElement(element, e => /\bfile-name\b/.test(e.className))!;
const line = findElement(element, e => /\bline-number\b/.test(e.className))!;
const lineNumber = line.textContent ? parseInt(line.textContent.split(':').shift() || '0') : 0;
return {
name: name.textContent || '',
lineNumber
};
}
export class Debug extends Viewlet {
constructor(spectron: SpectronApplication) {
super(spectron);
constructor(code: Code, private commands: Commands, private editors: Editors, private editor: Editor) {
super(code);
}
async openDebugViewlet(): Promise<any> {
await this.spectron.runCommand('workbench.view.debug');
await this.spectron.client.waitForElement(DEBUG_VIEW);
await this.commands.runCommand('workbench.view.debug');
await this.code.waitForElement(DEBUG_VIEW);
}
async configure(): Promise<any> {
await this.spectron.client.waitAndClick(CONFIGURE);
await this.spectron.workbench.waitForEditorFocus('launch.json');
await this.code.waitAndClick(CONFIGURE);
await this.editors.waitForEditorFocus('launch.json');
}
async setBreakpointOnLine(lineNumber: number): Promise<any> {
await this.spectron.client.waitForElement(`${GLYPH_AREA}(${lineNumber})`);
await this.spectron.client.leftClick(`${GLYPH_AREA}(${lineNumber})`, 5, 5);
await this.spectron.client.waitForElement(BREAKPOINT_GLYPH);
await this.code.waitForElement(`${GLYPH_AREA}(${lineNumber})`);
await this.code.waitAndClick(`${GLYPH_AREA}(${lineNumber})`, 5, 5);
await this.code.waitForElement(BREAKPOINT_GLYPH);
}
async startDebugging(): Promise<number> {
await this.spectron.client.waitAndClick(START);
await this.spectron.client.waitForElement(PAUSE);
await this.spectron.client.waitForElement(DEBUG_STATUS_BAR);
await this.commands.runCommand('workbench.action.debug.start');
await this.code.waitForElement(PAUSE);
await this.code.waitForElement(DEBUG_STATUS_BAR);
const portPrefix = 'Port: ';
await this.spectron.client.waitFor(async () => {
const output = await this.getConsoleOutput();
return output.join('');
}, text => !!text && text.indexOf(portPrefix) >= 0);
const output = await this.getConsoleOutput();
const lastOutput = output.pop();
const output = await this.waitForOutput(output => output.some(line => line.indexOf(portPrefix) >= 0));
const lastOutput = output.filter(line => line.indexOf(portPrefix) >= 0)[0];
return lastOutput ? parseInt(lastOutput.substr(portPrefix.length)) : 3000;
}
async stepOver(): Promise<any> {
await this.spectron.client.waitAndClick(STEP_OVER);
await this.code.waitAndClick(STEP_OVER);
}
async stepIn(): Promise<any> {
await this.spectron.client.waitAndClick(STEP_IN);
await this.code.waitAndClick(STEP_IN);
}
async stepOut(): Promise<any> {
await this.spectron.client.waitAndClick(STEP_OUT);
await this.code.waitAndClick(STEP_OUT);
}
async continue(): Promise<any> {
await this.spectron.client.waitAndClick(CONTINUE);
await this.code.waitAndClick(CONTINUE);
await this.waitForStackFrameLength(0);
}
async stopDebugging(): Promise<any> {
await this.spectron.client.waitAndClick(STOP);
await this.spectron.client.waitForElement(TOOLBAR_HIDDEN);
await this.spectron.client.waitForElement(NOT_DEBUG_STATUS_BAR);
await this.code.waitAndClick(STOP);
await this.code.waitForElement(TOOLBAR_HIDDEN);
await this.code.waitForElement(NOT_DEBUG_STATUS_BAR);
}
async waitForStackFrame(func: (stackFrame: IStackFrame) => boolean, message: string): Promise<IStackFrame> {
return await this.spectron.client.waitFor(async () => {
const stackFrames = await this.getStackFrames();
return stackFrames.filter(func)[0];
}, void 0, `Waiting for Stack Frame: ${message}`);
const elements = await this.code.waitForElements(STACK_FRAME, true, elements => elements.some(e => func(toStackFrame(e))));
return elements.map(toStackFrame).filter(s => func(s))[0];
}
async waitForStackFrameLength(length: number): Promise<any> {
return await this.spectron.client.waitFor(() => this.getStackFrames(), stackFrames => stackFrames.length === length);
await this.code.waitForElements(STACK_FRAME, false, result => result.length === length);
}
async focusStackFrame(name: string, message: string): Promise<any> {
const stackFrame = await this.waitForStackFrame(sf => sf.name === name, message);
await this.spectron.client.spectron.client.elementIdClick(stackFrame.id);
await this.spectron.workbench.waitForTab(name);
await this.code.waitAndClick(SPECIFIC_STACK_FRAME(name));
await this.editors.waitForTab(name);
}
async waitForReplCommand(text: string, accept: (result: string) => boolean): Promise<void> {
await this.spectron.workbench.quickopen.runCommand('Debug: Focus Debug Console');
await this.spectron.client.waitForActiveElement(REPL_FOCUSED);
await this.spectron.client.setValue(REPL_FOCUSED, text);
await this.commands.runCommand('Debug: Focus Debug Console');
await this.code.waitForActiveElement(REPL_FOCUSED);
await this.code.waitForSetValue(REPL_FOCUSED, text);
// Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed
await this.spectron.workbench.editor.waitForEditorContents('debug:input', s => s.indexOf(text) >= 0);
await this.spectron.client.keys(['Enter', 'NULL']);
await this.spectron.client.waitForElement(CONSOLE_INPUT_OUTPUT);
await this.spectron.client.waitFor(async () => {
const result = await this.getConsoleOutput();
return result[result.length - 1] || '';
}, accept);
await this.editor.waitForEditorContents('debug:input', s => s.indexOf(text) >= 0);
await this.code.dispatchKeybinding('enter');
await this.code.waitForElement(CONSOLE_INPUT_OUTPUT);
await this.waitForOutput(output => accept(output[output.length - 1] || ''));
}
async getLocalVariableCount(): Promise<number> {
return await this.spectron.webclient.selectorExecute(VARIABLE, div => (Array.isArray(div) ? div : [div]).length);
async waitForVariableCount(count: number): Promise<void> {
await this.code.waitForElements(VARIABLE, false, els => els.length === count);
}
async getStackFramesLength(): Promise<number> {
const stackFrames = await this.getStackFrames();
return stackFrames.length;
}
private async getStackFrames(): Promise<IStackFrame[]> {
const result = await this.spectron.webclient.selectorExecute(STACK_FRAME,
div => (Array.isArray(div) ? div : [div]).map(element => {
const name = element.querySelector('.file-name') as HTMLElement;
const line = element.querySelector('.line-number') as HTMLElement;
const lineNumber = line.textContent ? parseInt(line.textContent.split(':').shift() || '0') : 0;
return {
name: name.textContent,
lineNumber,
element
};
})
);
if (!Array.isArray(result)) {
return [];
}
return result
.map(({ name, lineNumber, element }) => ({ name, lineNumber, id: element.ELEMENT }));
}
private async getConsoleOutput(): Promise<string[]> {
const result = await this.spectron.webclient.selectorExecute(CONSOLE_OUTPUT,
div => (Array.isArray(div) ? div : [div]).map(element => {
const value = element.querySelector('.value') as HTMLElement;
return value && value.textContent;
}).filter(line => !!line)
);
return result;
private async waitForOutput(fn: (output: string[]) => boolean): Promise<string[]> {
const elements = await this.code.waitForElements(CONSOLE_OUTPUT, false, elements => fn(elements.map(e => e.textContent)));
return elements.map(e => e.textContent);
}
}