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.
This commit is contained in:
Dmitry Gozman 2019-12-13 16:28:25 -08:00
parent 32fa26be97
commit 44e5ca3db8
19 changed files with 226 additions and 170 deletions

54
src/api.d.ts vendored Normal file
View file

@ -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<void>;
press(key: string, options?: { text?: string, delay?: number }): Promise<void>;
sendCharacters(text: string): Promise<void>;
type(text: string, options?: { delay?: number }): Promise<void>;
up(key: string): Promise<void>;
}
export interface Mouse {
move(x: number, y: number, options?: { steps?: number }): Promise<void>;
down(options?: { button?: types.MouseButton, clickCount?: number }): Promise<void>;
up(options?: { button?: types.MouseButton, clickCount?: number }): Promise<void>;
click(x: number, y: number, options?: types.ClickOptions): Promise<void>;
dblclick(x: number, y: number, options?: types.DoubleClickOptions): Promise<void>;
tripleclick(x: number, y: number, options?: types.TripleClickOptions): Promise<void>;
}
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<Buffer>;
text(): Promise<string>;
json(): Promise<any>;
remoteAddress(): types.NetworkRemoteAddress;
frame(): Frame | null;
}
export interface Frame {
}

View file

@ -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;

View file

@ -425,7 +425,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
this._page._onFileChooserOpened(handle);
}
setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise<void> {
setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise<void> {
return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders);
}

View file

