提交 091b4454 编写于 作者: J Joao Moreno

fixes #48109

上级 52007064
......@@ -34,6 +34,7 @@ export interface IDriver {
doubleClick(windowId: number, selector: string): TPromise<void>;
move(windowId: number, selector: string): TPromise<void>;
setValue(windowId: number, selector: string, text: string): TPromise<void>;
paste(windowId: number, selector: string, text: string): TPromise<void>;
getTitle(windowId: number): TPromise<string>;
isActiveElement(windowId: number, selector: string): TPromise<boolean>;
getElements(windowId: number, selector: string, recursive?: boolean): TPromise<IElement[]>;
......@@ -51,6 +52,7 @@ export interface IDriverChannel extends IChannel {
call(command: 'doubleClick', arg: [number, string]): TPromise<void>;
call(command: 'move', arg: [number, string]): TPromise<void>;
call(command: 'setValue', arg: [number, string, string]): TPromise<void>;
call(command: 'paste', arg: [number, string, string]): TPromise<void>;
call(command: 'getTitle', arg: [number]): TPromise<string>;
call(command: 'isActiveElement', arg: [number, string]): TPromise<boolean>;
call(command: 'getElements', arg: [number, string, boolean]): TPromise<IElement[]>;
......@@ -73,6 +75,7 @@ export class DriverChannel implements IDriverChannel {
case 'doubleClick': return this.driver.doubleClick(arg[0], arg[1]);
case 'move': return this.driver.move(arg[0], arg[1]);
case 'setValue': return this.driver.setValue(arg[0], arg[1], arg[2]);
case 'paste': return this.driver.paste(arg[0], arg[1], arg[2]);
case 'getTitle': return this.driver.getTitle(arg[0]);
case 'isActiveElement': return this.driver.isActiveElement(arg[0], arg[1]);
case 'getElements': return this.driver.getElements(arg[0], arg[1], arg[2]);
......@@ -122,6 +125,10 @@ export class DriverChannelClient implements IDriver {
return this.channel.call('setValue', [windowId, selector, text]);
}
paste(windowId: number, selector: string, text: string): TPromise<void> {
return this.channel.call('paste', [windowId, selector, text]);
}
getTitle(windowId: number): TPromise<string> {
return this.channel.call('getTitle', [windowId]);
}
......@@ -188,6 +195,7 @@ export interface IWindowDriver {
doubleClick(selector: string): TPromise<void>;
move(selector: string): TPromise<void>;
setValue(selector: string, text: string): TPromise<void>;
paste(selector: string, text: string): TPromise<void>;
getTitle(): TPromise<string>;
isActiveElement(selector: string): TPromise<boolean>;
getElements(selector: string, recursive: boolean): TPromise<IElement[]>;
......@@ -200,6 +208,7 @@ export interface IWindowDriverChannel extends IChannel {
call(command: 'doubleClick', arg: string): TPromise<void>;
call(command: 'move', arg: string): TPromise<void>;
call(command: 'setValue', arg: [string, string]): TPromise<void>;
call(command: 'paste', arg: [string, string]): TPromise<void>;
call(command: 'getTitle'): TPromise<string>;
call(command: 'isActiveElement', arg: string): TPromise<boolean>;
call(command: 'getElements', arg: [string, boolean]): TPromise<IElement[]>;
......@@ -218,6 +227,7 @@ export class WindowDriverChannel implements IWindowDriverChannel {
case 'doubleClick': return this.driver.doubleClick(arg);
case 'move': return this.driver.move(arg);
case 'setValue': return this.driver.setValue(arg[0], arg[1]);
case 'paste': return this.driver.paste(arg[0], arg[1]);
case 'getTitle': return this.driver.getTitle();
case 'isActiveElement': return this.driver.isActiveElement(arg);
case 'getElements': return this.driver.getElements(arg[0], arg[1]);
......@@ -251,6 +261,10 @@ export class WindowDriverChannelClient implements IWindowDriver {
return this.channel.call('setValue', [selector, text]);
}
paste(selector: string, text: string): TPromise<void> {
return this.channel.call('paste', [selector, text]);
}
getTitle(): TPromise<string> {
return this.channel.call('getTitle');
}
......
......@@ -106,6 +106,21 @@ class WindowDriver implements IWindowDriver {
inputElement.dispatchEvent(event);
}
async paste(selector: string, text: string): TPromise<void> {
const element = document.querySelector(selector);
if (!element) {
throw new Error('Element not found');
}
const inputElement = element as HTMLInputElement;
const clipboardData = new DataTransfer();
clipboardData.setData('text/plain', text);
const event = new ClipboardEvent('paste', { clipboardData } as any);
inputElement.dispatchEvent(event);
}
async getTitle(): TPromise<string> {
return document.title;
}
......@@ -154,12 +169,16 @@ class WindowDriver implements IWindowDriver {
throw new Error('Terminal not found: ' + selector);
}
const buffer = (element as any).xterm.buffer;
const xterm = (element as any).xterm;
if (!xterm) {
throw new Error('Xterm not found: ' + selector);
}
const lines: string[] = [];
for (let i = 0; i < buffer.lines.length; i++) {
lines.push(buffer.translateBufferLineToString(i, true));
for (let i = 0; i < xterm.buffer.lines.length; i++) {
lines.push(xterm.buffer.translateBufferLineToString(i, true));
}
return lines;
......
......@@ -155,6 +155,11 @@ export class Driver implements IDriver, IWindowDriverRegistry {
return windowDriver.setValue(selector, text);
}
async paste(windowId: number, selector: string, text: string): TPromise<void> {
const windowDriver = await this.getWindowDriver(windowId);
return windowDriver.paste(selector, text);
}
async getTitle(windowId: number): TPromise<string> {
const windowDriver = await this.getWindowDriver(windowId);
return windowDriver.getTitle();
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Application } from '../../application';
export function setup() {
describe('Terminal', () => {
it(`opens terminal, runs 'echo' and verifies the output`, async function () {
const app = this.app as Application;
const expected = new Date().getTime().toString();
await app.workbench.terminal.showTerminal();
await app.workbench.terminal.runCommand(`echo ${expected}`);
await app.workbench.terminal.waitForTerminalText(terminalText => {
for (let index = terminalText.length - 2; index >= 0; index--) {
if (!!terminalText[index] && terminalText[index].trim() === expected) {
return true;
}
}
return false;
});
});
});
}
\ No newline at end of file
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Code } from '../../vscode/code';
import { Commands } from '../workbench/workbench';
const PANEL_SELECTOR = 'div[id="workbench.panel.terminal"]';
const XTERM_SELECTOR = `${PANEL_SELECTOR} .terminal-wrapper`;
const XTERM_TEXTAREA = `${XTERM_SELECTOR} textarea.xterm-helper-textarea`;
export class Terminal {
constructor(private code: Code, private commands: Commands) { }
async showTerminal(): Promise<void> {
await this.commands.runCommand('workbench.action.terminal.toggleTerminal');
await this.code.waitForActiveElement(XTERM_TEXTAREA);
await this.code.waitForTerminalBuffer(XTERM_SELECTOR, lines => lines.some(line => line.length > 0));
}
async runCommand(commandText: string): Promise<void> {
await this.code.waitForPaste(XTERM_TEXTAREA, commandText);
await this.code.dispatchKeybinding('enter');
}
async waitForTerminalText(accept: (buffer: string[]) => boolean): Promise<void> {
await this.code.waitForTerminalBuffer(XTERM_SELECTOR, accept);
}
}
\ No newline at end of file
......@@ -17,6 +17,7 @@ import { SettingsEditor } from '../preferences/settings';
import { KeybindingsEditor } from '../preferences/keybindings';
import { Editors } from '../editor/editors';
import { Code } from '../../vscode/code';
import { Terminal } from '../terminal/terminal';
export interface Commands {
runCommand(command: string): Promise<any>;
......@@ -37,6 +38,7 @@ export class Workbench implements Commands {
readonly problems: Problems;
readonly settingsEditor: SettingsEditor;
readonly keybindingsEditor: KeybindingsEditor;
readonly terminal: Terminal;
constructor(private code: Code, private keybindings: any[], userDataPath: string) {
this.editors = new Editors(code, this);
......@@ -52,6 +54,7 @@ export class Workbench implements Commands {
this.problems = new Problems(code, this);
this.settingsEditor = new SettingsEditor(code, userDataPath, this, this.editors, this.editor);
this.keybindingsEditor = new KeybindingsEditor(code, this);
this.terminal = new Terminal(code, this);
}
/**
......
......@@ -24,6 +24,7 @@ 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';
import { setup as setupDataMultirootTests } from './areas/multiroot/multiroot.test';
import { setup as setupDataLocalizationTests } from './areas/workbench/localization.test';
......@@ -300,6 +301,7 @@ describe('Test', () => {
setupDataGitTests();
setupDataStatusbarTests();
setupDataExtensionTests();
setupTerminalTests();
setupDataMultirootTests();
setupDataLocalizationTests();
});
......@@ -247,6 +247,11 @@ export class Code {
await poll(() => this.driver.setValue(windowId, selector, value), () => true, `set value '${selector}'`);
}
async waitForPaste(selector: string, value: string): Promise<void> {
const windowId = await this.getActiveWindowId();
await poll(() => this.driver.paste(windowId, selector, value), () => true, `paste '${selector}'`);
}
async waitForElements(selector: string, recursive: boolean, accept: (result: IElement[]) => boolean = result => result.length > 0): Promise<IElement[]> {
const windowId = await this.getActiveWindowId();
return await poll(() => this.driver.getElements(windowId, selector, recursive), accept, `get elements '${selector}'`);
......@@ -272,6 +277,11 @@ export class Code {
await poll(() => this.driver.typeInEditor(windowId, selector, text), () => true, `type in editor '${selector}'`);
}
async waitForTerminalBuffer(selector: string, accept: (result: string[]) => boolean): Promise<void> {
const windowId = await this.getActiveWindowId();
await poll(() => this.driver.getTerminalBuffer(windowId, selector), accept, `get terminal buffer '${selector}'`);
}
private async getActiveWindowId(): Promise<number> {
if (typeof this._activeWindowId !== 'number') {
const windows = await this.driver.getWindowIds();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册