diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 49366717d5f..21c021950f9 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -3,7 +3,6 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { IWindowDriver, IElement, WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver'; import { IPCClient } from 'vs/base/parts/ipc/node/ipc'; @@ -50,19 +49,19 @@ class WindowDriver implements IWindowDriver { @IWindowService private windowService: IWindowService ) { } - click(selector: string, xoffset?: number, yoffset?: number): TPromise { + click(selector: string, xoffset?: number, yoffset?: number): Promise { return this._click(selector, 1, xoffset, yoffset); } - doubleClick(selector: string): TPromise { + doubleClick(selector: string): Promise { return this._click(selector, 2); } - private _getElementXY(selector: string, xoffset?: number, yoffset?: number): TPromise<{ x: number; y: number; }> { + private async _getElementXY(selector: string, xoffset?: number, yoffset?: number): Promise<{ x: number; y: number; }> { const element = document.querySelector(selector); if (!element) { - return TPromise.wrapError(new Error(`Element not found: ${selector}`)); + return Promise.reject(new Error(`Element not found: ${selector}`)); } const { left, top } = getTopLeftOffset(element as HTMLElement); @@ -80,27 +79,25 @@ class WindowDriver implements IWindowDriver { x = Math.round(x); y = Math.round(y); - return TPromise.as({ x, y }); + return { x, y }; } - private _click(selector: string, clickCount: number, xoffset?: number, yoffset?: number): TPromise { - return this._getElementXY(selector, xoffset, yoffset).then(({ x, y }) => { + private async _click(selector: string, clickCount: number, xoffset?: number, yoffset?: number): Promise { + const { x, y } = await this._getElementXY(selector, xoffset, yoffset); - const webContents: electron.WebContents = (electron as any).remote.getCurrentWebContents(); - webContents.sendInputEvent({ type: 'mouseDown', x, y, button: 'left', clickCount } as any); + const webContents: electron.WebContents = (electron as any).remote.getCurrentWebContents(); + webContents.sendInputEvent({ type: 'mouseDown', x, y, button: 'left', clickCount } as any); + await timeout(10); - return TPromise.wrap(timeout(10)).then(() => { - webContents.sendInputEvent({ type: 'mouseUp', x, y, button: 'left', clickCount } as any); - return TPromise.wrap(timeout(100)); - }); - }); + webContents.sendInputEvent({ type: 'mouseUp', x, y, button: 'left', clickCount } as any); + await timeout(100); } - setValue(selector: string, text: string): TPromise { + async setValue(selector: string, text: string): Promise { const element = document.querySelector(selector); if (!element) { - return TPromise.wrapError(new Error(`Element not found: ${selector}`)); + return Promise.reject(new Error(`Element not found: ${selector}`)); } const inputElement = element as HTMLInputElement; @@ -108,15 +105,13 @@ class WindowDriver implements IWindowDriver { const event = new Event('input', { bubbles: true, cancelable: true }); inputElement.dispatchEvent(event); - - return TPromise.as(null); } - getTitle(): TPromise { - return TPromise.as(document.title); + async getTitle(): Promise { + return document.title; } - isActiveElement(selector: string): TPromise { + async isActiveElement(selector: string): Promise { const element = document.querySelector(selector); if (element !== document.activeElement) { @@ -132,13 +127,13 @@ class WindowDriver implements IWindowDriver { el = el.parentElement; } - return TPromise.wrapError(new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`)); + throw new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`); } - return TPromise.as(true); + return true; } - getElements(selector: string, recursive: boolean): TPromise { + async getElements(selector: string, recursive: boolean): Promise { const query = document.querySelectorAll(selector); const result: IElement[] = []; @@ -147,14 +142,14 @@ class WindowDriver implements IWindowDriver { result.push(serializeElement(element, recursive)); } - return TPromise.as(result); + return result; } - typeInEditor(selector: string, text: string): TPromise { + async typeInEditor(selector: string, text: string): Promise { const element = document.querySelector(selector); if (!element) { - return TPromise.wrapError(new Error(`Editor not found: ${selector}`)); + throw new Error(`Editor not found: ${selector}`); } const textarea = element as HTMLTextAreaElement; @@ -168,21 +163,19 @@ class WindowDriver implements IWindowDriver { const event = new Event('input', { 'bubbles': true, 'cancelable': true }); textarea.dispatchEvent(event); - - return TPromise.as(null); } - getTerminalBuffer(selector: string): TPromise { + async getTerminalBuffer(selector: string): Promise { const element = document.querySelector(selector); if (!element) { - return TPromise.wrapError(new Error(`Terminal not found: ${selector}`)); + throw new Error(`Terminal not found: ${selector}`); } const xterm: Terminal = (element as any).xterm; if (!xterm) { - return TPromise.wrapError(new Error(`Xterm not found: ${selector}`)); + throw new Error(`Xterm not found: ${selector}`); } const lines: string[] = []; @@ -191,29 +184,27 @@ class WindowDriver implements IWindowDriver { lines.push(xterm._core.buffer.translateBufferLineToString(i, true)); } - return TPromise.as(lines); + return lines; } - writeInTerminal(selector: string, text: string): TPromise { + async writeInTerminal(selector: string, text: string): Promise { const element = document.querySelector(selector); if (!element) { - return TPromise.wrapError(new Error(`Element not found: ${selector}`)); + throw new Error(`Element not found: ${selector}`); } const xterm: Terminal = (element as any).xterm; if (!xterm) { - return TPromise.wrapError(new Error(`Xterm not found: ${selector}`)); + throw new Error(`Xterm not found: ${selector}`); } xterm._core.handler(text); - - return TPromise.as(null); } - openDevTools(): TPromise { - return this.windowService.openDevTools({ mode: 'detach' }); + async openDevTools(): Promise { + await this.windowService.openDevTools({ mode: 'detach' }); } } diff --git a/src/vs/platform/driver/node/driver.ts b/src/vs/platform/driver/node/driver.ts index 2337f164adc..79b3343e14e 100644 --- a/src/vs/platform/driver/node/driver.ts +++ b/src/vs/platform/driver/node/driver.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import { connect as connectNet, Client } from 'vs/base/parts/ipc/node/ipc.net'; -import { TPromise } from 'vs/base/common/winjs.base'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/node/ipc'; import { Event } from 'vs/base/common/event'; @@ -28,19 +27,19 @@ export interface IElement { export interface IDriver { _serviceBrand: any; - getWindowIds(): TPromise; - capturePage(windowId: number): TPromise; - reloadWindow(windowId: number): TPromise; - dispatchKeybinding(windowId: number, keybinding: string): TPromise; - click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise; - doubleClick(windowId: number, selector: string): TPromise; - setValue(windowId: number, selector: string, text: string): TPromise; - getTitle(windowId: number): TPromise; - isActiveElement(windowId: number, selector: string): TPromise; - getElements(windowId: number, selector: string, recursive?: boolean): TPromise; - typeInEditor(windowId: number, selector: string, text: string): TPromise; - getTerminalBuffer(windowId: number, selector: string): TPromise; - writeInTerminal(windowId: number, selector: string, text: string): TPromise; + getWindowIds(): Thenable; + capturePage(windowId: number): Thenable; + reloadWindow(windowId: number): Thenable; + dispatchKeybinding(windowId: number, keybinding: string): Thenable; + click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Thenable; + doubleClick(windowId: number, selector: string): Thenable; + setValue(windowId: number, selector: string, text: string): Thenable; + getTitle(windowId: number): Thenable; + isActiveElement(windowId: number, selector: string): Thenable; + getElements(windowId: number, selector: string, recursive?: boolean): Thenable; + typeInEditor(windowId: number, selector: string, text: string): Thenable; + getTerminalBuffer(windowId: number, selector: string): Thenable; + writeInTerminal(windowId: number, selector: string, text: string): Thenable; } //*END @@ -52,7 +51,7 @@ export class DriverChannel implements IServerChannel { throw new Error('No event found'); } - call(_, command: string, arg?: any): TPromise { + call(_, command: string, arg?: any): Thenable { switch (command) { case 'getWindowIds': return this.driver.getWindowIds(); case 'capturePage': return this.driver.capturePage(arg); @@ -79,56 +78,56 @@ export class DriverChannelClient implements IDriver { constructor(private channel: IChannel) { } - getWindowIds(): TPromise { - return TPromise.wrap(this.channel.call('getWindowIds')); + getWindowIds(): Thenable { + return this.channel.call('getWindowIds'); } - capturePage(windowId: number): TPromise { - return TPromise.wrap(this.channel.call('capturePage', windowId)); + capturePage(windowId: number): Thenable { + return this.channel.call('capturePage', windowId); } - reloadWindow(windowId: number): TPromise { - return TPromise.wrap(this.channel.call('reloadWindow', windowId)); + reloadWindow(windowId: number): Thenable { + return this.channel.call('reloadWindow', windowId); } - dispatchKeybinding(windowId: number, keybinding: string): TPromise { - return TPromise.wrap(this.channel.call('dispatchKeybinding', [windowId, keybinding])); + dispatchKeybinding(windowId: number, keybinding: string): Thenable { + return this.channel.call('dispatchKeybinding', [windowId, keybinding]); } - click(windowId: number, selector: string, xoffset: number | undefined, yoffset: number | undefined): TPromise { - return TPromise.wrap(this.channel.call('click', [windowId, selector, xoffset, yoffset])); + click(windowId: number, selector: string, xoffset: number | undefined, yoffset: number | undefined): Thenable { + return this.channel.call('click', [windowId, selector, xoffset, yoffset]); } - doubleClick(windowId: number, selector: string): TPromise { - return TPromise.wrap(this.channel.call('doubleClick', [windowId, selector])); + doubleClick(windowId: number, selector: string): Thenable { + return this.channel.call('doubleClick', [windowId, selector]); } - setValue(windowId: number, selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('setValue', [windowId, selector, text])); + setValue(windowId: number, selector: string, text: string): Thenable { + return this.channel.call('setValue', [windowId, selector, text]); } - getTitle(windowId: number): TPromise { - return TPromise.wrap(this.channel.call('getTitle', [windowId])); + getTitle(windowId: number): Thenable { + return this.channel.call('getTitle', [windowId]); } - isActiveElement(windowId: number, selector: string): TPromise { - return TPromise.wrap(this.channel.call('isActiveElement', [windowId, selector])); + isActiveElement(windowId: number, selector: string): Thenable { + return this.channel.call('isActiveElement', [windowId, selector]); } - getElements(windowId: number, selector: string, recursive: boolean): TPromise { - return TPromise.wrap(this.channel.call('getElements', [windowId, selector, recursive])); + getElements(windowId: number, selector: string, recursive: boolean): Thenable { + return this.channel.call('getElements', [windowId, selector, recursive]); } - typeInEditor(windowId: number, selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('typeInEditor', [windowId, selector, text])); + typeInEditor(windowId: number, selector: string, text: string): Thenable { + return this.channel.call('typeInEditor', [windowId, selector, text]); } - getTerminalBuffer(windowId: number, selector: string): TPromise { - return TPromise.wrap(this.channel.call('getTerminalBuffer', [windowId, selector])); + getTerminalBuffer(windowId: number, selector: string): Thenable { + return this.channel.call('getTerminalBuffer', [windowId, selector]); } - writeInTerminal(windowId: number, selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('writeInTerminal', [windowId, selector, text])); + writeInTerminal(windowId: number, selector: string, text: string): Thenable { + return this.channel.call('writeInTerminal', [windowId, selector, text]); } } @@ -137,8 +136,8 @@ export interface IDriverOptions { } export interface IWindowDriverRegistry { - registerWindowDriver(windowId: number): TPromise; - reloadWindowDriver(windowId: number): TPromise; + registerWindowDriver(windowId: number): Thenable; + reloadWindowDriver(windowId: number): Thenable; } export class WindowDriverRegistryChannel implements IServerChannel { @@ -165,25 +164,25 @@ export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry constructor(private channel: IChannel) { } - registerWindowDriver(windowId: number): TPromise { - return TPromise.wrap(this.channel.call('registerWindowDriver', windowId)); + registerWindowDriver(windowId: number): Thenable { + return this.channel.call('registerWindowDriver', windowId); } - reloadWindowDriver(windowId: number): TPromise { - return TPromise.wrap(this.channel.call('reloadWindowDriver', windowId)); + reloadWindowDriver(windowId: number): Thenable { + return this.channel.call('reloadWindowDriver', windowId); } } export interface IWindowDriver { - click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise; - doubleClick(selector: string): TPromise; - setValue(selector: string, text: string): TPromise; - getTitle(): TPromise; - isActiveElement(selector: string): TPromise; - getElements(selector: string, recursive: boolean): TPromise; - typeInEditor(selector: string, text: string): TPromise; - getTerminalBuffer(selector: string): TPromise; - writeInTerminal(selector: string, text: string): TPromise; + click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Thenable; + doubleClick(selector: string): Thenable; + setValue(selector: string, text: string): Thenable; + getTitle(): Thenable; + isActiveElement(selector: string): Thenable; + getElements(selector: string, recursive: boolean): Thenable; + typeInEditor(selector: string, text: string): Thenable; + getTerminalBuffer(selector: string): Thenable; + writeInTerminal(selector: string, text: string): Thenable; } export class WindowDriverChannel implements IServerChannel { @@ -217,40 +216,40 @@ export class WindowDriverChannelClient implements IWindowDriver { constructor(private channel: IChannel) { } - click(selector: string, xoffset?: number, yoffset?: number): TPromise { - return TPromise.wrap(this.channel.call('click', [selector, xoffset, yoffset])); + click(selector: string, xoffset?: number, yoffset?: number): Thenable { + return this.channel.call('click', [selector, xoffset, yoffset]); } - doubleClick(selector: string): TPromise { - return TPromise.wrap(this.channel.call('doubleClick', selector)); + doubleClick(selector: string): Thenable { + return this.channel.call('doubleClick', selector); } - setValue(selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('setValue', [selector, text])); + setValue(selector: string, text: string): Thenable { + return this.channel.call('setValue', [selector, text]); } - getTitle(): TPromise { - return TPromise.wrap(this.channel.call('getTitle')); + getTitle(): Thenable { + return this.channel.call('getTitle'); } - isActiveElement(selector: string): TPromise { - return TPromise.wrap(this.channel.call('isActiveElement', selector)); + isActiveElement(selector: string): Thenable { + return this.channel.call('isActiveElement', selector); } - getElements(selector: string, recursive: boolean): TPromise { - return TPromise.wrap(this.channel.call('getElements', [selector, recursive])); + getElements(selector: string, recursive: boolean): Thenable { + return this.channel.call('getElements', [selector, recursive]); } - typeInEditor(selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('typeInEditor', [selector, text])); + typeInEditor(selector: string, text: string): Thenable { + return this.channel.call('typeInEditor', [selector, text]); } - getTerminalBuffer(selector: string): TPromise { - return TPromise.wrap(this.channel.call('getTerminalBuffer', selector)); + getTerminalBuffer(selector: string): Thenable { + return this.channel.call('getTerminalBuffer', selector); } - writeInTerminal(selector: string, text: string): TPromise { - return TPromise.wrap(this.channel.call('writeInTerminal', [selector, text])); + writeInTerminal(selector: string, text: string): Thenable { + return this.channel.call('writeInTerminal', [selector, text]); } } diff --git a/test/smoke/src/vscode/code.ts b/test/smoke/src/vscode/code.ts index 612405b948c..18b5a85dd51 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/smoke/src/vscode/code.ts @@ -7,7 +7,7 @@ import * as path from 'path'; import * as cp from 'child_process'; import * as os from 'os'; import { tmpName } from 'tmp'; -import { IDriver, connect as connectDriver, IDisposable, IElement } from './driver'; +import { IDriver, connect as connectDriver, IDisposable, IElement, Thenable } from './driver'; import { Logger } from '../logger'; const repoPath = path.join(__dirname, '../../../..'); @@ -147,7 +147,7 @@ export async function spawn(options: SpawnOptions): Promise { } async function poll( - fn: () => Promise, + fn: () => Thenable, acceptFn: (result: T) => boolean, timeoutMessage: string, retryCount: number = 200, diff --git a/test/smoke/tools/copy-driver-definition.js b/test/smoke/tools/copy-driver-definition.js index 643e60a67fe..2af7a3acd2a 100644 --- a/test/smoke/tools/copy-driver-definition.js +++ b/test/smoke/tools/copy-driver-definition.js @@ -18,6 +18,23 @@ contents = `/*------------------------------------------------------------------ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +/** + * Thenable is a common denominator between ES6 promises, Q, jquery.Deferred, WinJS.Promise, + * and others. This API makes no assumption about what promise library is being used which + * enables reusing existing code without migrating to a specific promise implementation. Still, + * we recommend the use of native promises which are available in this editor. + */ +interface Thenable { + /** + * Attaches callbacks for the resolution and/or rejection of the Promise. + * @param onfulfilled The callback to execute when the Promise is resolved. + * @param onrejected The callback to execute when the Promise is rejected. + * @returns A Promise for the completion of which ever callback is executed. + */ + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => TResult | Thenable): Thenable; + then(onfulfilled?: (value: T) => TResult | Thenable, onrejected?: (reason: any) => void): Thenable; +} + ${contents} export interface IDisposable {