@ -16,9 +16,10 @@
*/
import * as input from '../input';
import * as types from '../types';
import { CDPSession } from './Connection';
function toModifiersMask(modifiers: Set<input.Modifier>): number {
function toModifiersMask(modifiers: Set<types.ModifierKey>): 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<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
async keydown(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
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<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
async keyup(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>): Promise<void> {
async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async down(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async up(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
await this._client.send('Input.dispatchMouseEvent', {
type: 'mouseReleased',
button,

View file

@ -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<string, InterceptableRequest>();
private _requestIdToRequestWillBeSentEvent = new Map<string, Protocol.Network.requestWillBeSentPayload>();
private _extraHTTPHeaders: network.Headers = {};
private _extraHTTPHeaders: types.HttpHeaders = {};
private _offline = false;
private _credentials: {username: string, password: string} | null = null;
private _attemptedAuthentications = new Set<string>();
@ -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;

View file

@ -111,7 +111,7 @@ export class FrameExecutionContext extends js.ExecutionContext {
_$eval: types.$Eval<string | ScopedSelector> = 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<T extends Node = Node> extends js.JSHandle<T> {
return { point, scrollX, scrollY };
}
async _performPointerAction(action: (point: types.Point) => Promise<void>, options?: input.PointerActionOptions): Promise<void> {
async _performPointerAction(action: (point: types.Point) => Promise<void>, options?: types.PointerActionOptions): Promise<void> {
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<T extends Node = Node> extends js.JSHandle<T> {
await this._page.keyboard._ensureModifiers(restoreModifiers);
}
hover(options?: input.PointerActionOptions): Promise<void> {
hover(options?: types.PointerActionOptions): Promise<void> {
return this._performPointerAction(point => this._page.mouse.move(point.x, point.y), options);
}
click(options?: input.ClickOptions): Promise<void> {
click(options?: types.ClickOptions): Promise<void> {
return this._performPointerAction(point => this._page.mouse.click(point.x, point.y, options), options);
}
dblclick(options?: input.MultiClickOptions): Promise<void> {
dblclick(options?: types.DoubleClickOptions): Promise<void> {
return this._performPointerAction(point => this._page.mouse.dblclick(point.x, point.y, options), options);
}
tripleclick(options?: input.MultiClickOptions): Promise<void> {
tripleclick(options?: types.TripleClickOptions): Promise<void> {
return this._performPointerAction(point => this._page.mouse.tripleclick(point.x, point.y, options), options);
}
async select(...values: (string | ElementHandle | input.SelectOption)[]): Promise<string[]> {
async select(...values: (string | ElementHandle | types.SelectOption)[]): Promise<string[]> {
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<T extends Node = Node> extends js.JSHandle<T> {
}
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 };

View file

@ -296,7 +296,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
throw error;
}
setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise<void> {
setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise<void> {
return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders);
}

View file

@ -17,8 +17,9 @@
import { JugglerSession } from './Connection';
import * as input from '../input';
import * as types from '../types';
function toModifiersMask(modifiers: Set<input.Modifier>): number {
function toModifiersMask(modifiers: Set<types.ModifierKey>): number {
let mask = 0;
if (modifiers.has('Alt'))
mask |= 1;
@ -31,7 +32,7 @@ function toModifiersMask(modifiers: Set<input.Modifier>): 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<input.Button>): number {
function toButtonsMask(buttons: Set<types.MouseButton>): 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<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
async keydown(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
if (code === 'MetaLeft')
code = 'OSLeft';
if (code === 'MetaRight')
@ -73,7 +74,7 @@ export class RawKeyboardImpl implements input.RawKeyboard {
});
}
async keyup(modifiers: Set<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
async keyup(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>): Promise<void> {
async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async down(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
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<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async up(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
await this._client.send('Page.dispatchMouseEvent', {
type: 'mouseup',
button: toButtonNumber(button),

View file

@ -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;

View file

@ -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<dom.ElementHandle<Element> | null> {
const context = await this._mainContext();
return context._$(types.clearSelector(selector));
return context._$(helper.clearSelector(selector));
}
async $x(expression: string): Promise<dom.ElementHandle<Element>[]> {
@ -132,7 +131,7 @@ export class Frame {
async $$(selector: string | types.Selector): Promise<dom.ElementHandle<Element>[]> {
const context = await this._mainContext();
return context._$$(types.clearSelector(selector));
return context._$$(helper.clearSelector(selector));
}
async content(): Promise<string> {
@ -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<string[]> {
async select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | types.SelectOption)[]): Promise<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));
const toDispose: Promise<dom.ElementHandle>[] = [];
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<dom.ElementHandle | null> {
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;

View file

@ -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) {

View file

@ -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<Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void>;
keyup(modifiers: Set<Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void>;
keydown(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void>;
keyup(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void>;
sendText(text: string): Promise<void>;
}
export class Keyboard {
export class Keyboard implements api.Keyboard {
private _raw: RawKeyboard;
private _pressedModifiers = new Set<Modifier>();
private _pressedModifiers = new Set<types.ModifierKey>();
private _pressedKeys = new Set<string>();
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<Modifier[]> {
async _ensureModifiers(modifiers: types.ModifierKey[]): Promise<types.ModifierKey[]> {
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<void>[] = [];
for (const key of kModifiers) {
const needDown = modifiers.includes(key);
@ -173,24 +149,24 @@ export class Keyboard {
return restore;
}
_modifiers(): Set<Modifier> {
_modifiers(): Set<types.ModifierKey> {
return this._pressedModifiers;
}
}
export interface RawMouse {
move(x: number, y: number, button: Button | 'none', buttons: Set<Button>, modifiers: Set<Modifier>): Promise<void>;
down(x: number, y: number, button: Button, buttons: Set<Button>, modifiers: Set<Modifier>, clickCount: number): Promise<void>;
up(x: number, y: number, button: Button, buttons: Set<Button>, modifiers: Set<Modifier>, clickCount: number): Promise<void>;
move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>): Promise<void>;
down(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void>;
up(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void>;
}
export class Mouse {
export class Mouse implements api.Mouse {
private _raw: RawMouse;
private _keyboard: Keyboard;
private _x = 0;
private _y = 0;
private _lastButton: 'none' | Button = 'none';
private _buttons = new Set<Button>();
private _lastButton: 'none' | types.MouseButton = 'none';
private _buttons = new Set<types.MouseButton>();
constructor(raw: RawMouse, keyboard: Keyboard) {
this._raw = raw;
@ -210,21 +186,21 @@ export class Mouse {
}
}
async down(options: { button?: Button, clickCount?: number } = {}) {
async down(options: { button?: types.MouseButton, clickCount?: number } = {}) {
const { button = 'left', clickCount = 1 } = options;
this._lastButton = button;
this._buttons.add(button);
await this._raw.down(this._x, this._y, this._lastButton, this._buttons, this._keyboard._modifiers(), clickCount);
}
async up(options: { button?: Button, clickCount?: number } = {}) {
async up(options: { button?: types.MouseButton, clickCount?: number } = {}) {
const { button = 'left', clickCount = 1 } = options;
this._lastButton = 'none';
this._buttons.delete(button);
await this._raw.up(this._x, this._y, button, this._buttons, this._keyboard._modifiers(), clickCount);
}
async click(x: number, y: number, options: ClickOptions = {}) {
async click(x: number, y: number, options: types.ClickOptions = {}) {
const {delay = null} = options;
if (delay !== null) {
await Promise.all([
@ -242,7 +218,7 @@ export class Mouse {
}
}
async dblclick(x: number, y: number, options: MultiClickOptions = {}) {
async dblclick(x: number, y: number, options: types.DoubleClickOptions = {}) {
const { delay = null } = options;
if (delay !== null) {
await this.move(x, y);
@ -264,7 +240,7 @@ export class Mouse {
}
}
async tripleclick(x: number, y: number, options: MultiClickOptions = {}) {
async tripleclick(x: number, y: number, options: types.TripleClickOptions = {}) {
const { delay = null } = options;
if (delay !== null) {
await this.move(x, y);
@ -293,7 +269,7 @@ export class Mouse {
}
}
export const selectFunction = (node: Node, ...optionsToSelect: (Node | SelectOption)[]) => {
export const selectFunction = (node: Node, ...optionsToSelect: (Node | types.SelectOption)[]) => {
if (node.nodeName.toLowerCase() !== 'select')
throw new Error('Element is not a <select> element.');
const element = node as HTMLSelectElement;

View file

@ -2,6 +2,8 @@
// Licensed under the MIT license.
import * as frames from './frames';
import * as types from './types';
import * as api from './api';
import { assert } from './helper';
export type NetworkCookie = {
@ -67,9 +69,7 @@ export function rewriteCookies(cookies: SetNetworkCookieParam[]): SetNetworkCook
});
}
export type Headers = { [key: string]: string };
export class Request {
export class Request implements api.Request {
private _response: Response | null = null;
_redirectChain: Request[];
private _isNavigationRequest: boolean;
@ -78,7 +78,7 @@ export class Request {
private _resourceType: string;
private _method: string;
private _postData: string;
private _headers: Headers;
private _headers: types.HttpHeaders;
private _frame: frames.Frame;
private _waitForResponsePromise: Promise<Response>;
private _waitForResponsePromiseCallback: (value?: Response) => void;
@ -86,7 +86,7 @@ export class Request {
private _waitForFinishedPromiseCallback: (value?: Response | undefined) => void;
constructor(frame: frames.Frame | null, redirectChain: Request[], isNavigationRequest: boolean,
url: string, resourceType: string, method: string, postData: string, headers: Headers) {
url: string, resourceType: string, method: string, postData: string, headers: types.HttpHeaders) {
this._frame = frame;
this._redirectChain = redirectChain;
this._isNavigationRequest = isNavigationRequest;
@ -120,7 +120,7 @@ export class Request {
return this._postData;
}
headers(): {[key: string]: string} {
headers(): types.HttpHeaders {
return this._headers;
}
@ -165,26 +165,21 @@ export class Request {
}
}
export type RemoteAddress = {
ip: string,
port: number,
};
type GetResponseBodyCallback = () => Promise<Buffer>;
export class Response {
export class Response implements api.Response {
private _request: Request;
private _contentPromise: Promise<Buffer> | null = null;
_finishedPromise: Promise<Error | null>;
private _finishedPromiseCallback: any;
private _remoteAddress: RemoteAddress;
private _remoteAddress: types.NetworkRemoteAddress;
private _status: number;
private _statusText: string;
private _url: string;
private _headers: Headers;
private _headers: types.HttpHeaders;
private _getResponseBodyCallback: GetResponseBodyCallback;
constructor(request: Request, status: number, statusText: string, headers: Headers, remoteAddress: RemoteAddress, getResponseBodyCallback: GetResponseBodyCallback) {
constructor(request: Request, status: number, statusText: string, headers: types.HttpHeaders, remoteAddress: types.NetworkRemoteAddress, getResponseBodyCallback: GetResponseBodyCallback) {
this._request = request;
this._status = status;
this._statusText = statusText;
@ -202,7 +197,7 @@ export class Response {
this._finishedPromiseCallback.call(null, error);
}
remoteAddress(): RemoteAddress {
remoteAddress(): types.NetworkRemoteAddress {
return this._remoteAddress;
}
@ -222,7 +217,7 @@ export class Response {
return this._statusText;
}
headers(): object {
headers(): types.HttpHeaders {
return this._headers;
}

View file

@ -49,7 +49,7 @@ export interface PageDelegate {
waitForFrameNavigation(frame: frames.Frame, options?: frames.NavigateOptions): Promise<network.Response | null>;
setFrameContent(frame: frames.Frame, html: string, options?: frames.NavigateOptions): Promise<void>;
setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise<void>;
setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise<void>;
setUserAgent(userAgent: string): Promise<void>;
setJavaScriptEnabled(enabled: boolean): Promise<void>;
setBypassCSP(enabled: boolean): Promise<void>;
@ -78,7 +78,7 @@ type PageState = {
mediaType: input.MediaType | null;
mediaColorScheme: input.MediaColorScheme | null;
javascriptEnabled: boolean | null;
extraHTTPHeaders: network.Headers | null;
extraHTTPHeaders: types.HttpHeaders | null;
bypassCSP: boolean | null;
cacheEnabled: boolean | null;
};
@ -257,7 +257,7 @@ export class Page extends EventEmitter {
}
}
setExtraHTTPHeaders(headers: network.Headers) {
setExtraHTTPHeaders(headers: types.HttpHeaders) {
this._state.extraHTTPHeaders = {...headers};
return this._delegate.setExtraHTTPHeaders(headers);
}
@ -447,15 +447,15 @@ export class Page extends EventEmitter {
return this._closed;
}
click(selector: string | types.Selector, options?: input.ClickOptions) {
click(selector: string | types.Selector, options?: types.ClickOptions) {
return this.mainFrame().click(selector, options);
}
dblclick(selector: string | types.Selector, options?: input.MultiClickOptions) {
dblclick(selector: string | types.Selector, options?: types.DoubleClickOptions) {
return this.mainFrame().dblclick(selector, options);
}
tripleclick(selector: string | types.Selector, options?: input.MultiClickOptions) {
tripleclick(selector: string | types.Selector, options?: types.TripleClickOptions) {
return this.mainFrame().tripleclick(selector, options);
}
@ -467,11 +467,11 @@ export class Page extends EventEmitter {
return this.mainFrame().focus(selector);
}
hover(selector: string | types.Selector, options?: input.PointerActionOptions) {
hover(selector: string | types.Selector, options?: types.PointerActionOptions) {
return this.mainFrame().hover(selector, options);
}
select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | input.SelectOption)[]): Promise<string[]> {
select(selector: string | types.Selector, ...values: (string | dom.ElementHandle | types.SelectOption)[]): Promise<string[]> {
return this.mainFrame().select(selector, ...values);
}

View file

@ -2,7 +2,6 @@
// Licensed under the MIT license.
import * as js from './javascript';
import { helper } from './helper';
import * as dom from './dom';
type Boxed<Args extends any[]> = { [Index in keyof Args]: Args[Index] | js.JSHandle<Args[Index]> };
@ -31,18 +30,41 @@ export type Selector = { selector: string, visible?: boolean };
export type Polling = 'raf' | 'mutation' | number;
export type WaitForFunctionOptions = TimeoutOptions & { polling?: Polling };
export function selectorToString(selector: string | Selector): string {
if (typeof selector === 'string')
return selector;
return `${selector.visible ? '[visible] ' : selector.visible === false ? '[hidden] ' : ''}${selector.selector}`;
}
export type ModifierKey = 'Alt' | 'Control' | 'Meta' | 'Shift';
export type MouseButton = 'left' | 'right' | 'middle';
// Ensures that we don't use accidental properties in selector, e.g. scope.
export function clearSelector(selector: string | Selector): string | Selector {
if (helper.isString(selector))
return selector;
return { selector: selector.selector, visible: selector.visible };
}
export type PointerActionOptions = {
modifiers?: ModifierKey[];
relativePoint?: Point;
};
export type ClickOptions = PointerActionOptions & {
delay?: number;
button?: MouseButton;
clickCount?: number;
};
export type DoubleClickOptions = PointerActionOptions & {
delay?: number;
button?: MouseButton;
};
export type TripleClickOptions = PointerActionOptions & {
delay?: number;
button?: MouseButton;
};
export type SelectOption = {
value?: string;
label?: string;
index?: number;
};
export type HttpHeaders = { [key: string]: string };
export type NetworkRemoteAddress = {
ip: string,
port: number,
};
export type ElementScreenshotOptions = {
type?: 'png' | 'jpeg',

View file

@ -387,7 +387,7 @@ export class FrameManager extends EventEmitter implements PageDelegate {
this._page._onFileChooserOpened(handle);
}
setExtraHTTPHeaders(extraHTTPHeaders: network.Headers): Promise<void> {
setExtraHTTPHeaders(extraHTTPHeaders: types.HttpHeaders): Promise<void> {
return this._networkManager.setExtraHTTPHeaders(extraHTTPHeaders);
}

View file

@ -16,11 +16,12 @@
*/
import * as input from '../input';
import * as types from '../types';
import { helper } from '../helper';
import { macEditingCommands } from '../usKeyboardLayout';
import { TargetSession } from './Connection';
function toModifiersMask(modifiers: Set<input.Modifier>): number {
function toModifiersMask(modifiers: Set<types.ModifierKey>): number {
// From Source/WebKit/Shared/WebEvent.h
let mask = 0;
if (modifiers.has('Shift'))
@ -41,9 +42,9 @@ export class RawKeyboardImpl implements input.RawKeyboard {
this._session = session;
}
async keydown(modifiers: Set<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
async keydown(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number, autoRepeat: boolean, text: string | undefined): Promise<void> {
const parts = [];
for (const modifier of (['Shift', 'Control', 'Alt', 'Meta']) as input.Modifier[]) {
for (const modifier of (['Shift', 'Control', 'Alt', 'Meta']) as types.ModifierKey[]) {
if (modifiers.has(modifier))
parts.push(modifier);
}
@ -66,7 +67,7 @@ export class RawKeyboardImpl implements input.RawKeyboard {
});
}
async keyup(modifiers: Set<input.Modifier>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
async keyup(modifiers: Set<types.ModifierKey>, code: string, keyCode: number, keyCodeWithoutLocation: number, key: string, location: number): Promise<void> {
await this._session.send('Input.dispatchKeyEvent', {
type: 'keyUp',
modifiers: toModifiersMask(modifiers),
@ -89,7 +90,7 @@ export class RawMouseImpl implements input.RawMouse {
this._client = client;
}
async move(x: number, y: number, button: input.Button | 'none', buttons: Set<input.Button>, modifiers: Set<input.Modifier>): Promise<void> {
async move(x: number, y: number, button: types.MouseButton | 'none', buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>): Promise<void> {
await this._client.send('Input.dispatchMouseEvent', {
type: 'move',
button,
@ -99,7 +100,7 @@ export class RawMouseImpl implements input.RawMouse {
});
}
async down(x: number, y: number, button: input.Button, buttons: Set<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async down(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
await this._client.send('Input.dispatchMouseEvent', {
type: 'down',
button,
@ -110,7 +111,7 @@ export class RawMouseImpl implements input.RawMouse {
});
}
async up(x: number, y: number, button: input.Button, buttons: Set<input.Button>, modifiers: Set<input.Modifier>, clickCount: number): Promise<void> {
async up(x: number, y: number, button: types.MouseButton, buttons: Set<types.MouseButton>, modifiers: Set<types.ModifierKey>, clickCount: number): Promise<void> {
await this._client.send('Input.dispatchMouseEvent', {
type: 'up',
button,

View file

@ -22,6 +22,7 @@ import { assert, helper, RegisteredListener } 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'),
@ -34,7 +35,7 @@ export class NetworkManager extends EventEmitter {
private _session: TargetSession;
private _frameManager: FrameManager;
private _requestIdToRequest = new Map<string, InterceptableRequest>();
private _extraHTTPHeaders: network.Headers = {};
private _extraHTTPHeaders: types.HttpHeaders = {};
private _attemptedAuthentications = new Set<string>();
private _userCacheDisabled = false;
private _sessionListeners: RegisteredListener[] = [];
@ -109,7 +110,7 @@ export class NetworkManager extends EventEmitter {
}
_createResponse(request: InterceptableRequest, responsePayload: Protocol.Network.Response): network.Response {
const remoteAddress: network.RemoteAddress = { ip: '', port: 0 };
const remoteAddress: types.NetworkRemoteAddress = { ip: '', port: 0 };
const getResponseBody = async () => {
const response = await this._session.send('Network.getResponseBody', { requestId: request._requestId });
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
@ -198,8 +199,8 @@ class InterceptableRequest {
}
}
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;

View file

@ -10,6 +10,6 @@
"declaration": true
},
"compileOnSave": true,
"include": ["src/**/*.ts"],
"include": ["src/**/*.ts", "src/**/*.d.ts"],
"exclude": ["node_modules"]
}