From 44e5ca3db810ad6b0186ad5cbc95adae70948b54 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 13 Dec 2019 16:28:25 -0800 Subject: [PATCH] docs: api.d.ts and types.d.ts All api interfaces and types live in these two files. Interfaces and selected types are exported from api.d.ts. --- src/api.d.ts | 54 +++++++++++++++++++++++++ src/api.ts | 10 ----- src/chromium/FrameManager.ts | 2 +- src/chromium/Input.ts | 13 +++--- src/chromium/NetworkManager.ts | 13 +++--- src/dom.ts | 18 ++++----- src/firefox/FrameManager.ts | 2 +- src/firefox/Input.ts | 17 ++++---- src/firefox/NetworkManager.ts | 9 +++-- src/frames.ts | 51 ++++++++++++----------- src/helper.ts | 14 +++++++ src/input.ts | 74 ++++++++++++---------------------- src/network.ts | 29 ++++++------- src/page.ts | 16 ++++---- src/{types.ts => types.d.ts} | 46 +++++++++++++++------ src/webkit/FrameManager.ts | 2 +- src/webkit/Input.ts | 15 +++---- src/webkit/NetworkManager.ts | 9 +++-- tsconfig.json | 2 +- 19 files changed, 226 insertions(+), 170 deletions(-) create mode 100644 src/api.d.ts delete mode 100644 src/api.ts rename src/{types.ts => types.d.ts} (75%) diff --git a/src/api.d.ts b/src/api.d.ts new file mode 100644 index 0000000000..18deb0b238 --- /dev/null +++ b/src/api.d.ts @@ -0,0 +1,54 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import * as types from './types'; + +export type Point = types.Point; +export type HttpHeaders = types.HttpHeaders; + +export interface Keyboard { + down(key: string, options?: { text?: string }): Promise; + press(key: string, options?: { text?: string, delay?: number }): Promise; + sendCharacters(text: string): Promise; + type(text: string, options?: { delay?: number }): Promise; + up(key: string): Promise; +} + +export interface Mouse { + move(x: number, y: number, options?: { steps?: number }): Promise; + down(options?: { button?: types.MouseButton, clickCount?: number }): Promise; + up(options?: { button?: types.MouseButton, clickCount?: number }): Promise; + click(x: number, y: number, options?: types.ClickOptions): Promise; + dblclick(x: number, y: number, options?: types.DoubleClickOptions): Promise; + tripleclick(x: number, y: number, options?: types.TripleClickOptions): Promise; +} + +export interface Request { + url(): string; + resourceType(): string; + method(): string; + postData(): string | undefined; + headers(): types.HttpHeaders; + isNavigationRequest(): boolean; + redirectChain(): Request[]; + failure(): { errorText: string; } | null; + response(): Response | null; + frame(): Frame | null; +} + +export interface Response { + request(): Request; + url(): string; + ok(): boolean; + status(): number; + statusText(): string; + headers(): types.HttpHeaders; + buffer(): Promise; + text(): Promise; + json(): Promise; + remoteAddress(): types.NetworkRemoteAddress; + frame(): Frame | null; +} + +export interface Frame { +} diff --git a/src/api.ts b/src/api.ts deleted file mode 100644 index bfceefe31c..0000000000 --- a/src/api.ts +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. - -import * as chromium from './chromium/api'; -import * as firefox from './firefox/api'; -import * as webkit from './webkit/api'; - -export const Chromium = chromium; -export const Firefox = firefox; -export const WebKit = webkit; diff --git a/src/chromium/FrameManager.ts b/src/chromium/FrameManager.ts index 3fca1061a8..dfc1790200 100644 --- a/src/chromium/FrameManager.ts +++ b/src/chromium/FrameManager.ts @@ -425,7 +425,7 @@ export class FrameManager extends EventEmitter implements PageDelegate { this._page._onFileChooserOpened(handle); } - setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise { + setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise { return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders); } diff --git a/src/chromium/Input.ts b/src/chromium/Input.ts index 6cffc4d109..4432b3c787 100644 --- a/src/chromium/Input.ts +++ b/src/chromium/Input.ts @@ -16,9 +16,10 @@ */ import * as input from '../input'; +import * as types from '../types'; import { CDPSession } from './Connection'; -function toModifiersMask(modifiers: Set): number { +function toModifiersMask(modifiers: Set): number { let mask = 0; if (modifiers.has('Alt')) mask |= 1; @@ -38,7 +39,7 @@ export class RawKeyboardImpl implements input.RawKeyboard { this._client = client; } - async keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise { + async keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise { await this._client.send('Input.dispatchKeyEvent', { type: text ? 'keyDown' : 'rawKeyDown', modifiers: toModifiersMask(modifiers), @@ -53,7 +54,7 @@ export class RawKeyboardImpl implements input.RawKeyboard { }); } - async keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise { + async keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise { await this._client.send('Input.dispatchKeyEvent', { type: 'keyUp', modifiers: toModifiersMask(modifiers), @@ -76,7 +77,7 @@ export class RawMouseImpl implements input.RawMouse { this._client = client; } - async move(x: number, y: number, button: input.Button | 'none', buttons: Set, modifiers: Set): Promise { + async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set, modifiers: Set): Promise { await this._client.send('Input.dispatchMouseEvent', { type: 'mouseMoved', button, @@ -86,7 +87,7 @@ export class RawMouseImpl implements input.RawMouse { }); } - async down(x: number, y: number, button: input.Button, buttons: Set, modifiers: Set, clickCount: number): Promise { + async down(x: number, y: number, button: types.MouseButton, buttons: Set, modifiers: Set, clickCount: number): Promise { await this._client.send('Input.dispatchMouseEvent', { type: 'mousePressed', button, @@ -97,7 +98,7 @@ export class RawMouseImpl implements input.RawMouse { }); } - async up(x: number, y: number, button: input.Button, buttons: Set, modifiers: Set, clickCount: number): Promise { + async up(x: number, y: number, button: types.MouseButton, buttons: Set, modifiers: Set, clickCount: number): Promise { await this._client.send('Input.dispatchMouseEvent', { type: 'mouseReleased', button, diff --git a/src/chromium/NetworkManager.ts b/src/chromium/NetworkManager.ts index 3da800b001..0b5544abdc 100644 --- a/src/chromium/NetworkManager.ts +++ b/src/chromium/NetworkManager.ts @@ -22,6 +22,7 @@ import { assert, debugError, helper } from '../helper'; import { Protocol } from './protocol'; import * as network from '../network'; import * as frames from '../frames'; +import * as types from '../types'; export const NetworkManagerEvents = { Request: Symbol('Events.NetworkManager.Request'), @@ -36,7 +37,7 @@ export class NetworkManager extends EventEmitter { private _frameManager: FrameManager; private _requestIdToRequest = new Map(); private _requestIdToRequestWillBeSentEvent = new Map(); - private _extraHTTPHeaders: network.Headers = {}; + private _extraHTTPHeaders: types.HttpHeaders = {}; private _offline = false; private _credentials: {username: string, password: string} | null = null; private _attemptedAuthentications = new Set(); @@ -70,7 +71,7 @@ export class NetworkManager extends EventEmitter { await this._updateProtocolRequestInterception(); } - async setExtraHTTPHeaders(extraHTTPHeaders: network.Headers) { + async setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders) { this._extraHTTPHeaders = {}; for (const key of Object.keys(extraHTTPHeaders)) { const value = extraHTTPHeaders[key]; @@ -80,7 +81,7 @@ export class NetworkManager extends EventEmitter { await this._client.send('Network.setExtraHTTPHeaders', { headers: this._extraHTTPHeaders }); } - extraHTTPHeaders(): network.Headers { + extraHTTPHeaders(): types.HttpHeaders { return Object.assign({}, this._extraHTTPHeaders); } @@ -204,7 +205,7 @@ export class NetworkManager extends EventEmitter { } _createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): network.Response { - const remoteAddress: network.RemoteAddress = { ip: responsePayload.remoteIPAddress, port: responsePayload.remotePort }; + const remoteAddress: types.NetworkRemoteAddress = { ip: responsePayload.remoteIPAddress, port: responsePayload.remotePort }; const getResponseBody = async () => { const response = await this._client.send('Network.getResponseBody', { requestId: request._requestId }); return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8'); @@ -393,8 +394,8 @@ function headersArray(headers: { [s: string]: string; }): { name: string; value: return result; } -function headersObject(headers: Protocol.Network.Headers): network.Headers { - const result: network.Headers = {}; +function headersObject(headers: Protocol.Network.Headers): types.HttpHeaders { + const result: types.HttpHeaders = {}; for (const key of Object.keys(headers)) result[key.toLowerCase()] = headers[key]; return result; diff --git a/src/dom.ts b/src/dom.ts index 53951fe832..ba18825d79 100644 --- a/src/dom.ts +++ b/src/dom.ts @@ -111,7 +111,7 @@ export class FrameExecutionContext extends js.ExecutionContext { _$eval: types.$Eval = async (selector, pageFunction, ...args) => { const elementHandle = await this._$(selector); if (!elementHandle) - throw new Error(`Error: failed to find element matching selector "${types.selectorToString(selector)}"`); + throw new Error(`Error: failed to find element matching selector "${helper.selectorToString(selector)}"`); const result = await elementHandle.evaluate(pageFunction, ...args as any); await elementHandle.dispose(); return result; @@ -279,9 +279,9 @@ export class ElementHandle extends js.JSHandle { return { point, scrollX, scrollY }; } - async _performPointerAction(action: (point: types.Point) => Promise, options?: input.PointerActionOptions): Promise { + async _performPointerAction(action: (point: types.Point) => Promise, options?: types.PointerActionOptions): Promise { const point = await this._ensurePointerActionPoint(options ? options.relativePoint : undefined); - let restoreModifiers: input.Modifier[] | undefined; + let restoreModifiers: types.ModifierKey[] | undefined; if (options && options.modifiers) restoreModifiers = await this._page.keyboard._ensureModifiers(options.modifiers); await action(point); @@ -289,23 +289,23 @@ export class ElementHandle extends js.JSHandle { await this._page.keyboard._ensureModifiers(restoreModifiers); } - hover(options?: input.PointerActionOptions): Promise { + hover(options?: types.PointerActionOptions): Promise { return this._performPointerAction(point => this._page.mouse.move(point.x, point.y), options); } - click(options?: input.ClickOptions): Promise { + click(options?: types.ClickOptions): Promise { return this._performPointerAction(point => this._page.mouse.click(point.x, point.y, options), options); } - dblclick(options?: input.MultiClickOptions): Promise { + dblclick(options?: types.DoubleClickOptions): Promise { return this._performPointerAction(point => this._page.mouse.dblclick(point.x, point.y, options), options); } - tripleclick(options?: input.MultiClickOptions): Promise { + tripleclick(options?: types.TripleClickOptions): Promise { return this._performPointerAction(point => this._page.mouse.tripleclick(point.x, point.y, options), options); } - async select(...values: (string | ElementHandle | input.SelectOption)[]): Promise { + async select(...values: (string | ElementHandle | types.SelectOption)[]): Promise { const options = values.map(value => typeof value === 'object' ? value : { value }); for (const option of options) { if (option instanceof ElementHandle) @@ -369,7 +369,7 @@ export class ElementHandle extends js.JSHandle { } private _scopedSelector(selector: string | types.Selector): string | ScopedSelector { - selector = types.clearSelector(selector); + selector = helper.clearSelector(selector); if (helper.isString(selector)) selector = { selector }; return { scope: this, selector: selector.selector, visible: selector.visible }; diff --git a/src/firefox/FrameManager.ts b/src/firefox/FrameManager.ts index 8567355dd0..c7fc659cbd 100644 --- a/src/firefox/FrameManager.ts +++ b/src/firefox/FrameManager.ts @@ -296,7 +296,7 @@ export class FrameManager extends EventEmitter implements PageDelegate { throw error; } - setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise { + setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise { return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders); } diff --git a/src/firefox/Input.ts b/src/firefox/Input.ts index 65aad5295f..2c679450f2 100644 --- a/src/firefox/Input.ts +++ b/src/firefox/Input.ts @@ -17,8 +17,9 @@ import { JugglerSession } from './Connection'; import * as input from '../input'; +import * as types from '../types'; -function toModifiersMask(modifiers: Set): number { +function toModifiersMask(modifiers: Set): number { let mask = 0; if (modifiers.has('Alt')) mask |= 1; @@ -31,7 +32,7 @@ function toModifiersMask(modifiers: Set): number { return mask; } -function toButtonNumber(button: input.Button): number { +function toButtonNumber(button: types.MouseButton): number { if (button === 'left') return 0; if (button === 'middle') @@ -40,7 +41,7 @@ function toButtonNumber(button: input.Button): number { return 2; } -function toButtonsMask(buttons: Set): number { +function toButtonsMask(buttons: Set): number { let mask = 0; if (buttons.has('left')) mask |= 1; @@ -58,7 +59,7 @@ export class RawKeyboardImpl implements input.RawKeyboard { this._client = client; } - async keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise { + async keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise { if (code === 'MetaLeft') code = 'OSLeft'; if (code === 'MetaRight') @@ -73,7 +74,7 @@ export class RawKeyboardImpl implements input.RawKeyboard { }); } - async keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise { + async keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise { if (code === 'MetaLeft') code = 'OSLeft'; if (code === 'MetaRight') @@ -100,7 +101,7 @@ export class RawMouseImpl implements input.RawMouse { this._client = client; } - async move(x: number, y: number, button: input.Button | 'none', buttons: Set, modifiers: Set): Promise { + async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set, modifiers: Set): Promise { await this._client.send('Page.dispatchMouseEvent', { type: 'mousemove', button: 0, @@ -111,7 +112,7 @@ export class RawMouseImpl implements input.RawMouse { }); } - async down(x: number, y: number, button: input.Button, buttons: Set, modifiers: Set, clickCount: number): Promise { + async down(x: number, y: number, button: types.MouseButton, buttons: Set, modifiers: Set, clickCount: number): Promise { await this._client.send('Page.dispatchMouseEvent', { type: 'mousedown', button: toButtonNumber(button), @@ -123,7 +124,7 @@ export class RawMouseImpl implements input.RawMouse { }); } - async up(x: number, y: number, button: input.Button, buttons: Set, modifiers: Set, clickCount: number): Promise { + async up(x: number, y: number, button: types.MouseButton, buttons: Set, modifiers: Set, clickCount: number): Promise { await this._client.send('Page.dispatchMouseEvent', { type: 'mouseup', button: toButtonNumber(button), diff --git a/src/firefox/NetworkManager.ts b/src/firefox/NetworkManager.ts index 09a56ba4f7..cf3954d4ae 100644 --- a/src/firefox/NetworkManager.ts +++ b/src/firefox/NetworkManager.ts @@ -21,6 +21,7 @@ import { JugglerSession } from './Connection'; import { FrameManager } from './FrameManager'; import * as network from '../network'; import * as frames from '../frames'; +import * as types from '../types'; export const NetworkManagerEvents = { RequestFailed: Symbol('NetworkManagerEvents.RequestFailed'), @@ -54,7 +55,7 @@ export class NetworkManager extends EventEmitter { helper.removeEventListeners(this._eventListeners); } - async setExtraHTTPHeaders(headers: network.Headers) { + async setExtraHTTPHeaders(headers: types.HttpHeaders) { const array = []; for (const [name, value] of Object.entries(headers)) { assert(helper.isString(value), `Expected value of header "${name}" to be String, but "${typeof value}" is found.`); @@ -87,7 +88,7 @@ export class NetworkManager extends EventEmitter { const request = this._requests.get(event.requestId); if (!request) return; - const remoteAddress: network.RemoteAddress = { ip: event.remoteIPAddress, port: event.remotePort }; + const remoteAddress: types.NetworkRemoteAddress = { ip: event.remoteIPAddress, port: event.remotePort }; const getResponseBody = async () => { const response = await this._session.send('Network.getResponseBody', { requestId: request._id @@ -96,7 +97,7 @@ export class NetworkManager extends EventEmitter { throw new Error(`Response body for ${request.request.method()} ${request.request.url()} was evicted!`); return Buffer.from(response.base64body, 'base64'); }; - const headers: network.Headers = {}; + const headers: types.HttpHeaders = {}; for (const {name, value} of event.headers) headers[name.toLowerCase()] = value; const response = new network.Response(request.request, event.status, event.statusText, headers, remoteAddress, getResponseBody); @@ -176,7 +177,7 @@ class InterceptableRequest { this._suspended = payload.suspended; this._interceptionHandled = false; - const headers: network.Headers = {}; + const headers: types.HttpHeaders = {}; for (const {name, value} of payload.headers) headers[name.toLowerCase()] = value; diff --git a/src/frames.ts b/src/frames.ts index 6cb99853ff..3b5b6cbc9a 100644 --- a/src/frames.ts +++ b/src/frames.ts @@ -21,7 +21,6 @@ import * as js from './javascript'; import * as dom from './dom'; import * as network from './network'; import { helper, assert, RegisteredListener } from './helper'; -import { ClickOptions, MultiClickOptions, PointerActionOptions, SelectOption } from './input'; import { TimeoutError } from './errors'; import { Events } from './events'; import { Page } from './page'; @@ -112,7 +111,7 @@ export class Frame { async $(selector: string | types.Selector): Promise | null> { const context = await this._mainContext(); - return context._$(types.clearSelector(selector)); + return context._$(helper.clearSelector(selector)); } async $x(expression: string): Promise[]> { @@ -132,7 +131,7 @@ export class Frame { async $$(selector: string | types.Selector): Promise[]> { const context = await this._mainContext(); - return context._$$(types.clearSelector(selector)); + return context._$$(helper.clearSelector(selector)); } async content(): Promise { @@ -306,58 +305,58 @@ export class Frame { return result; } - async click(selector: string | types.Selector, options?: ClickOptions) { + async click(selector: string | types.Selector, options?: types.ClickOptions) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.click(options); await handle.dispose(); } - async dblclick(selector: string | types.Selector, options?: MultiClickOptions) { + async dblclick(selector: string | types.Selector, options?: types.DoubleClickOptions) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.dblclick(options); await handle.dispose(); } - async tripleclick(selector: string | types.Selector, options?: MultiClickOptions) { + async tripleclick(selector: string | types.Selector, options?: types.TripleClickOptions) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.tripleclick(options); await handle.dispose(); } async fill(selector: string | types.Selector, value: string) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.fill(value); await handle.dispose(); } async focus(selector: string | types.Selector) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.focus(); await handle.dispose(); } - async hover(selector: string | types.Selector, options?: PointerActionOptions) { + async hover(selector: string | types.Selector, options?: types.PointerActionOptions) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.hover(options); await handle.dispose(); } - async select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | SelectOption)[]): Promise { + async select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | types.SelectOption)[]): Promise { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); const toDispose: Promise[] = []; const adoptedValues = await Promise.all(values.map(async value => { if (value instanceof dom.ElementHandle && value.executionContext() !== context) { @@ -375,8 +374,8 @@ export class Frame { async type(selector: string | types.Selector, text: string, options: { delay: (number | undefined); } | undefined) { const context = await this._utilityContext(); - const handle = await context._$(types.clearSelector(selector)); - assert(handle, 'No node found for selector: ' + types.selectorToString(selector)); + const handle = await context._$(helper.clearSelector(selector)); + assert(handle, 'No node found for selector: ' + helper.selectorToString(selector)); await handle.type(text, options); await handle.dispose(); } @@ -393,8 +392,8 @@ export class Frame { async waitForSelector(selector: string | types.Selector, options: types.TimeoutOptions = {}): Promise { const { timeout = this._page._timeoutSettings.timeout() } = options; - const task = dom.waitForSelectorTask(types.clearSelector(selector), timeout); - const handle = await this._scheduleRerunnableTask(task, 'utility', timeout, `selector "${types.selectorToString(selector)}"`); + const task = dom.waitForSelectorTask(helper.clearSelector(selector), timeout); + const handle = await this._scheduleRerunnableTask(task, 'utility', timeout, `selector "${helper.selectorToString(selector)}"`); if (!handle.asElement()) { await handle.dispose(); return null; diff --git a/src/helper.ts b/src/helper.ts index 21052db77b..34ace11f4d 100644 --- a/src/helper.ts +++ b/src/helper.ts @@ -16,6 +16,7 @@ */ import * as debug from 'debug'; +import * as types from './types'; import { TimeoutError } from './errors'; export const debugError = debug(`playwright:error`); @@ -153,6 +154,19 @@ class Helper { clearTimeout(timeoutTimer); } } + + static selectorToString(selector: string | types.Selector): string { + if (typeof selector === 'string') + return selector; + return `${selector.visible ? '[visible] ' : selector.visible === false ? '[hidden] ' : ''}${selector.selector}`; + } + + // Ensures that we don't use accidental properties in selector, e.g. scope. + static clearSelector(selector: string | types.Selector): string | types.Selector { + if (helper.isString(selector)) + return selector; + return { selector: selector.selector, visible: selector.visible }; + } } export function assert(value: any, message?: string) { diff --git a/src/input.ts b/src/input.ts index 0c3b0f846c..0b032c7112 100644 --- a/src/input.ts +++ b/src/input.ts @@ -6,34 +6,10 @@ import * as path from 'path'; import { assert, helper } from './helper'; import * as types from './types'; import * as keyboardLayout from './usKeyboardLayout'; +import * as api from './api'; const readFileAsync = helper.promisify(fs.readFile); -export type Modifier = 'Alt' | 'Control' | 'Meta' | 'Shift'; -export type Button = 'left' | 'right' | 'middle'; - -export type PointerActionOptions = { - modifiers?: Modifier[]; - relativePoint?: types.Point; -}; - -export type ClickOptions = PointerActionOptions & { - delay?: number; - button?: Button; - clickCount?: number; -}; - -export type MultiClickOptions = PointerActionOptions & { - delay?: number; - button?: Button; -}; - -export type SelectOption = { - value?: string; - label?: string; - index?: number; -}; - export const keypadLocation = keyboardLayout.keypadLocation; type KeyDescription = { @@ -45,17 +21,17 @@ type KeyDescription = { location: number, }; -const kModifiers: Modifier[] = ['Alt', 'Control', 'Meta', 'Shift']; +const kModifiers: types.ModifierKey[] = ['Alt', 'Control', 'Meta', 'Shift']; export interface RawKeyboard { - keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise; - keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise; + keydown(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise; + keyup(modifiers: Set, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise; sendText(text: string): Promise; } -export class Keyboard { +export class Keyboard implements api.Keyboard { private _raw: RawKeyboard; - private _pressedModifiers = new Set(); + private _pressedModifiers = new Set(); private _pressedKeys = new Set(); constructor(raw: RawKeyboard) { @@ -66,8 +42,8 @@ export class Keyboard { const description = this._keyDescriptionForString(key); const autoRepeat = this._pressedKeys.has(description.code); this._pressedKeys.add(description.code); - if (kModifiers.includes(description.key as Modifier)) - this._pressedModifiers.add(description.key as Modifier); + if (kModifiers.includes(description.key as types.ModifierKey)) + this._pressedModifiers.add(description.key as types.ModifierKey); const text = options.text === undefined ? description.text : options.text; await this._raw.keydown(this._pressedModifiers, description.code, description.keyCode, description.keyCodeWithoutLocation, description.key, description.location, autoRepeat, text); } @@ -123,8 +99,8 @@ export class Keyboard { async up(key: string) { const description = this._keyDescriptionForString(key); - if (kModifiers.includes(description.key as Modifier)) - this._pressedModifiers.delete(description.key as Modifier); + if (kModifiers.includes(description.key as types.ModifierKey)) + this._pressedModifiers.delete(description.key as types.ModifierKey); this._pressedKeys.delete(description.code); await this._raw.keyup(this._pressedModifiers, description.code, description.keyCode, description.keyCodeWithoutLocation, description.key, description.location); } @@ -154,12 +130,12 @@ export class Keyboard { await this.up(key); } - async _ensureModifiers(modifiers: Modifier[]): Promise { + async _ensureModifiers(modifiers: types.ModifierKey[]): Promise { for (const modifier of modifiers) { if (!kModifiers.includes(modifier)) throw new Error('Uknown modifier ' + modifier); } - const restore: Modifier[] = Array.from(this._pressedModifiers); + const restore: types.ModifierKey[] = Array.from(this._pressedModifiers); const promises: Promise[] = []; for (const key of kModifiers) { const needDown = modifiers.includes(key); @@ -173,24 +149,24 @@ export class Keyboard { return restore; } - _modifiers(): Set { + _modifiers(): Set { return this._pressedModifiers; } } export interface RawMouse { - move(x: number, y: number, button: Button | 'none', buttons: Set