mirror of
				https://github.com/microsoft/playwright.git
				synced 2025-06-26 21:40:17 +00:00 
			
		
		
		
	chore(rpc): implement input, a11y, console (#2722)
This commit is contained in:
		
							parent
							
								
									ab6a6c9b82
								
							
						
					
					
						commit
						71618a9e2b
					
				@ -14,48 +14,15 @@
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import * as dom from './dom';
 | 
			
		||||
 | 
			
		||||
export type SerializedAXNode = {
 | 
			
		||||
  role: string,
 | 
			
		||||
  name: string,
 | 
			
		||||
  value?: string|number,
 | 
			
		||||
  description?: string,
 | 
			
		||||
 | 
			
		||||
  keyshortcuts?: string,
 | 
			
		||||
  roledescription?: string,
 | 
			
		||||
  valuetext?: string,
 | 
			
		||||
 | 
			
		||||
  disabled?: boolean,
 | 
			
		||||
  expanded?: boolean,
 | 
			
		||||
  focused?: boolean,
 | 
			
		||||
  modal?: boolean,
 | 
			
		||||
  multiline?: boolean,
 | 
			
		||||
  multiselectable?: boolean,
 | 
			
		||||
  readonly?: boolean,
 | 
			
		||||
  required?: boolean,
 | 
			
		||||
  selected?: boolean,
 | 
			
		||||
 | 
			
		||||
  checked?: boolean|'mixed',
 | 
			
		||||
  pressed?: boolean|'mixed',
 | 
			
		||||
 | 
			
		||||
  level?: number,
 | 
			
		||||
  valuemin?: number,
 | 
			
		||||
  valuemax?: number,
 | 
			
		||||
 | 
			
		||||
  autocomplete?: string,
 | 
			
		||||
  haspopup?: string,
 | 
			
		||||
  invalid?: string,
 | 
			
		||||
  orientation?: string,
 | 
			
		||||
 | 
			
		||||
  children?: SerializedAXNode[]
 | 
			
		||||
};
 | 
			
		||||
import * as types from './types';
 | 
			
		||||
 | 
			
		||||
export interface AXNode {
 | 
			
		||||
    isInteresting(insideControl: boolean): boolean;
 | 
			
		||||
    isLeafNode(): boolean;
 | 
			
		||||
    isControl(): boolean;
 | 
			
		||||
    serialize(): SerializedAXNode;
 | 
			
		||||
    serialize(): types.SerializedAXNode;
 | 
			
		||||
    children(): Iterable<AXNode>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -68,7 +35,7 @@ export class Accessibility {
 | 
			
		||||
  async snapshot(options: {
 | 
			
		||||
      interestingOnly?: boolean;
 | 
			
		||||
      root?: dom.ElementHandle;
 | 
			
		||||
    } = {}): Promise<SerializedAXNode | null> {
 | 
			
		||||
    } = {}): Promise<types.SerializedAXNode | null> {
 | 
			
		||||
    const {
 | 
			
		||||
      interestingOnly = true,
 | 
			
		||||
      root = null,
 | 
			
		||||
@ -98,8 +65,8 @@ function collectInterestingNodes(collection: Set<AXNode>, node: AXNode, insideCo
 | 
			
		||||
    collectInterestingNodes(collection, child, insideControl);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function serializeTree(node: AXNode, whitelistedNodes?: Set<AXNode>): SerializedAXNode[] {
 | 
			
		||||
  const children: SerializedAXNode[] = [];
 | 
			
		||||
function serializeTree(node: AXNode, whitelistedNodes?: Set<AXNode>): types.SerializedAXNode[] {
 | 
			
		||||
  const children: types.SerializedAXNode[] = [];
 | 
			
		||||
  for (const child of node.children())
 | 
			
		||||
    children.push(...serializeTree(child, whitelistedNodes));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import { CRSession } from './crConnection';
 | 
			
		||||
import { Protocol } from './protocol';
 | 
			
		||||
import * as dom from '../dom';
 | 
			
		||||
import * as accessibility from '../accessibility';
 | 
			
		||||
import * as types from '../types';
 | 
			
		||||
 | 
			
		||||
export async function getAccessibilityTree(client: CRSession, needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle: accessibility.AXNode | null}> {
 | 
			
		||||
  const {nodes} = await client.send('Accessibility.getFullAXTree');
 | 
			
		||||
@ -198,7 +199,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
    return this.isLeafNode() && !!this._name;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serialize(): accessibility.SerializedAXNode {
 | 
			
		||||
  serialize(): types.SerializedAXNode {
 | 
			
		||||
    const properties: Map<string, number | string | boolean> = new Map();
 | 
			
		||||
    for (const property of this._payload.properties || [])
 | 
			
		||||
      properties.set(property.name.toLowerCase(), property.value.value);
 | 
			
		||||
@ -209,12 +210,12 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
    if (this._payload.description)
 | 
			
		||||
      properties.set('description', this._payload.description.value);
 | 
			
		||||
 | 
			
		||||
    const node: {[x in keyof accessibility.SerializedAXNode]: any} = {
 | 
			
		||||
    const node: {[x in keyof types.SerializedAXNode]: any} = {
 | 
			
		||||
      role: this._role,
 | 
			
		||||
      name: this._payload.name ? (this._payload.name.value || '') : ''
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const userStringProperties: Array<keyof accessibility.SerializedAXNode> = [
 | 
			
		||||
    const userStringProperties: Array<keyof types.SerializedAXNode> = [
 | 
			
		||||
      'value',
 | 
			
		||||
      'description',
 | 
			
		||||
      'keyshortcuts',
 | 
			
		||||
@ -227,7 +228,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
      node[userStringProperty] = properties.get(userStringProperty);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const booleanProperties: Array<keyof accessibility.SerializedAXNode> = [
 | 
			
		||||
    const booleanProperties: Array<keyof types.SerializedAXNode> = [
 | 
			
		||||
      'disabled',
 | 
			
		||||
      'expanded',
 | 
			
		||||
      'focused',
 | 
			
		||||
@ -249,7 +250,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
      node[booleanProperty] = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const tristateProperties: Array<keyof accessibility.SerializedAXNode> = [
 | 
			
		||||
    const tristateProperties: Array<keyof types.SerializedAXNode> = [
 | 
			
		||||
      'checked',
 | 
			
		||||
      'pressed',
 | 
			
		||||
    ];
 | 
			
		||||
@ -259,7 +260,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
      const value = properties.get(tristateProperty);
 | 
			
		||||
      node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
 | 
			
		||||
    }
 | 
			
		||||
    const numericalProperties: Array<keyof accessibility.SerializedAXNode> = [
 | 
			
		||||
    const numericalProperties: Array<keyof types.SerializedAXNode> = [
 | 
			
		||||
      'level',
 | 
			
		||||
      'valuemax',
 | 
			
		||||
      'valuemin',
 | 
			
		||||
@ -269,7 +270,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
        continue;
 | 
			
		||||
      node[numericalProperty] = properties.get(numericalProperty);
 | 
			
		||||
    }
 | 
			
		||||
    const tokenProperties: Array<keyof accessibility.SerializedAXNode> = [
 | 
			
		||||
    const tokenProperties: Array<keyof types.SerializedAXNode> = [
 | 
			
		||||
      'autocomplete',
 | 
			
		||||
      'haspopup',
 | 
			
		||||
      'invalid',
 | 
			
		||||
@ -281,7 +282,7 @@ class CRAXNode implements accessibility.AXNode {
 | 
			
		||||
        continue;
 | 
			
		||||
      node[tokenProperty] = value;
 | 
			
		||||
    }
 | 
			
		||||
    return node as accessibility.SerializedAXNode;
 | 
			
		||||
    return node as types.SerializedAXNode;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static createTree(client: CRSession, payloads: Protocol.Accessibility.AXNode[]): CRAXNode {
 | 
			
		||||
 | 
			
		||||
@ -16,12 +16,7 @@
 | 
			
		||||
 | 
			
		||||
import * as js from './javascript';
 | 
			
		||||
import * as util from 'util';
 | 
			
		||||
 | 
			
		||||
export type ConsoleMessageLocation = {
 | 
			
		||||
  url?: string,
 | 
			
		||||
  lineNumber?: number,
 | 
			
		||||
  columnNumber?: number,
 | 
			
		||||
};
 | 
			
		||||
import { ConsoleMessageLocation } from './types';
 | 
			
		||||
 | 
			
		||||
export class ConsoleMessage {
 | 
			
		||||
  private _type: string;
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ import * as accessibility from '../accessibility';
 | 
			
		||||
import { FFSession } from './ffConnection';
 | 
			
		||||
import { Protocol } from './protocol';
 | 
			
		||||
import * as dom from '../dom';
 | 
			
		||||
import * as types from '../types';
 | 
			
		||||
 | 
			
		||||
export async function getAccessibilityTree(session: FFSession, needle?: dom.ElementHandle): Promise<{tree: accessibility.AXNode, needle: accessibility.AXNode | null}> {
 | 
			
		||||
  const objectId = needle ? needle._objectId : undefined;
 | 
			
		||||
@ -198,12 +199,12 @@ class FFAXNode implements accessibility.AXNode {
 | 
			
		||||
    return this.isLeafNode() && !!this._name.trim();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serialize(): accessibility.SerializedAXNode {
 | 
			
		||||
    const node: {[x in keyof accessibility.SerializedAXNode]: any} = {
 | 
			
		||||
  serialize(): types.SerializedAXNode {
 | 
			
		||||
    const node: {[x in keyof types.SerializedAXNode]: any} = {
 | 
			
		||||
      role: FFRoleToARIARole.get(this._role) || this._role,
 | 
			
		||||
      name: this._name || ''
 | 
			
		||||
    };
 | 
			
		||||
    const userStringProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
    const userStringProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
      'name',
 | 
			
		||||
      'value',
 | 
			
		||||
      'description',
 | 
			
		||||
@ -216,7 +217,7 @@ class FFAXNode implements accessibility.AXNode {
 | 
			
		||||
        continue;
 | 
			
		||||
      node[userStringProperty] = this._payload[userStringProperty];
 | 
			
		||||
    }
 | 
			
		||||
    const booleanProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
    const booleanProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
      'disabled',
 | 
			
		||||
      'expanded',
 | 
			
		||||
      'focused',
 | 
			
		||||
@ -235,7 +236,7 @@ class FFAXNode implements accessibility.AXNode {
 | 
			
		||||
        continue;
 | 
			
		||||
      node[booleanProperty] = value;
 | 
			
		||||
    }
 | 
			
		||||
    const tristateProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
    const tristateProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
      'checked',
 | 
			
		||||
      'pressed',
 | 
			
		||||
    ];
 | 
			
		||||
@ -245,7 +246,7 @@ class FFAXNode implements accessibility.AXNode {
 | 
			
		||||
      const value = this._payload[tristateProperty];
 | 
			
		||||
      node[tristateProperty] = value;
 | 
			
		||||
    }
 | 
			
		||||
    const numericalProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
    const numericalProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
      'level'
 | 
			
		||||
    ];
 | 
			
		||||
    for (const numericalProperty of numericalProperties) {
 | 
			
		||||
@ -253,7 +254,7 @@ class FFAXNode implements accessibility.AXNode {
 | 
			
		||||
        continue;
 | 
			
		||||
      node[numericalProperty] = this._payload[numericalProperty];
 | 
			
		||||
    }
 | 
			
		||||
    const tokenProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
    const tokenProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Accessibility.AXTree> = [
 | 
			
		||||
      'autocomplete',
 | 
			
		||||
      'haspopup',
 | 
			
		||||
      'invalid',
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,7 @@ import { TimeoutSettings } from './timeoutSettings';
 | 
			
		||||
import * as types from './types';
 | 
			
		||||
import { Events } from './events';
 | 
			
		||||
import { BrowserContext, BrowserContextBase } from './browserContext';
 | 
			
		||||
import { ConsoleMessage, ConsoleMessageLocation } from './console';
 | 
			
		||||
import { ConsoleMessage } from './console';
 | 
			
		||||
import * as accessibility from './accessibility';
 | 
			
		||||
import { EventEmitter } from 'events';
 | 
			
		||||
import { FileChooser } from './fileChooser';
 | 
			
		||||
@ -281,7 +281,7 @@ export class Page extends EventEmitter {
 | 
			
		||||
    await PageBinding.dispatch(this, payload, context);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _addConsoleMessage(type: string, args: js.JSHandle[], location: ConsoleMessageLocation, text?: string) {
 | 
			
		||||
  _addConsoleMessage(type: string, args: js.JSHandle[], location: types.ConsoleMessageLocation, text?: string) {
 | 
			
		||||
    const message = new ConsoleMessage(type, text, args, location);
 | 
			
		||||
    const intercepted = this._frameManager.interceptConsoleMessage(message);
 | 
			
		||||
    if (intercepted || !this.listenerCount(Events.Page.Console))
 | 
			
		||||
 | 
			
		||||
@ -64,6 +64,7 @@ export interface PageChannel extends Channel {
 | 
			
		||||
  on(event: 'requestFinished', callback: (params: RequestChannel) => void): this;
 | 
			
		||||
  on(event: 'requestFailed', callback: (params: RequestChannel) => void): this;
 | 
			
		||||
  on(event: 'close', callback: () => void): this;
 | 
			
		||||
  on(event: 'console', callback: (params: ConsoleMessageChannel) => void): this;
 | 
			
		||||
 | 
			
		||||
  setDefaultNavigationTimeoutNoReply(params: { timeout: number }): void;
 | 
			
		||||
  setDefaultTimeoutNoReply(params: { timeout: number }): Promise<void>;
 | 
			
		||||
@ -82,6 +83,20 @@ export interface PageChannel extends Channel {
 | 
			
		||||
  setNetworkInterceptionEnabled(params: { enabled: boolean }): Promise<void>;
 | 
			
		||||
  screenshot(params: { options?: types.ScreenshotOptions }): Promise<Buffer>;
 | 
			
		||||
  close(params: { options?: { runBeforeUnload?: boolean } }): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  // Input
 | 
			
		||||
  keyboardDown(params: { key: string }): Promise<void>;
 | 
			
		||||
  keyboardUp(params: { key: string }): Promise<void>;
 | 
			
		||||
  keyboardInsertText(params: { text: string }): Promise<void>;
 | 
			
		||||
  keyboardType(params: { text: string, options?: { delay?: number } }): Promise<void>;
 | 
			
		||||
  keyboardPress(params: { key: string, options?: { delay?: number } }): Promise<void>;
 | 
			
		||||
  mouseMove(params: { x: number, y: number, options?: { steps?: number } }): Promise<void>;
 | 
			
		||||
  mouseDown(params: { options?: { button?: types.MouseButton, clickCount?: number } }): Promise<void>;
 | 
			
		||||
  mouseUp(params: { options?: { button?: types.MouseButton, clickCount?: number } }): Promise<void>;
 | 
			
		||||
  mouseClick(params: { x: number, y: number, options?: { delay?: number, button?: types.MouseButton, clickCount?: number } }): Promise<void>;
 | 
			
		||||
 | 
			
		||||
  // A11Y
 | 
			
		||||
  accessibilitySnapshot(params: { options: { interestingOnly?: boolean, root?: ElementHandleChannel } }): Promise<types.SerializedAXNode | null>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface FrameChannel extends Channel {
 | 
			
		||||
@ -173,3 +188,5 @@ export interface ResponseChannel extends Channel {
 | 
			
		||||
  finished(): Promise<Error | null>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface ConsoleMessageChannel extends Channel {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										33
									
								
								src/rpc/client/accessibility.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/rpc/client/accessibility.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright 2017 Google Inc. All rights reserved.
 | 
			
		||||
 * Modifications copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { PageChannel } from '../channels';
 | 
			
		||||
import { ElementHandle } from './elementHandle';
 | 
			
		||||
import * as types from '../../types';
 | 
			
		||||
 | 
			
		||||
export class Accessibility {
 | 
			
		||||
  private _channel: PageChannel;
 | 
			
		||||
 | 
			
		||||
  constructor(channel: PageChannel) {
 | 
			
		||||
    this._channel = channel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  snapshot(options: { interestingOnly?: boolean; root?: ElementHandle } = {}): Promise<types.SerializedAXNode | null> {
 | 
			
		||||
    const root = options.root ? options.root._elementChannel : undefined;
 | 
			
		||||
    return this._channel.accessibilitySnapshot({ options: { interestingOnly: options.interestingOnly, root } });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										64
									
								
								src/rpc/client/console.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/rpc/client/console.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,64 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import * as util from 'util';
 | 
			
		||||
import { ConsoleMessageLocation } from '../../types';
 | 
			
		||||
import { JSHandle } from './jsHandle';
 | 
			
		||||
import { ConsoleMessageChannel, JSHandleChannel } from '../channels';
 | 
			
		||||
import { ChannelOwner } from './channelOwner';
 | 
			
		||||
import { Connection } from '../connection';
 | 
			
		||||
 | 
			
		||||
export class ConsoleMessage extends ChannelOwner<ConsoleMessageChannel> {
 | 
			
		||||
  private _type: string = '';
 | 
			
		||||
  private _text: string = '';
 | 
			
		||||
  private _args: JSHandle[] = [];
 | 
			
		||||
  private _location: ConsoleMessageLocation = {};
 | 
			
		||||
 | 
			
		||||
  static from(request: ConsoleMessageChannel): ConsoleMessage {
 | 
			
		||||
    return request._object;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(connection: Connection, channel: ConsoleMessageChannel) {
 | 
			
		||||
    super(connection, channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _initialize(params: { type: string, text: string, args: JSHandleChannel[], location: ConsoleMessageLocation }) {
 | 
			
		||||
    this._type = params.type;
 | 
			
		||||
    this._text = params.text;
 | 
			
		||||
    this._args = params.args.map(JSHandle.from);
 | 
			
		||||
    this._location = params.location;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  type(): string {
 | 
			
		||||
    return this._type;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  text(): string {
 | 
			
		||||
    return this._text;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  args(): JSHandle[] {
 | 
			
		||||
    return this._args;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  location(): ConsoleMessageLocation {
 | 
			
		||||
    return this._location;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  [util.inspect.custom]() {
 | 
			
		||||
    return this.text();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -21,7 +21,7 @@ import { FuncOn, JSHandle, convertArg } from './jsHandle';
 | 
			
		||||
import { Connection } from '../connection';
 | 
			
		||||
 | 
			
		||||
export class ElementHandle<T extends Node = Node> extends JSHandle<T> {
 | 
			
		||||
  private _elementChannel: ElementHandleChannel;
 | 
			
		||||
  readonly _elementChannel: ElementHandleChannel;
 | 
			
		||||
 | 
			
		||||
  static from(handle: ElementHandleChannel): ElementHandle {
 | 
			
		||||
    return handle._object;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										75
									
								
								src/rpc/client/input.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/rpc/client/input.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright 2017 Google Inc. All rights reserved.
 | 
			
		||||
 * Modifications copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 *     http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import * as types from '../../types';
 | 
			
		||||
import { PageChannel } from '../channels';
 | 
			
		||||
 | 
			
		||||
export class Keyboard {
 | 
			
		||||
  private _channel: PageChannel;
 | 
			
		||||
 | 
			
		||||
  constructor(channel: PageChannel) {
 | 
			
		||||
    this._channel = channel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async down(key: string) {
 | 
			
		||||
    await this._channel.keyboardDown({ key });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async up(key: string) {
 | 
			
		||||
    await this._channel.keyboardUp({ key });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async insertText(text: string) {
 | 
			
		||||
    await this._channel.keyboardInsertText({ text });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async type(text: string, options?: { delay?: number }) {
 | 
			
		||||
    await this._channel.keyboardType({ text, options });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async press(key: string, options: { delay?: number } = {}) {
 | 
			
		||||
    await this._channel.keyboardPress({ key, options });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class Mouse {
 | 
			
		||||
  private _channel: PageChannel;
 | 
			
		||||
 | 
			
		||||
  constructor(channel: PageChannel) {
 | 
			
		||||
    this._channel = channel;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async move(x: number, y: number, options: { steps?: number } = {}) {
 | 
			
		||||
    await this._channel.mouseMove({ x, y, options });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async down(options: { button?: types.MouseButton, clickCount?: number } = {}) {
 | 
			
		||||
    await this._channel.mouseDown({ options });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async up(options: { button?: types.MouseButton, clickCount?: number } = {}) {
 | 
			
		||||
    await this._channel.mouseUp({ options });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async click(x: number, y: number, options: { delay?: number, button?: types.MouseButton, clickCount?: number } = {}) {
 | 
			
		||||
    await this._channel.mouseClick({ x, y, options });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async dblclick(x: number, y: number, options: { delay?: number, button?: types.MouseButton } = {}) {
 | 
			
		||||
    await this.click(x, y, { ...options, clickCount: 2 });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -27,6 +27,9 @@ import { Frame, FunctionWithSource, GotoOptions } from './frame';
 | 
			
		||||
import { Func1, FuncOn, SmartHandle } from './jsHandle';
 | 
			
		||||
import { Request, Response, RouteHandler } from './network';
 | 
			
		||||
import { Connection } from '../connection';
 | 
			
		||||
import { Keyboard, Mouse } from './input';
 | 
			
		||||
import { Accessibility } from './accessibility';
 | 
			
		||||
import { ConsoleMessage } from './console';
 | 
			
		||||
 | 
			
		||||
export class Page extends ChannelOwner<PageChannel> {
 | 
			
		||||
  readonly pdf: ((options?: types.PDFOptions) => Promise<Buffer>) | undefined;
 | 
			
		||||
@ -39,6 +42,10 @@ export class Page extends ChannelOwner<PageChannel> {
 | 
			
		||||
  private _viewportSize: types.Size | null = null;
 | 
			
		||||
  private _routes: { url: types.URLMatch, handler: RouteHandler }[] = [];
 | 
			
		||||
 | 
			
		||||
  readonly accessibility: Accessibility;
 | 
			
		||||
  readonly keyboard: Keyboard;
 | 
			
		||||
  readonly mouse: Mouse;
 | 
			
		||||
 | 
			
		||||
  static from(page: PageChannel): Page {
 | 
			
		||||
    return page._object;
 | 
			
		||||
  }
 | 
			
		||||
@ -49,6 +56,9 @@ export class Page extends ChannelOwner<PageChannel> {
 | 
			
		||||
 | 
			
		||||
  constructor(connection: Connection, channel: PageChannel) {
 | 
			
		||||
    super(connection, channel);
 | 
			
		||||
    this.accessibility = new Accessibility(channel);
 | 
			
		||||
    this.keyboard = new Keyboard(channel);
 | 
			
		||||
    this.mouse = new Mouse(channel);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _initialize(payload: { browserContext: BrowserContextChannel, mainFrame: FrameChannel, viewportSize: types.Size }) {
 | 
			
		||||
@ -64,6 +74,7 @@ export class Page extends ChannelOwner<PageChannel> {
 | 
			
		||||
    this._channel.on('response', response => this.emit(Events.Page.Response, Response.from(response)));
 | 
			
		||||
    this._channel.on('requestFinished', request => this.emit(Events.Page.Request, Request.from(request)));
 | 
			
		||||
    this._channel.on('requestFailed', request => this.emit(Events.Page.Request, Request.from(request)));
 | 
			
		||||
    this._channel.on('console', message => this.emit(Events.Page.Console, ConsoleMessage.from(message)));
 | 
			
		||||
    this._channel.on('close', () => this._onClose());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -230,7 +241,9 @@ export class Page extends ChannelOwner<PageChannel> {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async waitForEvent(event: string, optionsOrPredicate: types.WaitForEventOptions = {}): Promise<any> {
 | 
			
		||||
    return await this._channel.waitForEvent({ event });
 | 
			
		||||
    const result = await this._channel.waitForEvent({ event });
 | 
			
		||||
    if (result._object)
 | 
			
		||||
      return result._object;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async goBack(options?: types.NavigateOptions): Promise<Response | null> {
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,7 @@ import { Request, Response } from './client/network';
 | 
			
		||||
import { Page } from './client/page';
 | 
			
		||||
import debug = require('debug');
 | 
			
		||||
import { Channel } from './channels';
 | 
			
		||||
import { ConsoleMessage } from './client/console';
 | 
			
		||||
 | 
			
		||||
export class Connection {
 | 
			
		||||
  private _channels = new Map<string, Channel>();
 | 
			
		||||
@ -65,6 +66,9 @@ export class Connection {
 | 
			
		||||
      case 'elementHandle':
 | 
			
		||||
        result = new ElementHandle(this, channel);
 | 
			
		||||
        break;
 | 
			
		||||
      case 'consoleMessage':
 | 
			
		||||
        result = new ConsoleMessage(this, channel);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        throw new Error('Missing type ' + type);
 | 
			
		||||
    }
 | 
			
		||||
@ -110,6 +114,8 @@ export class Connection {
 | 
			
		||||
          return obj.emit;
 | 
			
		||||
        if (prop === 'on')
 | 
			
		||||
          return obj.on;
 | 
			
		||||
        if (prop === 'once')
 | 
			
		||||
          return obj.once;
 | 
			
		||||
        if (prop === 'addEventListener')
 | 
			
		||||
          return obj.addListener;
 | 
			
		||||
        if (prop === 'removeEventListener')
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								src/rpc/server/consoleMessageDispatcher.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/rpc/server/consoleMessageDispatcher.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the 'License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
 * You may obtain a copy of the License at
 | 
			
		||||
 *
 | 
			
		||||
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 *
 | 
			
		||||
 * Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
 * See the License for the specific language governing permissions and
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { ConsoleMessage } from '../../console';
 | 
			
		||||
import { ConsoleMessageChannel } from '../channels';
 | 
			
		||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
 | 
			
		||||
import { ElementHandleDispatcher } from './elementHandlerDispatcher';
 | 
			
		||||
 | 
			
		||||
export class ConsoleMessageDispatcher extends Dispatcher implements ConsoleMessageChannel {
 | 
			
		||||
  static from(scope: DispatcherScope, message: ConsoleMessage): ConsoleMessageDispatcher {
 | 
			
		||||
    if ((message as any)[scope.dispatcherSymbol])
 | 
			
		||||
      return (message as any)[scope.dispatcherSymbol];
 | 
			
		||||
    return new ConsoleMessageDispatcher(scope, message);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  constructor(scope: DispatcherScope, message: ConsoleMessage) {
 | 
			
		||||
    super(scope, message, 'consoleMessage');
 | 
			
		||||
    this._initialize({
 | 
			
		||||
      type: message.type(),
 | 
			
		||||
      text: message.text(),
 | 
			
		||||
      args: message.args().map(a => ElementHandleDispatcher.from(this._scope, a)),
 | 
			
		||||
      location: message.location(),
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -14,15 +14,17 @@
 | 
			
		||||
 * limitations under the License.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { ConsoleMessage } from '../../console';
 | 
			
		||||
import { Events } from '../../events';
 | 
			
		||||
import { Frame } from '../../frames';
 | 
			
		||||
import { Page } from '../../page';
 | 
			
		||||
import * as types from '../../types';
 | 
			
		||||
import { PageChannel, ResponseChannel } from '../channels';
 | 
			
		||||
import { ElementHandleChannel, PageChannel, ResponseChannel } from '../channels';
 | 
			
		||||
import { Dispatcher, DispatcherScope } from '../dispatcher';
 | 
			
		||||
import { BrowserContextDispatcher } from './browserContextDispatcher';
 | 
			
		||||
import { FrameDispatcher } from './frameDispatcher';
 | 
			
		||||
import { RequestDispatcher, ResponseDispatcher } from './networkDispatchers';
 | 
			
		||||
import { ConsoleMessageDispatcher } from './consoleMessageDispatcher';
 | 
			
		||||
 | 
			
		||||
export class PageDispatcher extends Dispatcher implements PageChannel {
 | 
			
		||||
  private _page: Page;
 | 
			
		||||
@ -57,6 +59,7 @@ export class PageDispatcher extends Dispatcher implements PageChannel {
 | 
			
		||||
    page.on(Events.Page.Response, response => this._dispatchEvent('response', ResponseDispatcher.from(this._scope, response)));
 | 
			
		||||
    page.on(Events.Page.RequestFinished, request => this._dispatchEvent('requestFinished', ResponseDispatcher.from(this._scope, request)));
 | 
			
		||||
    page.on(Events.Page.RequestFailed, request => this._dispatchEvent('requestFailed', ResponseDispatcher.from(this._scope, request)));
 | 
			
		||||
    page.on(Events.Page.Console, message => this._dispatchEvent('console', ConsoleMessageDispatcher.from(this._scope, message)));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setDefaultNavigationTimeoutNoReply(params: { timeout: number }) {
 | 
			
		||||
@ -83,6 +86,9 @@ export class PageDispatcher extends Dispatcher implements PageChannel {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async waitForEvent(params: { event: string }): Promise<any> {
 | 
			
		||||
    const result = await this._page.waitForEvent(params.event);
 | 
			
		||||
    if (result instanceof ConsoleMessage)
 | 
			
		||||
      return ConsoleMessageDispatcher.from(this._scope, result);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async goBack(params: { options?: types.NavigateOptions }): Promise<ResponseChannel | null> {
 | 
			
		||||
@ -123,6 +129,49 @@ export class PageDispatcher extends Dispatcher implements PageChannel {
 | 
			
		||||
    return await this._page.title();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async keyboardDown(params: { key: string }): Promise<void> {
 | 
			
		||||
    await this._page.keyboard.down(params.key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async keyboardUp(params: { key: string }): Promise<void> {
 | 
			
		||||
    await this._page.keyboard.up(params.key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async keyboardInsertText(params: { text: string }): Promise<void> {
 | 
			
		||||
    await this._page.keyboard.insertText(params.text);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async keyboardType(params: { text: string, options?: { delay?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.keyboard.type(params.text, params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async keyboardPress(params: { key: string, options?: { delay?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.keyboard.press(params.key, params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async mouseMove(params: { x: number, y: number, options?: { steps?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.mouse.move(params.x, params.y, params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async mouseDown(params: { options?: { button?: types.MouseButton, clickCount?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.mouse.down(params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async mouseUp(params: { options?: { button?: types.MouseButton, clickCount?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.mouse.up(params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async mouseClick(params: { x: number, y: number, options?: { delay?: number, button?: types.MouseButton, clickCount?: number } }): Promise<void> {
 | 
			
		||||
    await this._page.mouse.click(params.x, params.y, params.options);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async accessibilitySnapshot(params: { options: { interestingOnly?: boolean, root?: ElementHandleChannel } }): Promise<types.SerializedAXNode | null> {
 | 
			
		||||
    return await this._page.accessibility.snapshot({
 | 
			
		||||
      interestingOnly: params.options.interestingOnly,
 | 
			
		||||
      root: params.options.root ? params.options.root._object : undefined
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _onFrameAttached(frame: Frame) {
 | 
			
		||||
    this._dispatchEvent('frameAttached', FrameDispatcher.from(this._scope, frame));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								src/types.ts
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								src/types.ts
									
									
									
									
									
								
							@ -1,5 +1,6 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright (c) Microsoft Corporation.
 | 
			
		||||
 * Copyright 2018 Google Inc. All rights reserved.
 | 
			
		||||
 * Modifications copyright (c) Microsoft Corporation.
 | 
			
		||||
 *
 | 
			
		||||
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
 * you may not use this file except in compliance with the License.
 | 
			
		||||
@ -263,3 +264,44 @@ export type ConnectOptions = {
 | 
			
		||||
  slowMo?: number,
 | 
			
		||||
  timeout?: number,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type SerializedAXNode = {
 | 
			
		||||
  role: string,
 | 
			
		||||
  name: string,
 | 
			
		||||
  value?: string|number,
 | 
			
		||||
  description?: string,
 | 
			
		||||
 | 
			
		||||
  keyshortcuts?: string,
 | 
			
		||||
  roledescription?: string,
 | 
			
		||||
  valuetext?: string,
 | 
			
		||||
 | 
			
		||||
  disabled?: boolean,
 | 
			
		||||
  expanded?: boolean,
 | 
			
		||||
  focused?: boolean,
 | 
			
		||||
  modal?: boolean,
 | 
			
		||||
  multiline?: boolean,
 | 
			
		||||
  multiselectable?: boolean,
 | 
			
		||||
  readonly?: boolean,
 | 
			
		||||
  required?: boolean,
 | 
			
		||||
  selected?: boolean,
 | 
			
		||||
 | 
			
		||||
  checked?: boolean | 'mixed',
 | 
			
		||||
  pressed?: boolean | 'mixed',
 | 
			
		||||
 | 
			
		||||
  level?: number,
 | 
			
		||||
  valuemin?: number,
 | 
			
		||||
  valuemax?: number,
 | 
			
		||||
 | 
			
		||||
  autocomplete?: string,
 | 
			
		||||
  haspopup?: string,
 | 
			
		||||
  invalid?: string,
 | 
			
		||||
  orientation?: string,
 | 
			
		||||
 | 
			
		||||
  children?: SerializedAXNode[]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export type ConsoleMessageLocation = {
 | 
			
		||||
  url?: string,
 | 
			
		||||
  lineNumber?: number,
 | 
			
		||||
  columnNumber?: number,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -17,6 +17,7 @@ import * as accessibility from '../accessibility';
 | 
			
		||||
import { WKSession } from './wkConnection';
 | 
			
		||||
import { Protocol } from './protocol';
 | 
			
		||||
import * as dom from '../dom';
 | 
			
		||||
import * as types from '../types';
 | 
			
		||||
 | 
			
		||||
export async function getAccessibilityTree(session: WKSession, needle?: dom.ElementHandle) {
 | 
			
		||||
  const objectId = needle ? needle._objectId : undefined;
 | 
			
		||||
@ -166,8 +167,8 @@ class WKAXNode implements accessibility.AXNode {
 | 
			
		||||
      return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    serialize(): accessibility.SerializedAXNode {
 | 
			
		||||
      const node: accessibility.SerializedAXNode = {
 | 
			
		||||
    serialize(): types.SerializedAXNode {
 | 
			
		||||
      const node: types.SerializedAXNode = {
 | 
			
		||||
        role: WKRoleToARIARole.get(this._payload.role) || this._payload.role,
 | 
			
		||||
        name: this._name(),
 | 
			
		||||
      };
 | 
			
		||||
@ -184,7 +185,7 @@ class WKAXNode implements accessibility.AXNode {
 | 
			
		||||
      if ('value' in this._payload && this._payload.role !== 'text')
 | 
			
		||||
        node.value = this._payload.value;
 | 
			
		||||
 | 
			
		||||
      const userStringProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
      const userStringProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
        'keyshortcuts',
 | 
			
		||||
        'valuetext'
 | 
			
		||||
      ];
 | 
			
		||||
@ -194,7 +195,7 @@ class WKAXNode implements accessibility.AXNode {
 | 
			
		||||
        (node as any)[userStringProperty] = this._payload[userStringProperty];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const booleanProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
      const booleanProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
        'disabled',
 | 
			
		||||
        'expanded',
 | 
			
		||||
        'focused',
 | 
			
		||||
@ -226,7 +227,7 @@ class WKAXNode implements accessibility.AXNode {
 | 
			
		||||
        const value = this._payload[tristateProperty];
 | 
			
		||||
        node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
 | 
			
		||||
      }
 | 
			
		||||
      const numericalProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
      const numericalProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
        'level',
 | 
			
		||||
        'valuemax',
 | 
			
		||||
        'valuemin',
 | 
			
		||||
@ -236,7 +237,7 @@ class WKAXNode implements accessibility.AXNode {
 | 
			
		||||
          continue;
 | 
			
		||||
        (node as any)[numericalProperty] = (this._payload as any)[numericalProperty];
 | 
			
		||||
      }
 | 
			
		||||
      const tokenProperties: Array<keyof accessibility.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
      const tokenProperties: Array<keyof types.SerializedAXNode & keyof Protocol.Page.AXNode> = [
 | 
			
		||||
        'autocomplete',
 | 
			
		||||
        'haspopup',
 | 
			
		||||
        'invalid',
 | 
			
		||||
 | 
			
		||||
@ -36,7 +36,6 @@ import { WKBrowserContext } from './wkBrowser';
 | 
			
		||||
import { selectors } from '../selectors';
 | 
			
		||||
import * as jpeg from 'jpeg-js';
 | 
			
		||||
import * as png from 'pngjs';
 | 
			
		||||
import { ConsoleMessageLocation } from '../console';
 | 
			
		||||
import { JSHandle } from '../javascript';
 | 
			
		||||
 | 
			
		||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
 | 
			
		||||
@ -63,7 +62,7 @@ export class WKPage implements PageDelegate {
 | 
			
		||||
  private _firstNonInitialNavigationCommittedPromise: Promise<void>;
 | 
			
		||||
  private _firstNonInitialNavigationCommittedFulfill = () => {};
 | 
			
		||||
  _firstNonInitialNavigationCommittedReject = (e: Error) => {};
 | 
			
		||||
  private _lastConsoleMessage: { derivedType: string, text: string, handles: JSHandle[]; count: number, location: ConsoleMessageLocation; } | null = null;
 | 
			
		||||
  private _lastConsoleMessage: { derivedType: string, text: string, handles: JSHandle[]; count: number, location: types.ConsoleMessageLocation; } | null = null;
 | 
			
		||||
 | 
			
		||||
  // Holds window features for the next popup being opened via window.open,
 | 
			
		||||
  // until the popup page proxy arrives.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user