chore: remove unneeded files, reuse events between browsers, no implicit any (#191)

This commit is contained in:
Dmitry Gozman 2019-12-10 11:15:14 -08:00 коммит произвёл GitHub
Родитель d96cd76852
Коммит f1f9dc166b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
30 изменённых файлов: 125 добавлений и 321 удалений

Просмотреть файл

@ -1,6 +0,0 @@
export interface ConnectionTransport {
send(s: string): void;
close(): void;
onmessage?: (message: string) => void,
onclose?: () => void,
}

Просмотреть файл

@ -15,7 +15,15 @@
* limitations under the License.
*/
export const DeviceDescriptors = [
import * as types from './types';
export type DeviceDescriptor = {
name: string,
userAgent: string,
viewport: types.Viewport,
};
export const DeviceDescriptors: DeviceDescriptor[] = [
{
'name': 'Blackberry PlayBook',
'userAgent': 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+',

Просмотреть файл

@ -171,7 +171,7 @@ export class Browser extends EventEmitter {
const existingTarget = this._allTargets().find(predicate);
if (existingTarget)
return existingTarget;
let resolve;
let resolve: (target: Target) => void;
const targetPromise = new Promise<Target>(x => resolve = x);
this.chromium.on(Events.Chromium.TargetCreated, check);
this.chromium.on(Events.Chromium.TargetChanged, check);

Просмотреть файл

@ -17,7 +17,7 @@
import * as debug from 'debug';
import { EventEmitter } from 'events';
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import { assert } from '../helper';
import { Protocol } from './protocol';

Просмотреть файл

@ -28,7 +28,7 @@ import { LifecycleWatcher } from './LifecycleWatcher';
import { NetworkManager, NetworkManagerEvents } from './NetworkManager';
import { Page } from '../page';
import { Protocol } from './protocol';
import { Events as CommonEvents } from '../events';
import { Events } from '../events';
import { toConsoleMessageLocation, exceptionToError, releaseObject } from './protocolHelper';
import * as dialog from '../dialog';
import { PageDelegate } from '../page';
@ -85,18 +85,18 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
(this._page as any).accessibility = new Accessibility(client);
(this._page as any).coverage = new Coverage(client);
(this._page as any).pdf = new PDF(client);
(this._page as any).workers = new Workers(client, this._page._addConsoleMessage.bind(this._page), error => this._page.emit(CommonEvents.Page.PageError, error));
(this._page as any).workers = new Workers(client, this._page._addConsoleMessage.bind(this._page), error => this._page.emit(Events.Page.PageError, error));
(this._page as any).overrides = new Overrides(client);
(this._page as any).interception = new Interception(this._networkManager);
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(CommonEvents.Page.Request, event));
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(CommonEvents.Page.Response, event));
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(CommonEvents.Page.RequestFailed, event));
this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(CommonEvents.Page.RequestFinished, event));
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(Events.Page.Request, event));
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(Events.Page.Response, event));
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(Events.Page.RequestFailed, event));
this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(Events.Page.RequestFinished, event));
this._client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
this._client.on('Log.entryAdded', event => this._onLogEntryAdded(event));
this._client.on('Page.domContentEventFired', event => this._page.emit(CommonEvents.Page.DOMContentLoaded));
this._client.on('Page.domContentEventFired', event => this._page.emit(Events.Page.DOMContentLoaded));
this._client.on('Page.fileChooserOpened', event => this._onFileChooserOpened(event));
this._client.on('Page.frameAttached', event => this._onFrameAttached(event.frameId, event.parentFrameId));
this._client.on('Page.frameDetached', event => this._onFrameDetached(event.frameId));
@ -104,7 +104,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
this._client.on('Page.frameStoppedLoading', event => this._onFrameStoppedLoading(event.frameId));
this._client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event));
this._client.on('Page.loadEventFired', event => this._page.emit(CommonEvents.Page.Load));
this._client.on('Page.loadEventFired', event => this._page.emit(Events.Page.Load));
this._client.on('Page.navigatedWithinDocument', event => this._onFrameNavigatedWithinDocument(event.frameId, event.url));
this._client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
this._client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
@ -280,10 +280,10 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
id: frameId,
loaderId: '',
};
frame[frameDataSymbol] = data;
(frame as any)[frameDataSymbol] = data;
this._frames.set(frameId, frame);
this.emit(FrameManagerEvents.FrameAttached, frame);
this._page.emit(CommonEvents.Page.FrameAttached, frame);
this._page.emit(Events.Page.FrameAttached, frame);
}
_onFrameNavigated(framePayload: Protocol.Page.Frame) {
@ -311,7 +311,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
id: framePayload.id,
loaderId: '',
};
frame[frameDataSymbol] = data;
(frame as any)[frameDataSymbol] = data;
}
this._frames.set(framePayload.id, frame);
this._mainFrame = frame;
@ -321,7 +321,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._navigated(framePayload.url, framePayload.name);
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
async _ensureIsolatedWorld(name: string) {
@ -346,7 +346,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._navigated(url, frame.name());
this.emit(FrameManagerEvents.FrameNavigatedWithinDocument, frame);
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
_onFrameDetached(frameId: string) {
@ -355,16 +355,16 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
this._removeFramesRecursively(frame);
}
_onExecutionContextCreated(contextPayload) {
_onExecutionContextCreated(contextPayload: Protocol.Runtime.ExecutionContextDescription) {
const frameId = contextPayload.auxData ? contextPayload.auxData.frameId : null;
const frame = this._frames.get(frameId) || null;
if (contextPayload.auxData && contextPayload.auxData['type'] === 'isolated')
if (contextPayload.auxData && contextPayload.auxData.type === 'isolated')
this._isolatedWorlds.add(contextPayload.name);
const context = new js.ExecutionContext(new ExecutionContextDelegate(this._client, contextPayload));
if (frame)
context._domWorld = new dom.DOMWorld(context, new DOMWorldDelegate(this, frame));
if (frame) {
if (contextPayload.auxData && !!contextPayload.auxData['isDefault'])
if (contextPayload.auxData && !!contextPayload.auxData.isDefault)
frame._contextCreated('main', context);
else if (contextPayload.name === UTILITY_WORLD_NAME)
frame._contextCreated('utility', context);
@ -398,7 +398,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._detach();
this._frames.delete(this._frameData(frame).id);
this.emit(FrameManagerEvents.FrameDetached, frame);
this._page.emit(CommonEvents.Page.FrameDetached, frame);
this._page.emit(Events.Page.FrameDetached, frame);
}
async _onConsoleAPI(event: Protocol.Runtime.consoleAPICalledPayload) {
@ -435,7 +435,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
_onDialog(event : Protocol.Page.javascriptDialogOpeningPayload) {
this._page.emit(CommonEvents.Page.Dialog, new dialog.Dialog(
this._page.emit(Events.Page.Dialog, new dialog.Dialog(
event.type as dialog.DialogType,
event.message,
async (accept: boolean, promptText?: string) => {
@ -445,7 +445,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
_handleException(exceptionDetails: Protocol.Runtime.ExceptionDetails) {
this._page.emit(CommonEvents.Page.PageError, exceptionToError(exceptionDetails));
this._page.emit(Events.Page.PageError, exceptionToError(exceptionDetails));
}
_onTargetCrashed() {
@ -457,7 +457,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
if (args)
args.map(arg => releaseObject(this._client, arg));
if (source !== 'worker')
this._page.emit(CommonEvents.Page.Console, new ConsoleMessage(level, text, [], {url, lineNumber}));
this._page.emit(Events.Page.Console, new ConsoleMessage(level, text, [], {url, lineNumber}));
}
async _onFileChooserOpened(event: Protocol.Page.fileChooserOpenedPayload) {
@ -550,8 +550,8 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
}
function assertNoLegacyNavigationOptions(options) {
assert(options['networkIdleTimeout'] === undefined, 'ERROR: networkIdleTimeout option is no longer supported.');
assert(options['networkIdleInflight'] === undefined, 'ERROR: networkIdleInflight option is no longer supported.');
assert(options.waitUntil !== 'networkidle', 'ERROR: "networkidle" option is no longer supported. Use "networkidle2" instead');
function assertNoLegacyNavigationOptions(options: frames.NavigateOptions) {
assert((options as any)['networkIdleTimeout'] === undefined, 'ERROR: networkIdleTimeout option is no longer supported.');
assert((options as any)['networkIdleInflight'] === undefined, 'ERROR: networkIdleInflight option is no longer supported.');
assert((options as any).waitUntil !== 'networkidle', 'ERROR: "networkidle" option is no longer supported. Use "networkidle2" instead');
}

Просмотреть файл

@ -31,7 +31,7 @@ import { assert, debugError, helper } from '../helper';
import * as types from '../types';
import { PipeTransport } from './PipeTransport';
import { WebSocketTransport } from './WebSocketTransport';
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import * as util from 'util';
const mkdtempAsync = helper.promisify(fs.mkdtemp);
@ -100,7 +100,7 @@ export class Launcher {
else
chromeArguments.push(...args);
let temporaryUserDataDir = null;
let temporaryUserDataDir: string | null = null;
if (!chromeArguments.some(argument => argument.startsWith('--remote-debugging-')))
chromeArguments.push(pipe ? '--remote-debugging-pipe' : '--remote-debugging-port=0');
@ -139,7 +139,7 @@ export class Launcher {
);
if (!chromeProcess.pid) {
let reject;
let reject: (e: Error) => void;
const result = new Promise((f, r) => reject = r);
chromeProcess.once('error', error => {
reject(new Error('Failed to launch browser: ' + error));
@ -160,7 +160,7 @@ export class Launcher {
if (temporaryUserDataDir) {
removeFolderAsync(temporaryUserDataDir)
.then(() => fulfill())
.catch(err => console.error(err));
.catch((err: Error) => console.error(err));
} else {
fulfill();
}
@ -344,7 +344,8 @@ function waitForWSEndpoint(chromeProcess: childProcess.ChildProcess, timeout: nu
}
function getWSEndpoint(browserURL: string): Promise<string> {
let resolve, reject;
let resolve: (url: string) => void;
let reject: (e: Error) => void;
const promise = new Promise<string>((res, rej) => { resolve = res; reject = rej; });
const endpointURL = URL.resolve(browserURL, '/json/version');
@ -423,7 +424,7 @@ export function createBrowserFetcher(projectRoot: string, options: BrowserFetche
...defaultOptions,
...options,
};
assert(!!downloadURLs[options.platform], 'Unsupported platform: ' + options.platform);
assert(!!(downloadURLs as any)[options.platform], 'Unsupported platform: ' + options.platform);
return new BrowserFetcher(options.path, options.platform, (platform: string, revision: string) => {
let archiveName = '';
@ -440,7 +441,7 @@ export function createBrowserFetcher(projectRoot: string, options: BrowserFetche
executablePath = path.join(archiveName, 'chrome.exe');
}
return {
downloadUrl: util.format(downloadURLs[platform], options.host, revision, archiveName),
downloadUrl: util.format((downloadURLs as any)[platform], options.host, revision, archiveName),
executablePath
};
});

Просмотреть файл

@ -18,7 +18,7 @@
import { CDPSessionEvents } from './Connection';
import { TimeoutError } from '../Errors';
import { FrameManager, FrameManagerEvents } from './FrameManager';
import { assert, helper, RegisteredListener } from '../helper';
import { helper, RegisteredListener } from '../helper';
import { NetworkManagerEvents } from './NetworkManager';
import * as frames from '../frames';
import * as network from '../network';

Просмотреть файл

@ -1,93 +0,0 @@
/**
* 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.
*/
export class Multimap<T, V> {
private _map: Map<T, Set<V>>;
constructor() {
this._map = new Map();
}
set(key: T, value: V) {
let set = this._map.get(key);
if (!set) {
set = new Set();
this._map.set(key, set);
}
set.add(value);
}
get(key: T): Set<V> {
let result = this._map.get(key);
if (!result)
result = new Set();
return result;
}
has(key: T): boolean {
return this._map.has(key);
}
hasValue(key: T, value: V): boolean {
const set = this._map.get(key);
if (!set)
return false;
return set.has(value);
}
get size(): number {
return this._map.size;
}
delete(key: T, value: V): boolean {
const values = this.get(key);
const result = values.delete(value);
if (!values.size)
this._map.delete(key);
return result;
}
deleteAll(key: T) {
this._map.delete(key);
}
firstValue(key: T): V {
const set = this._map.get(key);
if (!set)
return null;
return set.values().next().value;
}
firstKey(): T {
return this._map.keys().next().value;
}
valuesArray(): V[] {
const result = [];
for (const key of this._map.keys())
result.push(...Array.from(this._map.get(key).values()));
return result;
}
keysArray(): T[] {
return Array.from(this._map.keys());
}
clear() {
this._map.clear();
}
}

Просмотреть файл

@ -337,7 +337,7 @@ class InterceptableRequest {
await this._client.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: response.status || 200,
responsePhrase: STATUS_TEXTS[response.status || 200],
responsePhrase: STATUS_TEXTS[String(response.status || 200)],
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
}).catch(error => {
@ -367,7 +367,7 @@ class InterceptableRequest {
}
}
const errorReasons = {
const errorReasons: { [reason: string]: Protocol.Network.ErrorReason } = {
'aborted': 'Aborted',
'accessdenied': 'AccessDenied',
'addressunreachable': 'AddressUnreachable',
@ -401,7 +401,7 @@ function headersObject(headers: Protocol.Network.Headers): network.Headers {
}
// List taken from https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml with extra 306 and 418 codes.
const STATUS_TEXTS = {
const STATUS_TEXTS: { [status: string]: string } = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import { debugError, helper, RegisteredListener } from '../helper';
export class PipeTransport implements ConnectionTransport {

Просмотреть файл

@ -14,13 +14,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Browser } from './Browser';
import { BrowserFetcher, BrowserFetcherOptions, BrowserFetcherRevisionInfo, OnProgressCallback } from '../browserFetcher';
import { ConnectionTransport } from '../ConnectionTransport';
import { DeviceDescriptors } from '../DeviceDescriptors';
import { ConnectionTransport } from '../types';
import { DeviceDescriptors, DeviceDescriptor } from '../DeviceDescriptors';
import * as Errors from '../Errors';
import { Launcher, LauncherBrowserOptions, LauncherChromeArgOptions, LauncherLaunchOptions, createBrowserFetcher } from './Launcher';
type Devices = { [name: string]: DeviceDescriptor } & DeviceDescriptor[];
export class Playwright {
private _projectRoot: string;
private _launcher: Launcher;
@ -54,8 +57,8 @@ export class Playwright {
return this._launcher.executablePath();
}
get devices(): any {
const result = DeviceDescriptors.slice();
get devices(): Devices {
const result = DeviceDescriptors.slice() as Devices;
for (const device of DeviceDescriptors)
result[device.name] = device;
return result;

Просмотреть файл

@ -19,7 +19,7 @@ import * as types from '../types';
import { Browser } from './Browser';
import { BrowserContext } from './BrowserContext';
import { CDPSession, CDPSessionEvents } from './Connection';
import { Events as CommonEvents } from '../events';
import { Events } from '../events';
import { Worker } from './features/workers';
import { Page } from '../page';
import { Protocol } from './protocol';
@ -65,10 +65,10 @@ export class Target {
if (!opener || !opener._pagePromise || this.type() !== 'page')
return true;
const openerPage = await opener._pagePromise;
if (!openerPage.listenerCount(CommonEvents.Page.Popup))
if (!openerPage.listenerCount(Events.Page.Popup))
return true;
const popupPage = await this.page();
openerPage.emit(CommonEvents.Page.Popup, popupPage);
openerPage.emit(Events.Page.Popup, popupPage);
return true;
});
this._isInitialized = this._targetInfo.type !== 'page' || this._targetInfo.url !== '';
@ -87,7 +87,7 @@ export class Target {
const frameManager = new FrameManager(client, this._browserContext, this._ignoreHTTPSErrors);
const page = frameManager.page();
this._page = page;
page[targetSymbol] = this;
(page as any)[targetSymbol] = this;
client.once(CDPSessionEvents.Disconnected, () => page._didDisconnect());
client.on('Target.attachedToTarget', event => {
if (event.targetInfo.type !== 'worker') {

Просмотреть файл

@ -16,7 +16,7 @@
*/
import * as WebSocket from 'ws';
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
export class WebSocketTransport implements ConnectionTransport {
private _ws: WebSocket;

Просмотреть файл

@ -0,0 +1,6 @@
{
"compilerOptions": {
"noImplicitAny": true
},
"extends": "../../tsconfig.json"
}

Просмотреть файл

@ -20,6 +20,7 @@ import { assert, helper, RegisteredListener } from '../helper';
import { filterCookies, NetworkCookie, SetNetworkCookieParam, rewriteCookies } from '../network';
import { Connection, ConnectionEvents, JugglerSessionEvents } from './Connection';
import { Events } from './events';
import { Events as CommonEvents } from '../events';
import { Permissions } from './features/permissions';
import { Page } from '../page';
import * as types from '../types';
@ -164,9 +165,9 @@ export class Browser extends EventEmitter {
this._targets.set(targetId, target);
if (target.opener() && target.opener()._pagePromise) {
const openerPage = await target.opener()._pagePromise;
if (openerPage.listenerCount(Events.Page.Popup)) {
if (openerPage.listenerCount(CommonEvents.Page.Popup)) {
const popupPage = await target.page();
openerPage.emit(Events.Page.Popup, popupPage);
openerPage.emit(CommonEvents.Page.Popup, popupPage);
}
}
}

Просмотреть файл

@ -18,7 +18,7 @@
import {assert} from '../helper';
import {EventEmitter} from 'events';
import * as debug from 'debug';
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import { Protocol } from './protocol';
const debugProtocol = debug('playwright:protocol');

Просмотреть файл

@ -27,8 +27,7 @@ import { NavigationWatchdog, NextNavigationWatchdog } from './NavigationWatchdog
import { Page, PageDelegate } from '../page';
import { NetworkManager, NetworkManagerEvents } from './NetworkManager';
import { DOMWorldDelegate } from './JSHandle';
import { Events } from './events';
import { Events as CommonEvents } from '../events';
import { Events } from '../events';
import * as dialog from '../dialog';
import { Protocol } from './protocol';
import * as input from '../input';
@ -89,10 +88,10 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
helper.addEventListener(this._session, 'Page.dialogOpened', this._onDialogOpened.bind(this)),
helper.addEventListener(this._session, 'Page.bindingCalled', this._onBindingCalled.bind(this)),
helper.addEventListener(this._session, 'Page.fileChooserOpened', this._onFileChooserOpened.bind(this)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.Request, request => this._page.emit(CommonEvents.Page.Request, request)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.Response, response => this._page.emit(CommonEvents.Page.Response, response)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFinished, request => this._page.emit(CommonEvents.Page.RequestFinished, request)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFailed, request => this._page.emit(CommonEvents.Page.RequestFailed, request)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.Request, request => this._page.emit(Events.Page.Request, request)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.Response, response => this._page.emit(Events.Page.Response, response)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFinished, request => this._page.emit(Events.Page.RequestFinished, request)),
helper.addEventListener(this._networkManager, NetworkManagerEvents.RequestFailed, request => this._page.emit(Events.Page.RequestFailed, request)),
];
this._page = new Page(this, browserContext);
(this._page as any).interception = new Interception(this._networkManager);
@ -164,14 +163,14 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
data.lastCommittedNavigationId = params.navigationId;
frame._firedLifecycleEvents.clear();
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
_onSameDocumentNavigation(params) {
const frame = this._frames.get(params.frameId);
frame._navigated(params.url, frame.name());
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
_onFrameAttached(params) {
@ -188,7 +187,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
this._frames.set(params.frameId, frame);
this.emit(FrameManagerEvents.FrameAttached, frame);
this._page.emit(CommonEvents.Page.FrameAttached, frame);
this._page.emit(Events.Page.FrameAttached, frame);
}
_onFrameDetached(params) {
@ -196,7 +195,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
this._frames.delete(params.frameId);
frame._detach();
this.emit(FrameManagerEvents.FrameDetached, frame);
this._page.emit(CommonEvents.Page.FrameDetached, frame);
this._page.emit(Events.Page.FrameDetached, frame);
}
_onEventFired({frameId, name}) {
@ -205,14 +204,14 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._firedLifecycleEvents.add('load');
if (frame === this._mainFrame) {
this.emit(FrameManagerEvents.Load);
this._page.emit(CommonEvents.Page.Load);
this._page.emit(Events.Page.Load);
}
}
if (name === 'DOMContentLoaded') {
frame._firedLifecycleEvents.add('domcontentloaded');
if (frame === this._mainFrame) {
this.emit(FrameManagerEvents.DOMContentLoaded);
this._page.emit(CommonEvents.Page.DOMContentLoaded);
this._page.emit(Events.Page.DOMContentLoaded);
}
}
}

Просмотреть файл

@ -16,11 +16,13 @@
*/
import { Browser } from './Browser';
import { BrowserFetcher, BrowserFetcherOptions, OnProgressCallback, BrowserFetcherRevisionInfo } from '../browserFetcher';
import { ConnectionTransport } from '../ConnectionTransport';
import { DeviceDescriptors } from '../DeviceDescriptors';
import { ConnectionTransport } from '../types';
import { DeviceDescriptors, DeviceDescriptor } from '../DeviceDescriptors';
import * as Errors from '../Errors';
import { Launcher, createBrowserFetcher } from './Launcher';
type Devices = { [name: string]: DeviceDescriptor } & DeviceDescriptor[];
export class Playwright {
private _projectRoot: string;
private _launcher: Launcher;
@ -54,8 +56,8 @@ export class Playwright {
return this._launcher.executablePath();
}
get devices(): any {
const result = DeviceDescriptors.slice();
get devices(): Devices {
const result = DeviceDescriptors.slice() as Devices;
for (const device of DeviceDescriptors)
result[device.name] = device;
return result;

Просмотреть файл

@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import * as WebSocket from 'ws';
export class WebSocketTransport implements ConnectionTransport {

Просмотреть файл

@ -16,26 +16,6 @@
*/
export const Events = {
Page: {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
FileChooser: 'filechooser',
DOMContentLoaded: 'domcontentloaded',
// Can't use just 'error' due to node.js special treatment of error events.
// @see https://nodejs.org/api/events.html#events_error_events
PageError: 'pageerror',
Request: 'request',
Response: 'response',
RequestFailed: 'requestfailed',
RequestFinished: 'requestfinished',
FrameAttached: 'frameattached',
FrameDetached: 'framedetached',
FrameNavigated: 'framenavigated',
Load: 'load',
Popup: 'popup',
},
Browser: {
Disconnected: 'disconnected'
},

Просмотреть файл

@ -19,7 +19,7 @@ class Injected {
querySelector(selector: string, root: Node): Element | undefined {
const parsed = this._parseSelector(selector);
if (!root['querySelector'])
if (!(root as any)['querySelector'])
throw new Error('Node is not queryable.');
let element = root as SelectorRoot;
for (const { engine, selector } of parsed) {
@ -33,7 +33,7 @@ class Injected {
querySelectorAll(selector: string, root: Node): Element[] {
const parsed = this._parseSelector(selector);
if (!root['querySelectorAll'])
if (!(root as any)['querySelectorAll'])
throw new Error('Node is not queryable.');
let set = new Set<SelectorRoot>([ root as SelectorRoot ]);
for (const { engine, selector } of parsed) {
@ -105,7 +105,7 @@ class Injected {
if (success)
return Promise.resolve(success);
let fulfill;
let fulfill: (result?: any) => void;
const result = new Promise(x => fulfill = x);
const observer = new MutationObserver(mutations => {
if (timedOut) {
@ -131,7 +131,7 @@ class Injected {
if (timeout)
setTimeout(() => timedOut = true, timeout);
let fulfill;
let fulfill: (result?: any) => void;
const result = new Promise(x => fulfill = x);
onRaf();
return result;
@ -154,7 +154,7 @@ class Injected {
if (timeout)
setTimeout(() => timedOut = true, timeout);
let fulfill;
let fulfill: (result?: any) => void;
const result = new Promise(x => fulfill = x);
onTimeout();
return result;

Просмотреть файл

@ -0,0 +1,6 @@
{
"compilerOptions": {
"noImplicitAny": true
},
"extends": "../../tsconfig.json"
}

Просмотреть файл

@ -62,4 +62,11 @@ export type Viewport = {
isMobile?: boolean;
isLandscape?: boolean;
hasTouch?: boolean;
};
export interface ConnectionTransport {
send(s: string): void;
close(): void;
onmessage?: (message: string) => void,
onclose?: () => void,
}

Просмотреть файл

@ -18,7 +18,7 @@
import {assert} from '../helper';
import * as debug from 'debug';
import {EventEmitter} from 'events';
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import { Protocol } from './protocol';
const debugProtocol = debug('playwright:protocol');

Просмотреть файл

@ -23,8 +23,7 @@ import * as js from '../javascript';
import * as dom from '../dom';
import * as network from '../network';
import { TargetSession, TargetSessionEvents } from './Connection';
import { Events } from './events';
import { Events as CommonEvents } from '../events';
import { Events } from '../events';
import { ExecutionContextDelegate, EVALUATION_SCRIPT_URL } from './ExecutionContext';
import { NetworkManager, NetworkManagerEvents } from './NetworkManager';
import { Page, PageDelegate } from '../page';
@ -78,10 +77,10 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
this._contextIdToContext = new Map();
this._isolatedWorlds = new Set();
this._page = new Page(this, browserContext);
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(CommonEvents.Page.Request, event));
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(CommonEvents.Page.Response, event));
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(CommonEvents.Page.RequestFailed, event));
this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(CommonEvents.Page.RequestFinished, event));
this._networkManager.on(NetworkManagerEvents.Request, event => this._page.emit(Events.Page.Request, event));
this._networkManager.on(NetworkManagerEvents.Response, event => this._page.emit(Events.Page.Response, event));
this._networkManager.on(NetworkManagerEvents.RequestFailed, event => this._page.emit(Events.Page.RequestFailed, event));
this._networkManager.on(NetworkManagerEvents.RequestFinished, event => this._page.emit(Events.Page.RequestFinished, event));
}
async initialize(session: TargetSession) {
@ -128,9 +127,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
helper.addEventListener(this._session, 'Page.loadEventFired', event => this._onLifecycleEvent(event.frameId, 'load')),
helper.addEventListener(this._session, 'Page.domContentEventFired', event => this._onLifecycleEvent(event.frameId, 'domcontentloaded')),
helper.addEventListener(this._session, 'Runtime.executionContextCreated', event => this._onExecutionContextCreated(event.context)),
helper.addEventListener(this._session, 'Page.loadEventFired', event => this._page.emit(Events.Page.Load)),
helper.addEventListener(this._session, 'Console.messageAdded', event => this._onConsoleMessage(event)),
helper.addEventListener(this._session, 'Page.domContentEventFired', event => this._page.emit(Events.Page.DOMContentLoaded)),
helper.addEventListener(this._session, 'Dialog.javascriptDialogOpening', event => this._onDialog(event)),
helper.addEventListener(this._session, 'Page.fileChooserOpened', event => this._onFileChooserOpened(event))
];
@ -158,9 +155,9 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._firedLifecycleEvents.add('load');
this.emit(FrameManagerEvents.LifecycleEvent, frame);
if (frame === this.mainFrame() && !hasDOMContentLoaded)
this._page.emit(CommonEvents.Page.DOMContentLoaded);
this._page.emit(Events.Page.DOMContentLoaded);
if (frame === this.mainFrame() && !hasLoad)
this._page.emit(CommonEvents.Page.Load);
this._page.emit(Events.Page.Load);
}
_onLifecycleEvent(frameId: string, event: frames.LifecycleEvent) {
@ -171,9 +168,9 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
this.emit(FrameManagerEvents.LifecycleEvent, frame);
if (frame === this.mainFrame()) {
if (event === 'load')
this._page.emit(CommonEvents.Page.Load);
this._page.emit(Events.Page.Load);
if (event === 'domcontentloaded')
this._page.emit(CommonEvents.Page.DOMContentLoaded);
this._page.emit(Events.Page.DOMContentLoaded);
}
}
@ -221,7 +218,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame[frameDataSymbol] = data;
this._frames.set(frameId, frame);
this.emit(FrameManagerEvents.FrameAttached, frame);
this._page.emit(CommonEvents.Page.FrameAttached, frame);
this._page.emit(Events.Page.FrameAttached, frame);
return frame;
}
@ -273,7 +270,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
}
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
_onFrameNavigatedWithinDocument(frameId: string, url: string) {
@ -283,7 +280,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._navigated(url, frame.name());
this.emit(FrameManagerEvents.FrameNavigatedWithinDocument, frame);
this.emit(FrameManagerEvents.FrameNavigated, frame);
this._page.emit(CommonEvents.Page.FrameNavigated, frame);
this._page.emit(Events.Page.FrameNavigated, frame);
}
_onFrameDetached(frameId: string) {
@ -324,7 +321,7 @@ export class FrameManager extends EventEmitter implements frames.FrameDelegate,
frame._detach();
this._frames.delete(this._frameData(frame).id);
this.emit(FrameManagerEvents.FrameDetached, frame);
this._page.emit(CommonEvents.Page.FrameDetached, frame);
this._page.emit(Events.Page.FrameDetached, frame);
}
async navigateFrame(frame: frames.Frame, url: string, options: frames.GotoOptions = {}): Promise<network.Response | null> {
@ -589,7 +586,7 @@ class NextNavigationWatchdog {
_registerDisconnectedListener() {
if (this._disconnectedListener)
helper.removeEventListeners([this._disconnectedListener]);
helper.removeEventListeners([this._disconnectedListener]);
const session = this._frameManager._session;
this._disconnectedListener = helper.addEventListener(this._frameManager._session, TargetSessionEvents.Disconnected, () => {
// Session may change on swap out, check that it's current.

Просмотреть файл

@ -1,93 +0,0 @@
/**
* 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.
*/
export class Multimap<T, V> {
private _map: Map<T, Set<V>>;
constructor() {
this._map = new Map();
}
set(key: T, value: V) {
let set = this._map.get(key);
if (!set) {
set = new Set();
this._map.set(key, set);
}
set.add(value);
}
get(key: T): Set<V> {
let result = this._map.get(key);
if (!result)
result = new Set();
return result;
}
has(key: T): boolean {
return this._map.has(key);
}
hasValue(key: T, value: V): boolean {
const set = this._map.get(key);
if (!set)
return false;
return set.has(value);
}
get size(): number {
return this._map.size;
}
delete(key: T, value: V): boolean {
const values = this.get(key);
const result = values.delete(value);
if (!values.size)
this._map.delete(key);
return result;
}
deleteAll(key: T) {
this._map.delete(key);
}
firstValue(key: T): V {
const set = this._map.get(key);
if (!set)
return null;
return set.values().next().value;
}
firstKey(): T {
return this._map.keys().next().value;
}
valuesArray(): V[] {
const result = [];
for (const key of this._map.keys())
result.push(...Array.from(this._map.get(key).values()));
return result;
}
keysArray(): T[] {
return Array.from(this._map.keys());
}
clear() {
this._map.clear();
}
}

Просмотреть файл

@ -15,7 +15,7 @@
* limitations under the License.
*/
import { ConnectionTransport } from '../ConnectionTransport';
import { ConnectionTransport } from '../types';
import { debugError, helper, RegisteredListener } from '../helper';
export class PipeTransport implements ConnectionTransport {

Просмотреть файл

@ -16,22 +16,6 @@
*/
export const Events = {
Page: {
Close: 'close',
Console: 'console',
Dialog: 'dialog',
FileChooser: 'filechooser',
DOMContentLoaded: 'domcontentloaded',
Request: 'request',
Response: 'response',
RequestFailed: 'requestfailed',
RequestFinished: 'requestfinished',
FrameAttached: 'frameattached',
FrameDetached: 'framedetached',
FrameNavigated: 'framenavigated',
Load: 'load',
},
Browser: {
Disconnected: 'disconnected'
},

Просмотреть файл

@ -117,7 +117,7 @@ function checkSources(sources) {
function serializeSymbol(symbol, circular = []) {
const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration);
const name = symbol.getName();
if (symbol.valueDeclaration.dotDotDotToken) {
if (symbol.valueDeclaration && symbol.valueDeclaration.dotDotDotToken) {
const innerType = serializeType(type.typeArguments ? type.typeArguments[0] : type, circular);
innerType.name = '...' + innerType.name;
return Documentation.Member.createProperty('...' + name, innerType);

Просмотреть файл

@ -113,6 +113,8 @@ function typeOfProperty(property, domain) {
return typeOfProperty(property.items, domain) + '[]';
case 'integer':
return 'number';
case 'object':
return '{ [key: string]: string }';
}
return property.type;
}