diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index a09429f113755355848a0aea8013d7492072702d..e928613fb9bf1ce7057658d226b0388a9ca2fb3e 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -360,7 +360,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { this.toDispose.push(dom.addDisposableListener(domNode, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { let keyEvent = new StandardKeyboardEvent(e); - let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target); + let shouldPreventDefault = this.dispatchEvent(keyEvent, keyEvent.target); if (shouldPreventDefault) { keyEvent.preventDefault(); } diff --git a/src/vs/editor/standalone/test/browser/simpleServices.test.ts b/src/vs/editor/standalone/test/browser/simpleServices.test.ts index e13eab64aa9d1000a53171802e2ad8db03e9af7e..ef3756c76c8c9349b6f2e90454a3ff9e7583f90c 100644 --- a/src/vs/editor/standalone/test/browser/simpleServices.test.ts +++ b/src/vs/editor/standalone/test/browser/simpleServices.test.ts @@ -17,7 +17,7 @@ suite('StandaloneKeybindingService', () => { class TestStandaloneKeybindingService extends StandaloneKeybindingService { public testDispatch(e: IKeyboardEvent): void { - super._dispatch(e, null); + super.dispatchEvent(e, null); } } diff --git a/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts index 6c7b6705d9e38460a41aa0430fc696f4aecda152..826415b59f3d8bbfaab1c909220c49f92f6d996c 100644 --- a/src/vs/platform/driver/common/driver.ts +++ b/src/vs/platform/driver/common/driver.ts @@ -23,12 +23,14 @@ export interface IDriver { _serviceBrand: any; getWindowIds(): TPromise; getElements(windowId: number, selector: string): TPromise; + dispatchKeybinding(windowId: number, keybinding: string): TPromise; } //*END export interface IDriverChannel extends IChannel { call(command: 'getWindowIds'): TPromise; call(command: 'getElements', arg: [number, string]): TPromise; + call(command: 'dispatchKeybinding', arg: [number, string]): TPromise; call(command: string, arg: any): TPromise; } @@ -40,6 +42,7 @@ export class DriverChannel implements IDriverChannel { switch (command) { case 'getWindowIds': return this.driver.getWindowIds(); case 'getElements': return this.driver.getElements(arg[0], arg[1]); + case 'dispatchKeybinding': return this.driver.dispatchKeybinding(arg[0], arg[1]); } return undefined; @@ -59,6 +62,10 @@ export class DriverChannelClient implements IDriver { getElements(windowId: number, selector: string): TPromise { return this.channel.call('getElements', [windowId, selector]); } + + dispatchKeybinding(windowId: number, keybinding: string): TPromise { + return this.channel.call('dispatchKeybinding', [windowId, keybinding]); + } } export interface IWindowDriverRegistry { @@ -96,10 +103,12 @@ export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry export interface IWindowDriver { getElements(selector: string): TPromise; + dispatchKeybinding(keybinding: string): TPromise; } export interface IWindowDriverChannel extends IChannel { call(command: 'getElements', arg: string): TPromise; + call(command: 'dispatchKeybinding', arg: string): TPromise; call(command: string, arg: any): TPromise; } @@ -110,6 +119,7 @@ export class WindowDriverChannel implements IWindowDriverChannel { call(command: string, arg?: any): TPromise { switch (command) { case 'getElements': return this.driver.getElements(arg); + case 'dispatchKeybinding': return this.driver.dispatchKeybinding(arg); } return undefined; @@ -125,4 +135,8 @@ export class WindowDriverChannelClient implements IWindowDriver { getElements(selector: string): TPromise { return this.channel.call('getElements', selector); } + + dispatchKeybinding(keybinding: string): TPromise { + return this.channel.call('dispatchKeybinding', keybinding); + } } \ No newline at end of file diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index 55949acb636302f86aa95944a134b181c37247fc..2e6d60b0903f81a4134586028d103b0fe7dbcbb9 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -9,9 +9,53 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } 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 { KeybindingIO } from 'vs/workbench/services/keybinding/common/keybindingIO'; +import { SimpleKeybinding } from 'vs/base/common/keyCodes'; +import { ScanCodeBinding, IMMUTABLE_KEY_CODE_TO_CODE, ScanCodeUtils } from 'vs/workbench/services/keybinding/common/scanCode'; +import { IKeybindingService, IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; class WindowDriver implements IWindowDriver { + constructor( + @IKeybindingService private keybindingService: IKeybindingService + ) { } + + async dispatchKeybinding(rawKeybinding: string): TPromise { + const [first, second] = KeybindingIO._readUserBinding(rawKeybinding); + + this._dispatchKeybinding(first); + + if (second) { + this._dispatchKeybinding(second); + } + } + + private _dispatchKeybinding(keybinding: SimpleKeybinding | ScanCodeBinding): void { + if (keybinding instanceof ScanCodeBinding) { + throw new Error('ScanCodeBindings not supported'); + } + + const scanCode = IMMUTABLE_KEY_CODE_TO_CODE[keybinding.keyCode]; + const event: IKeyboardEvent = { + ctrlKey: keybinding.ctrlKey, + altKey: keybinding.altKey, + shiftKey: keybinding.shiftKey, + metaKey: keybinding.metaKey, + keyCode: keybinding.keyCode, + code: ScanCodeUtils.toString(scanCode) + }; + + this.keybindingService.dispatchEvent(event, document.activeElement); + + // console.log(keybinding); + + // const e = new KeyboardEvent('keydown', event); + // console.log('dispatching', e); + // document.activeElement.dispatchEvent(e); + // document.activeElement.dispatchEvent(new KeyboardEvent('keyup', event)); + } + async getElements(selector: string): TPromise { const query = document.querySelectorAll(selector); const result: IElement[] = []; @@ -30,8 +74,12 @@ class WindowDriver implements IWindowDriver { } } -export async function registerWindowDriver(client: IPCClient, windowId: number): TPromise { - const windowDriver = new WindowDriver(); +export async function registerWindowDriver( + client: IPCClient, + windowId: number, + instantiationService: IInstantiationService +): TPromise { + const windowDriver = instantiationService.createInstance(WindowDriver); const windowDriverChannel = new WindowDriverChannel(windowDriver); client.registerChannel('windowDriver', windowDriverChannel); diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 36bc975313599791c6c50380985859377655ea33..f456136c7774d9d219f7b819c2740308d8184073 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -6,7 +6,7 @@ 'use strict'; import { TPromise } from 'vs/base/common/winjs.base'; -import { IDriver, DriverChannel, IElement, IWindowDriverChannel, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel } from 'vs/platform/driver/common/driver'; +import { IDriver, DriverChannel, IElement, IWindowDriverChannel, WindowDriverChannelClient, IWindowDriverRegistry, WindowDriverRegistryChannel, IWindowDriver } from 'vs/platform/driver/common/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'; @@ -45,11 +45,19 @@ export class Driver implements IDriver, IWindowDriverRegistry { } getElements(windowId: number, selector: string): TPromise { + const windowDriver = this.getWindowDriver(windowId); + return windowDriver.getElements(selector); + } + + dispatchKeybinding(windowId: number, keybinding: string): TPromise { + const windowDriver = this.getWindowDriver(windowId); + return windowDriver.dispatchKeybinding(keybinding); + } + + private getWindowDriver(windowId: number): IWindowDriver { const router = new WindowRouter(windowId); const windowDriverChannel = this.windowServer.getChannel('windowDriver', router); - const windowDriver = new WindowDriverChannelClient(windowDriverChannel); - - return windowDriver.getElements(selector); + return new WindowDriverChannelClient(windowDriverChannel); } } diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 8e41b28534742d700a4b6c4d0185ba42efb190a7..abf8f7246f652d600c23d8fda421b7c41995d609 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -114,7 +114,7 @@ export abstract class AbstractKeybindingService implements IKeybindingService { return this._getResolver().resolve(contextValue, currentChord, firstPart); } - protected _dispatch(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean { + dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean { let shouldPreventDefault = false; const keybinding = this.resolveKeyboardEvent(e); diff --git a/src/vs/platform/keybinding/common/keybinding.ts b/src/vs/platform/keybinding/common/keybinding.ts index c491ec7a8d0bce4480c2affe3638fc2571ec4a8a..dde18ad1da3637bc28bee46fecb91fcb838fa0f9 100644 --- a/src/vs/platform/keybinding/common/keybinding.ts +++ b/src/vs/platform/keybinding/common/keybinding.ts @@ -77,5 +77,10 @@ export interface IKeybindingService { getKeybindings(): ResolvedKeybindingItem[]; customKeybindingsCount(): number; + + /** + * For simulation purposes (eg, smoke test) + */ + dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean; } diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 44ea5de8c5d77e7fc0839bb853312058b383c24a..032e9138c9c179749bf11f6caa647e86b0f837d2 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -70,7 +70,7 @@ suite('AbstractKeybindingService', () => { public testDispatch(kb: number): boolean { const keybinding = createSimpleKeybinding(kb, OS); - return this._dispatch({ + return this.dispatchEvent({ ctrlKey: keybinding.ctrlKey, shiftKey: keybinding.shiftKey, altKey: keybinding.altKey, diff --git a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts index 99c88c4fa06691ee6c4dacdaf220475e73a3275a..8a44c7bd8db9c11664db4bef88107bdd9c2f9ccb 100644 --- a/src/vs/platform/keybinding/test/common/mockKeybindingService.ts +++ b/src/vs/platform/keybinding/test/common/mockKeybindingService.ts @@ -120,4 +120,8 @@ export class MockKeybindingService implements IKeybindingService { public softDispatch(keybinding: IKeyboardEvent, target: IContextKeyServiceTarget): IResolveResult { return null; } + + dispatchEvent(e: IKeyboardEvent, target: IContextKeyServiceTarget): boolean { + return false; + } } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index e2312c32a6203a7af25356b2f3f27e794b1c0a4f..932e9288f4305ff909bce66f36f8e04f46504bd7 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -95,7 +95,6 @@ import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService'; import { DialogChannel } from 'vs/platform/dialogs/common/dialogIpc'; import { EventType, addDisposableListener, addClass, getClientArea } from 'vs/base/browser/dom'; -import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; /** * Services that we require for the Shell @@ -140,7 +139,7 @@ export class WorkbenchShell { private configuration: IWindowConfiguration; private workbench: Workbench; - constructor(container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, mainProcessClient: IPCClient, configuration: IWindowConfiguration) { + constructor(container: HTMLElement, coreServices: ICoreServices, mainProcessServices: ServiceCollection, private mainProcessClient: IPCClient, configuration: IWindowConfiguration) { this.container = container; this.configuration = configuration; @@ -156,11 +155,6 @@ export class WorkbenchShell { this.toUnbind = []; this.previousErrorTime = 0; - - if (coreServices.environmentService.driverHandle) { - registerWindowDriver(mainProcessClient, configuration.windowId) - .then(disposable => this.toUnbind.push(disposable)); - } } private createContents(parent: HTMLElement): HTMLElement { @@ -195,7 +189,7 @@ export class WorkbenchShell { private createWorkbench(instantiationService: IInstantiationService, serviceCollection: ServiceCollection, parent: HTMLElement, workbenchContainer: HTMLElement): Workbench { try { - const workbench = instantiationService.createInstance(Workbench, parent, workbenchContainer, this.configuration, serviceCollection, this.lifecycleService); + const workbench = instantiationService.createInstance(Workbench, parent, workbenchContainer, this.configuration, serviceCollection, this.lifecycleService, this.mainProcessClient); // Set lifecycle phase to `Restoring` this.lifecycleService.phase = LifecyclePhase.Restoring; diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index e4e9cc79e7f6cae2c1abc79f0fa64d5581127163..d799f2c7136c22aa839edef1f1208854539cce35 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -106,6 +106,8 @@ import { NotificationsAlerts } from 'vs/workbench/browser/parts/notifications/no import { NotificationsStatus } from 'vs/workbench/browser/parts/notifications/notificationsStatus'; import { registerNotificationCommands } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { NotificationsToasts } from 'vs/workbench/browser/parts/notifications/notificationsToasts'; +import { IPCClient } from 'vs/base/parts/ipc/common/ipc'; +import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); export const InZenModeContext = new RawContextKey('inZenMode', false); @@ -231,9 +233,10 @@ export class Workbench implements IPartService { constructor( parent: HTMLElement, container: HTMLElement, - configuration: IWindowConfiguration, + private configuration: IWindowConfiguration, serviceCollection: ServiceCollection, private lifecycleService: LifecycleService, + private mainProcessClient: IPCClient, @IInstantiationService private instantiationService: IInstantiationService, @IWorkspaceContextService private contextService: IWorkspaceContextService, @IStorageService private storageService: IStorageService, @@ -318,6 +321,12 @@ export class Workbench implements IPartService { // Workbench Layout this.createWorkbenchLayout(); + // Driver + if (this.environmentService.driverHandle) { + registerWindowDriver(this.mainProcessClient, this.configuration.windowId, this.instantiationService) + .then(disposable => this.toUnbind.push(disposable)); + } + // Restore Parts return this.restoreParts(); } diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index 94cce17a1d0d5e6425a8ed93030a772c1ec4aeeb..53a383766dfcfffaa330b0adf76d40c7c4439934 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -313,7 +313,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { this.toDispose.push(dom.addDisposableListener(windowElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { let keyEvent = new StandardKeyboardEvent(e); - let shouldPreventDefault = this._dispatch(keyEvent, keyEvent.target); + let shouldPreventDefault = this.dispatchEvent(keyEvent, keyEvent.target); if (shouldPreventDefault) { keyEvent.preventDefault(); } diff --git a/test/smoke/src/api.ts b/test/smoke/src/api.ts index b6d29b07f4f1a780224617c31be1eab70a8df5e0..a2f8b5ce21dd15a9a3ec27904d11902a007231ca 100644 --- a/test/smoke/src/api.ts +++ b/test/smoke/src/api.ts @@ -11,7 +11,7 @@ export class API { // waitFor calls should not take more than 200 * 100 = 20 seconds to complete, excluding // the time it takes for the actual retry call to complete private retryCount: number; - private readonly retryDuration = 100; // in milliseconds + private readonly retryDuration = 1000; // in milliseconds constructor( private driver: Driver, @@ -21,8 +21,8 @@ export class API { this.retryCount = (waitTime * 1000) / this.retryDuration; } - keys(keys: string[]): Promise { - return this.driver.keys(keys); + dispatchKeybinding(keybinding: string): Promise { + return this.driver.dispatchKeybinding(keybinding); } waitForTextContent(selector: string, textContent?: string, accept?: (result: string) => boolean): Promise { diff --git a/test/smoke/src/areas/debug/debug.ts b/test/smoke/src/areas/debug/debug.ts index 67d4224e15f8b82fffc18bd7319cff42fc13cb64..b346f7395c98b8ee0912ea0e828793ec1b664036 100644 --- a/test/smoke/src/areas/debug/debug.ts +++ b/test/smoke/src/areas/debug/debug.ts @@ -120,7 +120,7 @@ export class Debug extends Viewlet { // Wait for the keys to be picked up by the editor model such that repl evalutes what just got typed await this.editor.waitForEditorContents('debug:input', s => s.indexOf(text) >= 0); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); await this.api.waitForElement(CONSOLE_INPUT_OUTPUT); await this.api.waitFor(async () => { const result = await this.getConsoleOutput(); diff --git a/test/smoke/src/areas/editor/editor.ts b/test/smoke/src/areas/editor/editor.ts index 26f6e2ed8eb5a3dac90d50ca9b655e92cc4d6fb9..74486d947b31856054db8ba17645109a299653b1 100644 --- a/test/smoke/src/areas/editor/editor.ts +++ b/test/smoke/src/areas/editor/editor.ts @@ -34,7 +34,7 @@ export class Editor { await this.api.waitForActiveElement(RENAME_INPUT); await this.api.setValue(RENAME_INPUT, to); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); } async gotoDefinition(term: string, line: number): Promise { diff --git a/test/smoke/src/areas/editor/peek.ts b/test/smoke/src/areas/editor/peek.ts index 5d68eb38c1b655e7f4c2ca7ac05367c3f6998feb..fe094cdb68379be2f51460e70d66dd356e3957b9 100644 --- a/test/smoke/src/areas/editor/peek.ts +++ b/test/smoke/src/areas/editor/peek.ts @@ -34,7 +34,7 @@ export class References { } async close(): Promise { - await this.api.keys(['Escape', 'NULL']); + await this.api.dispatchKeybinding('escape'); await this.api.waitForElement(References.REFERENCES_WIDGET, element => !element); } } \ No newline at end of file diff --git a/test/smoke/src/areas/explorer/explorer.test.ts b/test/smoke/src/areas/explorer/explorer.test.ts index 9829cff95f84b1d140be81f418b369d1679d7611..a18c7ec6f0c3825f9ab8bd796b42a90fd5a5ed61 100644 --- a/test/smoke/src/areas/explorer/explorer.test.ts +++ b/test/smoke/src/areas/explorer/explorer.test.ts @@ -25,7 +25,7 @@ export function setup() { await app.workbench.quickopen.openQuickOpen('.js'); await app.workbench.quickopen.waitForQuickOpenElements(names => expectedNames.every(n => names.some(m => n === m))); - await app.api.keys(['Escape', 'NULL']); + await app.api.dispatchKeybinding('escape'); }); it('quick open respects fuzzy matching', async function () { @@ -38,7 +38,7 @@ export function setup() { await app.workbench.quickopen.openQuickOpen('a.s'); await app.workbench.quickopen.waitForQuickOpenElements(names => expectedNames.every(n => names.some(m => n === m))); - await app.api.keys(['Escape', 'NULL']); + await app.api.dispatchKeybinding('escape'); }); }); } \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/keybindings.ts b/test/smoke/src/areas/preferences/keybindings.ts index ef50ff850dc1326e8880b712d0f4d2bd39a80592..014dff290a3978eba3bf8dd6915c303e3235a3bf 100644 --- a/test/smoke/src/areas/preferences/keybindings.ts +++ b/test/smoke/src/areas/preferences/keybindings.ts @@ -12,7 +12,7 @@ export class KeybindingsEditor { constructor(private api: API, private commands: Commands) { } - async updateKeybinding(command: string, keys: string[], ariaLabel: string): Promise { + async updateKeybinding(command: string, keybinding: string, ariaLabel: string): Promise { await this.commands.runCommand('workbench.action.openGlobalKeybindings'); await this.api.waitForActiveElement(SEARCH_INPUT); await this.api.setValue(SEARCH_INPUT, command); @@ -23,7 +23,8 @@ export class KeybindingsEditor { await this.api.waitAndClick('div[aria-label="Keybindings"] .monaco-list-row.keybinding-item .action-item .icon.add'); await this.api.waitForElement('.defineKeybindingWidget .monaco-inputbox.synthetic-focus'); - await this.api.keys([...keys, 'NULL', 'Enter', 'NULL']); + await this.api.dispatchKeybinding(keybinding); + await this.api.dispatchKeybinding('enter'); await this.api.waitForElement(`div[aria-label="Keybindings"] div[aria-label="Keybinding is ${ariaLabel}."]`); } } \ No newline at end of file diff --git a/test/smoke/src/areas/preferences/preferences.test.ts b/test/smoke/src/areas/preferences/preferences.test.ts index 8d59aa7799e6d46b276d15b04d2a19e154d74482..fc1dccb8d6d36a32caada9b7eaf6e5880c621d63 100644 --- a/test/smoke/src/areas/preferences/preferences.test.ts +++ b/test/smoke/src/areas/preferences/preferences.test.ts @@ -32,9 +32,9 @@ export function setup() { const app = this.app as SpectronApplication; assert.ok(await app.workbench.activitybar.getActivityBar(ActivityBarPosition.LEFT), 'Activity bar should be positioned on the left.'); - await app.workbench.keybindingsEditor.updateKeybinding('workbench.action.toggleSidebarPosition', ['Control', 'u'], 'Control+U'); + await app.workbench.keybindingsEditor.updateKeybinding('workbench.action.toggleSidebarPosition', 'ctrl+u', 'Control+U'); - await app.api.keys(['Control', 'u', 'NULL']); + await app.api.dispatchKeybinding('ctrl+u'); assert.ok(await app.workbench.activitybar.getActivityBar(ActivityBarPosition.RIGHT), 'Activity bar was not moved to right after toggling its position.'); }); diff --git a/test/smoke/src/areas/preferences/settings.ts b/test/smoke/src/areas/preferences/settings.ts index 97182736c5a285cf8f74ad036cfba4d31a674809..915af0873eab3a84be0218345a15decf1ebc62fb 100644 --- a/test/smoke/src/areas/preferences/settings.ts +++ b/test/smoke/src/areas/preferences/settings.ts @@ -27,11 +27,10 @@ export class SettingsEditor { await this.api.waitAndClick(SEARCH_INPUT); await this.api.waitForActiveElement(SEARCH_INPUT); - await this.api.keys(['ArrowDown', 'NULL']); + await this.api.dispatchKeybinding('down'); await this.api.waitForActiveElement(EDITOR); - await this.api.keys(['ArrowRight', 'NULL']); - + await this.api.dispatchKeybinding('right'); await this.editor.waitForTypeInEditor('settings.json', `"${setting}": ${value}`, '.editable-preferences-editor-container'); await this.editors.saveOpenedFile(); } diff --git a/test/smoke/src/areas/quickopen/quickopen.ts b/test/smoke/src/areas/quickopen/quickopen.ts index f379d39824739765229e74a51b58a5d2dbbfaa2c..a4a14ee2cf35b91d0d251bd484a1dca93512694e 100644 --- a/test/smoke/src/areas/quickopen/quickopen.ts +++ b/test/smoke/src/areas/quickopen/quickopen.ts @@ -36,7 +36,7 @@ export class QuickOpen { await this.openQuickOpen(fileName); await this.waitForQuickOpenElements(names => names.some(n => n === fileName)); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); await this.editors.waitForActiveTab(fileName); await this.editors.waitForEditorFocus(fileName); } @@ -51,16 +51,16 @@ export class QuickOpen { async submit(text: string): Promise { await this.api.setValue(QuickOpen.QUICK_OPEN_INPUT, text); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); await this.waitForQuickOpenClosed(); } async selectQuickOpenElement(index: number): Promise { await this.waitForQuickOpenOpened(); for (let from = 0; from < index; from++) { - await this.api.keys(['ArrowDown', 'NULL']); + await this.api.dispatchKeybinding('down'); } - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); await this.waitForQuickOpenClosed(); } diff --git a/test/smoke/src/areas/search/search.ts b/test/smoke/src/areas/search/search.ts index f0fed76a813e2738fffb90ebd2f425a5c479898a..3976d4e64c67759a8624a0fa8f062237c7ecd177 100644 --- a/test/smoke/src/areas/search/search.ts +++ b/test/smoke/src/areas/search/search.ts @@ -33,7 +33,7 @@ export class Search extends Viewlet { await this.api.waitAndClick(INPUT); await this.api.waitForActiveElement(INPUT); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); await this.api.waitForElement(`${VIEWLET} .messages[aria-hidden="false"]`); } diff --git a/test/smoke/src/areas/terminal/terminal.ts b/test/smoke/src/areas/terminal/terminal.ts index 7dabb26e62785dc2f7962c9a3792f8d4245fd33a..231a90b5bfa64371ab4a52d91e0a4ae9296e73ab 100644 --- a/test/smoke/src/areas/terminal/terminal.ts +++ b/test/smoke/src/areas/terminal/terminal.ts @@ -28,7 +28,7 @@ export class Terminal { async runCommand(commandText: string): Promise { // TODO@Tyriar fix this. we should not use type but setValue // await this.spectron.client.type(commandText); - await this.api.keys(['Enter', 'NULL']); + await this.api.dispatchKeybinding('enter'); } async waitForTerminalText(fn: (text: string[]) => boolean, timeOutDescription: string = 'Getting Terminal Text'): Promise { diff --git a/test/smoke/src/areas/workbench/workbench.ts b/test/smoke/src/areas/workbench/workbench.ts index c87ea5a779a532c54168d1454b9e0e46951f8470..01760d509a0da0ea916edf5aa05cea64146ab95d 100644 --- a/test/smoke/src/areas/workbench/workbench.ts +++ b/test/smoke/src/areas/workbench/workbench.ts @@ -68,32 +68,7 @@ export class Workbench implements Commands { return; } - const keys: string = binding.key; - let keysToPress: string[] = []; - - const chords = keys.split(' '); - chords.forEach((chord) => { - const keys = chord.split('+'); - keys.forEach((key) => keysToPress.push(this.transliterate(key))); - keysToPress.push('NULL'); - }); - - return this.api.keys(keysToPress); - } - - /** - * Transliterates key names from keybindings file to WebdriverIO keyboard actions defined in: - * https://w3c.github.io/webdriver/webdriver-spec.html#keyboard-actions - */ - private transliterate(key: string): string { - switch (key) { - case 'ctrl': - return 'Control'; - case 'cmd': - return 'Meta'; - default: - return key.length === 1 ? key : key.charAt(0).toUpperCase() + key.slice(1); - } + return this.api.dispatchKeybinding(binding.key); } } diff --git a/test/smoke/src/driver.ts b/test/smoke/src/driver.ts index 00789e1abf6e70ed90f45e29d57c47e6fef35ec0..b3f0e72c77f48222c55571f35627881b0bc20536 100644 --- a/test/smoke/src/driver.ts +++ b/test/smoke/src/driver.ts @@ -13,7 +13,7 @@ export interface Element { } export interface Driver { - keys(keys: string[]): Promise; + dispatchKeybinding(keybinding: string): Promise; click(selector: string, xoffset?: number, yoffset?: number): Promise; doubleClick(selector: string): Promise; move(selector: string): Promise; @@ -32,13 +32,8 @@ export class SpectronDriver implements Driver { private verbose: boolean ) { } - keys(keys: string[]): Promise { - if (this.verbose) { - console.log('- keys:', keys); - } - - this.spectronClient.keys(keys); - return Promise.resolve(); + dispatchKeybinding(keybinding: string): Promise { + return Promise.reject(new Error('not implemented')); } async click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise { @@ -147,12 +142,13 @@ export class CodeDriver implements Driver { return this._activeWindowId; } - keys(keys: string[]): Promise { + async dispatchKeybinding(keybinding: string): Promise { if (this.verbose) { - console.log('- keys:', keys); + console.log('- dispatchKeybinding:', keybinding); } - throw new Error('Method not implemented.'); + const windowId = await this.getWindowId(); + await this.driver.dispatchKeybinding(windowId, keybinding); } click(selector: string, xoffset?: number | undefined, yoffset?: number | undefined): Promise { diff --git a/test/smoke/src/vscode/driver.d.ts b/test/smoke/src/vscode/driver.d.ts index d405e1181a68a6f5450bfdaad317f1cbfdc4584c..dce79062e31e8350e20ad89e760dc12792fdf892 100644 --- a/test/smoke/src/vscode/driver.d.ts +++ b/test/smoke/src/vscode/driver.d.ts @@ -13,6 +13,7 @@ export interface IDriver { _serviceBrand: any; getWindowIds(): Promise; getElements(windowId: number, selector: string): Promise; + dispatchKeybinding(windowId: number, keybinding: string): Promise; } export interface IDisposable {