mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 18:46:40 -05:00
Merge from master
This commit is contained in:
@@ -1,292 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IChannel } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
|
||||
export const ID = 'driverService';
|
||||
export const IDriver = createDecorator<IDriver>(ID);
|
||||
|
||||
// !! Do not remove the following START and END markers, they are parsed by the smoketest build
|
||||
|
||||
//*START
|
||||
export interface IElement {
|
||||
tagName: string;
|
||||
className: string;
|
||||
textContent: string;
|
||||
attributes: { [name: string]: string; };
|
||||
children: IElement[];
|
||||
top: number;
|
||||
left: number;
|
||||
}
|
||||
|
||||
export interface IDriver {
|
||||
_serviceBrand: any;
|
||||
|
||||
getWindowIds(): TPromise<number[]>;
|
||||
capturePage(windowId: number): TPromise<string>;
|
||||
reloadWindow(windowId: number): TPromise<void>;
|
||||
dispatchKeybinding(windowId: number, keybinding: string): TPromise<void>;
|
||||
click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise<void>;
|
||||
doubleClick(windowId: number, selector: string): TPromise<void>;
|
||||
setValue(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[]>;
|
||||
typeInEditor(windowId: number, selector: string, text: string): TPromise<void>;
|
||||
getTerminalBuffer(windowId: number, selector: string): TPromise<string[]>;
|
||||
writeInTerminal(windowId: number, selector: string, text: string): TPromise<void>;
|
||||
}
|
||||
//*END
|
||||
|
||||
export interface IDriverChannel extends IChannel {
|
||||
call(command: 'getWindowIds'): TPromise<number[]>;
|
||||
call(command: 'capturePage'): TPromise<string>;
|
||||
call(command: 'reloadWindow', arg: number): TPromise<void>;
|
||||
call(command: 'dispatchKeybinding', arg: [number, string]): TPromise<void>;
|
||||
call(command: 'click', arg: [number, string, number | undefined, number | undefined]): TPromise<void>;
|
||||
call(command: 'doubleClick', arg: [number, string]): TPromise<void>;
|
||||
call(command: 'setValue', 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[]>;
|
||||
call(command: 'typeInEditor', arg: [number, string, string]): TPromise<void>;
|
||||
call(command: 'getTerminalBuffer', arg: [number, string]): TPromise<string[]>;
|
||||
call(command: 'writeInTerminal', arg: [number, string, string]): TPromise<void>;
|
||||
call(command: string, arg: any): TPromise<any>;
|
||||
}
|
||||
|
||||
export class DriverChannel implements IDriverChannel {
|
||||
|
||||
constructor(private driver: IDriver) { }
|
||||
|
||||
listen<T>(event: string): Event<T> {
|
||||
throw new Error('No event found');
|
||||
}
|
||||
|
||||
call(command: string, arg?: any): TPromise<any> {
|
||||
switch (command) {
|
||||
case 'getWindowIds': return this.driver.getWindowIds();
|
||||
case 'capturePage': return this.driver.capturePage(arg);
|
||||
case 'reloadWindow': return this.driver.reloadWindow(arg);
|
||||
case 'dispatchKeybinding': return this.driver.dispatchKeybinding(arg[0], arg[1]);
|
||||
case 'click': return this.driver.click(arg[0], arg[1], arg[2], arg[3]);
|
||||
case 'doubleClick': return this.driver.doubleClick(arg[0], arg[1]);
|
||||
case 'setValue': return this.driver.setValue(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]);
|
||||
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1], arg[2]);
|
||||
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg[0], arg[1]);
|
||||
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1], arg[2]);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class DriverChannelClient implements IDriver {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IDriverChannel) { }
|
||||
|
||||
getWindowIds(): TPromise<number[]> {
|
||||
return this.channel.call('getWindowIds');
|
||||
}
|
||||
|
||||
capturePage(windowId: number): TPromise<string> {
|
||||
return this.channel.call('capturePage', windowId);
|
||||
}
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void> {
|
||||
return this.channel.call('reloadWindow', windowId);
|
||||
}
|
||||
|
||||
dispatchKeybinding(windowId: number, keybinding: string): TPromise<void> {
|
||||
return this.channel.call('dispatchKeybinding', [windowId, keybinding]);
|
||||
}
|
||||
|
||||
click(windowId: number, selector: string, xoffset: number | undefined, yoffset: number | undefined): TPromise<void> {
|
||||
return this.channel.call('click', [windowId, selector, xoffset, yoffset]);
|
||||
}
|
||||
|
||||
doubleClick(windowId: number, selector: string): TPromise<void> {
|
||||
return this.channel.call('doubleClick', [windowId, selector]);
|
||||
}
|
||||
|
||||
setValue(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('setValue', [windowId, selector, text]);
|
||||
}
|
||||
|
||||
getTitle(windowId: number): TPromise<string> {
|
||||
return this.channel.call('getTitle', [windowId]);
|
||||
}
|
||||
|
||||
isActiveElement(windowId: number, selector: string): TPromise<boolean> {
|
||||
return this.channel.call('isActiveElement', [windowId, selector]);
|
||||
}
|
||||
|
||||
getElements(windowId: number, selector: string, recursive: boolean): TPromise<IElement[]> {
|
||||
return this.channel.call('getElements', [windowId, selector, recursive]);
|
||||
}
|
||||
|
||||
typeInEditor(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('typeInEditor', [windowId, selector, text]);
|
||||
}
|
||||
|
||||
getTerminalBuffer(windowId: number, selector: string): TPromise<string[]> {
|
||||
return this.channel.call('getTerminalBuffer', [windowId, selector]);
|
||||
}
|
||||
|
||||
writeInTerminal(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('writeInTerminal', [windowId, selector, text]);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IDriverOptions {
|
||||
verbose: boolean;
|
||||
}
|
||||
|
||||
export interface IWindowDriverRegistry {
|
||||
registerWindowDriver(windowId: number): TPromise<IDriverOptions>;
|
||||
reloadWindowDriver(windowId: number): TPromise<void>;
|
||||
}
|
||||
|
||||
export interface IWindowDriverRegistryChannel extends IChannel {
|
||||
call(command: 'registerWindowDriver', arg: number): TPromise<IDriverOptions>;
|
||||
call(command: 'reloadWindowDriver', arg: number): TPromise<void>;
|
||||
call(command: string, arg: any): TPromise<any>;
|
||||
}
|
||||
|
||||
export class WindowDriverRegistryChannel implements IWindowDriverRegistryChannel {
|
||||
|
||||
constructor(private registry: IWindowDriverRegistry) { }
|
||||
|
||||
listen<T>(event: string): Event<T> {
|
||||
throw new Error('No event found');
|
||||
}
|
||||
|
||||
call(command: string, arg?: any): TPromise<any> {
|
||||
switch (command) {
|
||||
case 'registerWindowDriver': return this.registry.registerWindowDriver(arg);
|
||||
case 'reloadWindowDriver': return this.registry.reloadWindowDriver(arg);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IWindowDriverRegistryChannel) { }
|
||||
|
||||
registerWindowDriver(windowId: number): TPromise<IDriverOptions> {
|
||||
return this.channel.call('registerWindowDriver', windowId);
|
||||
}
|
||||
|
||||
reloadWindowDriver(windowId: number): TPromise<void> {
|
||||
return this.channel.call('reloadWindowDriver', windowId);
|
||||
}
|
||||
}
|
||||
|
||||
export interface IWindowDriver {
|
||||
click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise<void>;
|
||||
doubleClick(selector: string): TPromise<void>;
|
||||
setValue(selector: string, text: string): TPromise<void>;
|
||||
getTitle(): TPromise<string>;
|
||||
isActiveElement(selector: string): TPromise<boolean>;
|
||||
getElements(selector: string, recursive: boolean): TPromise<IElement[]>;
|
||||
typeInEditor(selector: string, text: string): TPromise<void>;
|
||||
getTerminalBuffer(selector: string): TPromise<string[]>;
|
||||
writeInTerminal(selector: string, text: string): TPromise<void>;
|
||||
}
|
||||
|
||||
export interface IWindowDriverChannel extends IChannel {
|
||||
call(command: 'click', arg: [string, number | undefined, number | undefined]): TPromise<void>;
|
||||
call(command: 'doubleClick', arg: string): TPromise<void>;
|
||||
call(command: 'setValue', 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[]>;
|
||||
call(command: 'typeInEditor', arg: [string, string]): TPromise<void>;
|
||||
call(command: 'getTerminalBuffer', arg: string): TPromise<string[]>;
|
||||
call(command: 'writeInTerminal', arg: [string, string]): TPromise<void>;
|
||||
call(command: string, arg: any): TPromise<any>;
|
||||
}
|
||||
|
||||
export class WindowDriverChannel implements IWindowDriverChannel {
|
||||
|
||||
constructor(private driver: IWindowDriver) { }
|
||||
|
||||
listen<T>(event: string): Event<T> {
|
||||
throw new Error('No event found');
|
||||
}
|
||||
|
||||
call(command: string, arg?: any): TPromise<any> {
|
||||
switch (command) {
|
||||
case 'click': return this.driver.click(arg[0], arg[1], arg[2]);
|
||||
case 'doubleClick': return this.driver.doubleClick(arg);
|
||||
case 'setValue': return this.driver.setValue(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]);
|
||||
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1]);
|
||||
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg);
|
||||
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1]);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowDriverChannelClient implements IWindowDriver {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IWindowDriverChannel) { }
|
||||
|
||||
click(selector: string, xoffset?: number, yoffset?: number): TPromise<void> {
|
||||
return this.channel.call('click', [selector, xoffset, yoffset]);
|
||||
}
|
||||
|
||||
doubleClick(selector: string): TPromise<void> {
|
||||
return this.channel.call('doubleClick', selector);
|
||||
}
|
||||
|
||||
setValue(selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('setValue', [selector, text]);
|
||||
}
|
||||
|
||||
getTitle(): TPromise<string> {
|
||||
return this.channel.call('getTitle');
|
||||
}
|
||||
|
||||
isActiveElement(selector: string): TPromise<boolean> {
|
||||
return this.channel.call('isActiveElement', selector);
|
||||
}
|
||||
|
||||
getElements(selector: string, recursive: boolean): TPromise<IElement[]> {
|
||||
return this.channel.call('getElements', [selector, recursive]);
|
||||
}
|
||||
|
||||
typeInEditor(selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('typeInEditor', [selector, text]);
|
||||
}
|
||||
|
||||
getTerminalBuffer(selector: string): TPromise<string[]> {
|
||||
return this.channel.call('getTerminalBuffer', selector);
|
||||
}
|
||||
|
||||
writeInTerminal(selector: string, text: string): TPromise<void> {
|
||||
return this.channel.call('writeInTerminal', [selector, text]);
|
||||
}
|
||||
}
|
||||
@@ -3,17 +3,16 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
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/common/driver';
|
||||
import { IPCClient } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IWindowDriver, IElement, WindowDriverChannel, WindowDriverRegistryChannelClient } from 'vs/platform/driver/node/driver';
|
||||
import { IPCClient } from 'vs/base/parts/ipc/node/ipc';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom';
|
||||
import * as electron from 'electron';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
import { Terminal } from 'vscode-xterm';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
function serializeElement(element: Element, recursive: boolean): IElement {
|
||||
const attributes = Object.create(null);
|
||||
@@ -23,7 +22,7 @@ function serializeElement(element: Element, recursive: boolean): IElement {
|
||||
attributes[attr.name] = attr.value;
|
||||
}
|
||||
|
||||
const children = [];
|
||||
const children: IElement[] = [];
|
||||
|
||||
if (recursive) {
|
||||
for (let i = 0; i < element.children.length; i++) {
|
||||
@@ -62,7 +61,7 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (!element) {
|
||||
return TPromise.wrapError(new Error('Element not found'));
|
||||
return TPromise.wrapError(new Error(`Element not found: ${selector}`));
|
||||
}
|
||||
|
||||
const { left, top } = getTopLeftOffset(element as HTMLElement);
|
||||
@@ -86,12 +85,12 @@ class WindowDriver implements IWindowDriver {
|
||||
private _click(selector: string, clickCount: number, xoffset?: number, yoffset?: number): TPromise<void> {
|
||||
return this._getElementXY(selector, xoffset, yoffset).then(({ x, y }) => {
|
||||
|
||||
const webContents = electron.remote.getCurrentWebContents();
|
||||
const webContents: electron.WebContents = (electron as any).remote.getCurrentWebContents();
|
||||
webContents.sendInputEvent({ type: 'mouseDown', x, y, button: 'left', clickCount } as any);
|
||||
|
||||
return TPromise.timeout(10).then(() => {
|
||||
return TPromise.wrap(timeout(10)).then(() => {
|
||||
webContents.sendInputEvent({ type: 'mouseUp', x, y, button: 'left', clickCount } as any);
|
||||
return TPromise.timeout(100);
|
||||
return TPromise.wrap(timeout(100));
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -100,7 +99,7 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (!element) {
|
||||
return TPromise.wrapError(new Error('Element not found'));
|
||||
return TPromise.wrapError(new Error(`Element not found: ${selector}`));
|
||||
}
|
||||
|
||||
const inputElement = element as HTMLInputElement;
|
||||
@@ -120,7 +119,7 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (element !== document.activeElement) {
|
||||
const chain = [];
|
||||
const chain: string[] = [];
|
||||
let el = document.activeElement;
|
||||
|
||||
while (el) {
|
||||
@@ -132,7 +131,7 @@ class WindowDriver implements IWindowDriver {
|
||||
el = el.parentElement;
|
||||
}
|
||||
|
||||
return TPromise.wrapError(new Error(`Active element not found. Current active element is '${chain.join(' > ')}'`));
|
||||
return TPromise.wrapError(new Error(`Active element not found. Current active element is '${chain.join(' > ')}'. Looking for ${selector}`));
|
||||
}
|
||||
|
||||
return TPromise.as(true);
|
||||
@@ -154,7 +153,7 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (!element) {
|
||||
return TPromise.wrapError(new Error('Editor not found: ' + selector));
|
||||
return TPromise.wrapError(new Error(`Editor not found: ${selector}`));
|
||||
}
|
||||
|
||||
const textarea = element as HTMLTextAreaElement;
|
||||
@@ -176,13 +175,13 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (!element) {
|
||||
return TPromise.wrapError(new Error('Terminal not found: ' + selector));
|
||||
return TPromise.wrapError(new Error(`Terminal not found: ${selector}`));
|
||||
}
|
||||
|
||||
const xterm: Terminal = (element as any).xterm;
|
||||
|
||||
if (!xterm) {
|
||||
return TPromise.wrapError(new Error('Xterm not found: ' + selector));
|
||||
return TPromise.wrapError(new Error(`Xterm not found: ${selector}`));
|
||||
}
|
||||
|
||||
const lines: string[] = [];
|
||||
@@ -198,16 +197,16 @@ class WindowDriver implements IWindowDriver {
|
||||
const element = document.querySelector(selector);
|
||||
|
||||
if (!element) {
|
||||
return TPromise.wrapError(new Error('Element not found'));
|
||||
return TPromise.wrapError(new Error(`Element not found: ${selector}`));
|
||||
}
|
||||
|
||||
const xterm: Terminal = (element as any).xterm;
|
||||
|
||||
if (!xterm) {
|
||||
return TPromise.wrapError(new Error('Xterm not found'));
|
||||
return TPromise.wrapError(new Error(`Xterm not found: ${selector}`));
|
||||
}
|
||||
|
||||
xterm._core.send(text);
|
||||
xterm._core.handler(text);
|
||||
|
||||
return TPromise.as(null);
|
||||
}
|
||||
@@ -229,11 +228,12 @@ export async function registerWindowDriver(
|
||||
const windowDriverRegistryChannel = client.getChannel('windowDriverRegistry');
|
||||
const windowDriverRegistry = new WindowDriverRegistryChannelClient(windowDriverRegistryChannel);
|
||||
|
||||
const options = await windowDriverRegistry.registerWindowDriver(windowId);
|
||||
await windowDriverRegistry.registerWindowDriver(windowId);
|
||||
// const options = await windowDriverRegistry.registerWindowDriver(windowId);
|
||||
|
||||
if (options.verbose) {
|
||||
windowDriver.openDevTools();
|
||||
}
|
||||
// if (options.verbose) {
|
||||
// windowDriver.openDevTools();
|
||||
// }
|
||||
|
||||
const disposable = toDisposable(() => windowDriverRegistry.reloadWindowDriver(windowId));
|
||||
return combinedDisposable([disposable, client]);
|
||||
|
||||
@@ -3,38 +3,20 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { TPromise } from 'vs/base/common/winjs.base';
|
||||
import { IDriver, DriverChannel, IElement, IWindowDriverChannel, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel, IWindowDriver, IDriverOptions } from 'vs/platform/driver/common/driver';
|
||||
import { IDriver, DriverChannel, IElement, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel, IWindowDriver, IDriverOptions } from 'vs/platform/driver/node/driver';
|
||||
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
|
||||
import { serve as serveNet } from 'vs/base/parts/ipc/node/ipc.net';
|
||||
import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IPCServer, IClientRouter } from 'vs/base/parts/ipc/common/ipc';
|
||||
import { IPCServer, StaticRouter } from 'vs/base/parts/ipc/node/ipc';
|
||||
import { SimpleKeybinding, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding';
|
||||
import { OS } from 'vs/base/common/platform';
|
||||
import { Emitter, toPromise } from 'vs/base/common/event';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
|
||||
// TODO@joao: bad layering!
|
||||
import { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO';
|
||||
import { ScanCodeBinding } from 'vs/workbench/services/keybinding/common/scanCode';
|
||||
import { toWinJsPromise } from 'vs/base/common/async';
|
||||
|
||||
class WindowRouter implements IClientRouter {
|
||||
|
||||
constructor(private windowId: number) { }
|
||||
|
||||
routeCall(): TPromise<string> {
|
||||
return TPromise.as(`window:${this.windowId}`);
|
||||
}
|
||||
|
||||
routeEvent(): TPromise<string> {
|
||||
return TPromise.as(`window:${this.windowId}`);
|
||||
}
|
||||
}
|
||||
import { ScanCodeBinding } from 'vs/base/common/scanCode';
|
||||
import { KeybindingParser } from 'vs/base/common/keybindingParser';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
|
||||
function isSilentKeyCode(keyCode: KeyCode) {
|
||||
return keyCode < KeyCode.KEY_0;
|
||||
@@ -54,57 +36,60 @@ export class Driver implements IDriver, IWindowDriverRegistry {
|
||||
@IWindowsMainService private windowsService: IWindowsMainService
|
||||
) { }
|
||||
|
||||
registerWindowDriver(windowId: number): TPromise<IDriverOptions> {
|
||||
async registerWindowDriver(windowId: number): Promise<IDriverOptions> {
|
||||
this.registeredWindowIds.add(windowId);
|
||||
this.reloadingWindowIds.delete(windowId);
|
||||
this.onDidReloadingChange.fire();
|
||||
return TPromise.as(this.options);
|
||||
return this.options;
|
||||
}
|
||||
|
||||
reloadWindowDriver(windowId: number): TPromise<void> {
|
||||
async reloadWindowDriver(windowId: number): Promise<void> {
|
||||
this.reloadingWindowIds.add(windowId);
|
||||
return TPromise.as(null);
|
||||
}
|
||||
|
||||
getWindowIds(): TPromise<number[]> {
|
||||
return TPromise.as(this.windowsService.getWindows()
|
||||
async getWindowIds(): Promise<number[]> {
|
||||
return this.windowsService.getWindows()
|
||||
.map(w => w.id)
|
||||
.filter(id => this.registeredWindowIds.has(id) && !this.reloadingWindowIds.has(id)));
|
||||
.filter(id => this.registeredWindowIds.has(id) && !this.reloadingWindowIds.has(id));
|
||||
}
|
||||
|
||||
capturePage(windowId: number): TPromise<string> {
|
||||
return this.whenUnfrozen(windowId).then(() => {
|
||||
const window = this.windowsService.getWindowById(windowId);
|
||||
const webContents = window.win.webContents;
|
||||
return new TPromise(c => webContents.capturePage(image => c(image.toPNG().toString('base64'))));
|
||||
});
|
||||
async capturePage(windowId: number): Promise<string> {
|
||||
await this.whenUnfrozen(windowId);
|
||||
|
||||
const window = this.windowsService.getWindowById(windowId);
|
||||
const webContents = window.win.webContents;
|
||||
const image = await new Promise<Electron.NativeImage>(c => webContents.capturePage(c));
|
||||
|
||||
return image.toPNG().toString('base64');
|
||||
}
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void> {
|
||||
return this.whenUnfrozen(windowId).then(() => {
|
||||
const window = this.windowsService.getWindowById(windowId);
|
||||
this.reloadingWindowIds.add(windowId);
|
||||
this.windowsService.reload(window);
|
||||
});
|
||||
async reloadWindow(windowId: number): Promise<void> {
|
||||
await this.whenUnfrozen(windowId);
|
||||
|
||||
const window = this.windowsService.getWindowById(windowId);
|
||||
this.reloadingWindowIds.add(windowId);
|
||||
this.windowsService.reload(window);
|
||||
}
|
||||
|
||||
dispatchKeybinding(windowId: number, keybinding: string): TPromise<void> {
|
||||
return this.whenUnfrozen(windowId).then(() => {
|
||||
const [first, second] = KeybindingIO._readUserBinding(keybinding);
|
||||
async dispatchKeybinding(windowId: number, keybinding: string): Promise<void> {
|
||||
await this.whenUnfrozen(windowId);
|
||||
|
||||
return this._dispatchKeybinding(windowId, first).then(() => {
|
||||
if (second) {
|
||||
return this._dispatchKeybinding(windowId, second);
|
||||
} else {
|
||||
return TPromise.as(null);
|
||||
}
|
||||
});
|
||||
});
|
||||
const [first, second] = KeybindingParser.parseUserBinding(keybinding);
|
||||
|
||||
if (!first) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this._dispatchKeybinding(windowId, first);
|
||||
|
||||
if (second) {
|
||||
await this._dispatchKeybinding(windowId, second);
|
||||
}
|
||||
}
|
||||
|
||||
private _dispatchKeybinding(windowId: number, keybinding: SimpleKeybinding | ScanCodeBinding): TPromise<void> {
|
||||
private async _dispatchKeybinding(windowId: number, keybinding: SimpleKeybinding | ScanCodeBinding): Promise<void> {
|
||||
if (keybinding instanceof ScanCodeBinding) {
|
||||
return TPromise.wrapError(new Error('ScanCodeBindings not supported'));
|
||||
throw new Error('ScanCodeBindings not supported');
|
||||
}
|
||||
|
||||
const window = this.windowsService.getWindowById(windowId);
|
||||
@@ -113,7 +98,7 @@ export class Driver implements IDriver, IWindowDriverRegistry {
|
||||
const resolvedKeybinding = new USLayoutResolvedKeybinding(noModifiedKeybinding, OS);
|
||||
const keyCode = resolvedKeybinding.getElectronAccelerator();
|
||||
|
||||
const modifiers = [];
|
||||
const modifiers: string[] = [];
|
||||
|
||||
if (keybinding.ctrlKey) {
|
||||
modifiers.push('ctrl');
|
||||
@@ -139,76 +124,64 @@ export class Driver implements IDriver, IWindowDriverRegistry {
|
||||
|
||||
webContents.sendInputEvent({ type: 'keyUp', keyCode, modifiers } as any);
|
||||
|
||||
return TPromise.timeout(100);
|
||||
await timeout(100);
|
||||
}
|
||||
|
||||
click(windowId: number, selector: string, xoffset?: number, yoffset?: number): TPromise<void> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.click(selector, xoffset, yoffset);
|
||||
});
|
||||
async click(windowId: number, selector: string, xoffset?: number, yoffset?: number): Promise<void> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
await windowDriver.click(selector, xoffset, yoffset);
|
||||
}
|
||||
|
||||
doubleClick(windowId: number, selector: string): TPromise<void> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.doubleClick(selector);
|
||||
});
|
||||
async doubleClick(windowId: number, selector: string): Promise<void> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
await windowDriver.doubleClick(selector);
|
||||
}
|
||||
|
||||
setValue(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.setValue(selector, text);
|
||||
});
|
||||
async setValue(windowId: number, selector: string, text: string): Promise<void> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
await windowDriver.setValue(selector, text);
|
||||
}
|
||||
|
||||
getTitle(windowId: number): TPromise<string> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.getTitle();
|
||||
});
|
||||
async getTitle(windowId: number): Promise<string> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
return await windowDriver.getTitle();
|
||||
}
|
||||
|
||||
isActiveElement(windowId: number, selector: string): TPromise<boolean> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.isActiveElement(selector);
|
||||
});
|
||||
async isActiveElement(windowId: number, selector: string): Promise<boolean> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
return await windowDriver.isActiveElement(selector);
|
||||
}
|
||||
|
||||
getElements(windowId: number, selector: string, recursive: boolean): TPromise<IElement[]> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.getElements(selector, recursive);
|
||||
});
|
||||
async getElements(windowId: number, selector: string, recursive: boolean): Promise<IElement[]> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
return await windowDriver.getElements(selector, recursive);
|
||||
}
|
||||
|
||||
typeInEditor(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.typeInEditor(selector, text);
|
||||
});
|
||||
async typeInEditor(windowId: number, selector: string, text: string): Promise<void> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
await windowDriver.typeInEditor(selector, text);
|
||||
}
|
||||
|
||||
getTerminalBuffer(windowId: number, selector: string): TPromise<string[]> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.getTerminalBuffer(selector);
|
||||
});
|
||||
async getTerminalBuffer(windowId: number, selector: string): Promise<string[]> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
return await windowDriver.getTerminalBuffer(selector);
|
||||
}
|
||||
|
||||
writeInTerminal(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return this.getWindowDriver(windowId).then(windowDriver => {
|
||||
return windowDriver.writeInTerminal(selector, text);
|
||||
});
|
||||
async writeInTerminal(windowId: number, selector: string, text: string): Promise<void> {
|
||||
const windowDriver = await this.getWindowDriver(windowId);
|
||||
await windowDriver.writeInTerminal(selector, text);
|
||||
}
|
||||
|
||||
private getWindowDriver(windowId: number): TPromise<IWindowDriver> {
|
||||
return this.whenUnfrozen(windowId).then(() => {
|
||||
const router = new WindowRouter(windowId);
|
||||
const windowDriverChannel = this.windowServer.getChannel<IWindowDriverChannel>('windowDriver', router);
|
||||
return new WindowDriverChannelClient(windowDriverChannel);
|
||||
});
|
||||
private async getWindowDriver(windowId: number): Promise<IWindowDriver> {
|
||||
await this.whenUnfrozen(windowId);
|
||||
|
||||
const id = `window:${windowId}`;
|
||||
const router = new StaticRouter(ctx => ctx === id);
|
||||
const windowDriverChannel = this.windowServer.getChannel('windowDriver', router);
|
||||
return new WindowDriverChannelClient(windowDriverChannel);
|
||||
}
|
||||
|
||||
private whenUnfrozen(windowId: number): TPromise<void> {
|
||||
return toWinJsPromise(this._whenUnfrozen(windowId));
|
||||
}
|
||||
|
||||
private async _whenUnfrozen(windowId: number): Promise<void> {
|
||||
private async whenUnfrozen(windowId: number): Promise<void> {
|
||||
while (this.reloadingWindowIds.has(windowId)) {
|
||||
await toPromise(this.onDidReloadingChange.event);
|
||||
}
|
||||
|
||||
@@ -3,10 +3,256 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import { IDriver, DriverChannelClient } from 'vs/platform/driver/common/driver';
|
||||
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';
|
||||
|
||||
export const ID = 'driverService';
|
||||
export const IDriver = createDecorator<IDriver>(ID);
|
||||
|
||||
// !! Do not remove the following START and END markers, they are parsed by the smoketest build
|
||||
|
||||
//*START
|
||||
export interface IElement {
|
||||
tagName: string;
|
||||
className: string;
|
||||
textContent: string;
|
||||
attributes: { [name: string]: string; };
|
||||
children: IElement[];
|
||||
top: number;
|
||||
left: number;
|
||||
}
|
||||
|
||||
export interface IDriver {
|
||||
_serviceBrand: any;
|
||||
|
||||
getWindowIds(): TPromise<number[]>;
|
||||
capturePage(windowId: number): TPromise<string>;
|
||||
reloadWindow(windowId: number): TPromise<void>;
|
||||
dispatchKeybinding(windowId: number, keybinding: string): TPromise<void>;
|
||||
click(windowId: number, selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise<void>;
|
||||
doubleClick(windowId: number, selector: string): TPromise<void>;
|
||||
setValue(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[]>;
|
||||
typeInEditor(windowId: number, selector: string, text: string): TPromise<void>;
|
||||
getTerminalBuffer(windowId: number, selector: string): TPromise<string[]>;
|
||||
writeInTerminal(windowId: number, selector: string, text: string): TPromise<void>;
|
||||
}
|
||||
//*END
|
||||
|
||||
export class DriverChannel implements IServerChannel {
|
||||
|
||||
constructor(private driver: IDriver) { }
|
||||
|
||||
listen<T>(_, event: string): Event<T> {
|
||||
throw new Error('No event found');
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): TPromise<any> {
|
||||
switch (command) {
|
||||
case 'getWindowIds': return this.driver.getWindowIds();
|
||||
case 'capturePage': return this.driver.capturePage(arg);
|
||||
case 'reloadWindow': return this.driver.reloadWindow(arg);
|
||||
case 'dispatchKeybinding': return this.driver.dispatchKeybinding(arg[0], arg[1]);
|
||||
case 'click': return this.driver.click(arg[0], arg[1], arg[2], arg[3]);
|
||||
case 'doubleClick': return this.driver.doubleClick(arg[0], arg[1]);
|
||||
case 'setValue': return this.driver.setValue(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]);
|
||||
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1], arg[2]);
|
||||
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg[0], arg[1]);
|
||||
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1], arg[2]);
|
||||
}
|
||||
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class DriverChannelClient implements IDriver {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IChannel) { }
|
||||
|
||||
getWindowIds(): TPromise<number[]> {
|
||||
return TPromise.wrap(this.channel.call('getWindowIds'));
|
||||
}
|
||||
|
||||
capturePage(windowId: number): TPromise<string> {
|
||||
return TPromise.wrap(this.channel.call('capturePage', windowId));
|
||||
}
|
||||
|
||||
reloadWindow(windowId: number): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('reloadWindow', windowId));
|
||||
}
|
||||
|
||||
dispatchKeybinding(windowId: number, keybinding: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('dispatchKeybinding', [windowId, keybinding]));
|
||||
}
|
||||
|
||||
click(windowId: number, selector: string, xoffset: number | undefined, yoffset: number | undefined): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('click', [windowId, selector, xoffset, yoffset]));
|
||||
}
|
||||
|
||||
doubleClick(windowId: number, selector: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('doubleClick', [windowId, selector]));
|
||||
}
|
||||
|
||||
setValue(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('setValue', [windowId, selector, text]));
|
||||
}
|
||||
|
||||
getTitle(windowId: number): TPromise<string> {
|
||||
return TPromise.wrap(this.channel.call('getTitle', [windowId]));
|
||||
}
|
||||
|
||||
isActiveElement(windowId: number, selector: string): TPromise<boolean> {
|
||||
return TPromise.wrap(this.channel.call('isActiveElement', [windowId, selector]));
|
||||
}
|
||||
|
||||
getElements(windowId: number, selector: string, recursive: boolean): TPromise<IElement[]> {
|
||||
return TPromise.wrap(this.channel.call('getElements', [windowId, selector, recursive]));
|
||||
}
|
||||
|
||||
typeInEditor(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('typeInEditor', [windowId, selector, text]));
|
||||
}
|
||||
|
||||
getTerminalBuffer(windowId: number, selector: string): TPromise<string[]> {
|
||||
return TPromise.wrap(this.channel.call('getTerminalBuffer', [windowId, selector]));
|
||||
}
|
||||
|
||||
writeInTerminal(windowId: number, selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('writeInTerminal', [windowId, selector, text]));
|
||||
}
|
||||
}
|
||||
|
||||
export interface IDriverOptions {
|
||||
verbose: boolean;
|
||||
}
|
||||
|
||||
export interface IWindowDriverRegistry {
|
||||
registerWindowDriver(windowId: number): TPromise<IDriverOptions>;
|
||||
reloadWindowDriver(windowId: number): TPromise<void>;
|
||||
}
|
||||
|
||||
export class WindowDriverRegistryChannel implements IServerChannel {
|
||||
|
||||
constructor(private registry: IWindowDriverRegistry) { }
|
||||
|
||||
listen<T>(_, event: string): Event<T> {
|
||||
throw new Error(`Event not found: ${event}`);
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): Thenable<any> {
|
||||
switch (command) {
|
||||
case 'registerWindowDriver': return this.registry.registerWindowDriver(arg);
|
||||
case 'reloadWindowDriver': return this.registry.reloadWindowDriver(arg);
|
||||
}
|
||||
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IChannel) { }
|
||||
|
||||
registerWindowDriver(windowId: number): TPromise<IDriverOptions> {
|
||||
return TPromise.wrap(this.channel.call('registerWindowDriver', windowId));
|
||||
}
|
||||
|
||||
reloadWindowDriver(windowId: number): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('reloadWindowDriver', windowId));
|
||||
}
|
||||
}
|
||||
|
||||
export interface IWindowDriver {
|
||||
click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): TPromise<void>;
|
||||
doubleClick(selector: string): TPromise<void>;
|
||||
setValue(selector: string, text: string): TPromise<void>;
|
||||
getTitle(): TPromise<string>;
|
||||
isActiveElement(selector: string): TPromise<boolean>;
|
||||
getElements(selector: string, recursive: boolean): TPromise<IElement[]>;
|
||||
typeInEditor(selector: string, text: string): TPromise<void>;
|
||||
getTerminalBuffer(selector: string): TPromise<string[]>;
|
||||
writeInTerminal(selector: string, text: string): TPromise<void>;
|
||||
}
|
||||
|
||||
export class WindowDriverChannel implements IServerChannel {
|
||||
|
||||
constructor(private driver: IWindowDriver) { }
|
||||
|
||||
listen<T>(_, event: string): Event<T> {
|
||||
throw new Error(`No event found: ${event}`);
|
||||
}
|
||||
|
||||
call(_, command: string, arg?: any): Thenable<any> {
|
||||
switch (command) {
|
||||
case 'click': return this.driver.click(arg[0], arg[1], arg[2]);
|
||||
case 'doubleClick': return this.driver.doubleClick(arg);
|
||||
case 'setValue': return this.driver.setValue(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]);
|
||||
case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1]);
|
||||
case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg);
|
||||
case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1]);
|
||||
}
|
||||
|
||||
throw new Error(`Call not found: ${command}`);
|
||||
}
|
||||
}
|
||||
|
||||
export class WindowDriverChannelClient implements IWindowDriver {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
constructor(private channel: IChannel) { }
|
||||
|
||||
click(selector: string, xoffset?: number, yoffset?: number): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('click', [selector, xoffset, yoffset]));
|
||||
}
|
||||
|
||||
doubleClick(selector: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('doubleClick', selector));
|
||||
}
|
||||
|
||||
setValue(selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('setValue', [selector, text]));
|
||||
}
|
||||
|
||||
getTitle(): TPromise<string> {
|
||||
return TPromise.wrap(this.channel.call('getTitle'));
|
||||
}
|
||||
|
||||
isActiveElement(selector: string): TPromise<boolean> {
|
||||
return TPromise.wrap(this.channel.call('isActiveElement', selector));
|
||||
}
|
||||
|
||||
getElements(selector: string, recursive: boolean): TPromise<IElement[]> {
|
||||
return TPromise.wrap(this.channel.call('getElements', [selector, recursive]));
|
||||
}
|
||||
|
||||
typeInEditor(selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('typeInEditor', [selector, text]));
|
||||
}
|
||||
|
||||
getTerminalBuffer(selector: string): TPromise<string[]> {
|
||||
return TPromise.wrap(this.channel.call('getTerminalBuffer', selector));
|
||||
}
|
||||
|
||||
writeInTerminal(selector: string, text: string): TPromise<void> {
|
||||
return TPromise.wrap(this.channel.call('writeInTerminal', [selector, text]));
|
||||
}
|
||||
}
|
||||
|
||||
export async function connect(handle: string): Promise<{ client: Client, driver: IDriver }> {
|
||||
const client = await connectNet(handle, 'driverClient');
|
||||
|
||||
Reference in New Issue
Block a user