chore: finish strict type checks across src (#482)
This commit is contained in:
Родитель
dbc39a8816
Коммит
fb1b3d9a89
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true
|
|
||||||
},
|
|
||||||
"extends": "../../tsconfig.json"
|
|
||||||
}
|
|
|
@ -14,8 +14,10 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as accessibility from '../accessibility';
|
import * as accessibility from '../accessibility';
|
||||||
import { FFSession } from './ffConnection';
|
import { FFSession } from './ffConnection';
|
||||||
|
import { Protocol } from './protocol';
|
||||||
|
|
||||||
export async function getAccessibilityTree(session: FFSession) : Promise<accessibility.AXNode> {
|
export async function getAccessibilityTree(session: FFSession) : Promise<accessibility.AXNode> {
|
||||||
const { tree } = await session.send('Accessibility.getFullAXTree');
|
const { tree } = await session.send('Accessibility.getFullAXTree');
|
||||||
|
@ -33,13 +35,13 @@ class FFAXNode implements accessibility.AXNode {
|
||||||
private _role: string;
|
private _role: string;
|
||||||
private _cachedHasFocusableChild: boolean|undefined;
|
private _cachedHasFocusableChild: boolean|undefined;
|
||||||
|
|
||||||
constructor(payload) {
|
constructor(payload: Protocol.AXTree) {
|
||||||
this._payload = payload;
|
this._payload = payload;
|
||||||
this._children = (payload.children || []).map(x => new FFAXNode(x));
|
this._children = (payload.children || []).map(x => new FFAXNode(x));
|
||||||
this._editable = payload.editable;
|
this._editable = !!payload.editable;
|
||||||
this._richlyEditable = this._editable && (payload.tag !== 'textarea' && payload.tag !== 'input');
|
this._richlyEditable = this._editable && (payload.tag !== 'textarea' && payload.tag !== 'input');
|
||||||
this._focusable = payload.focusable;
|
this._focusable = !!payload.focusable;
|
||||||
this._expanded = payload.expanded;
|
this._expanded = !!payload.expanded;
|
||||||
this._name = this._payload.name;
|
this._name = this._payload.name;
|
||||||
this._role = this._payload.role;
|
this._role = this._payload.role;
|
||||||
this._cachedHasFocusableChild;
|
this._cachedHasFocusableChild;
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { ConnectionTransport, SlowMoTransport } from '../transport';
|
||||||
import { ConnectionEvents, FFConnection, FFSessionEvents } from './ffConnection';
|
import { ConnectionEvents, FFConnection, FFSessionEvents } from './ffConnection';
|
||||||
import { FFPage } from './ffPage';
|
import { FFPage } from './ffPage';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
|
import { Protocol } from './protocol';
|
||||||
|
|
||||||
export type FFConnectOptions = {
|
export type FFConnectOptions = {
|
||||||
slowMo?: number,
|
slowMo?: number,
|
||||||
|
@ -124,12 +125,14 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
return Array.from(this._targets.values());
|
return Array.from(this._targets.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onTargetCreated({targetId, url, browserContextId, openerId, type}) {
|
async _onTargetCreated(payload: Protocol.Target.targetCreatedPayload) {
|
||||||
const context = browserContextId ? this._contexts.get(browserContextId) : this._defaultContext;
|
const {targetId, url, browserContextId, openerId, type} = payload;
|
||||||
|
const context = browserContextId ? this._contexts.get(browserContextId)! : this._defaultContext;
|
||||||
const target = new Target(this._connection, this, context, targetId, type, url, openerId);
|
const target = new Target(this._connection, this, context, targetId, type, url, openerId);
|
||||||
this._targets.set(targetId, target);
|
this._targets.set(targetId, target);
|
||||||
if (target.opener() && target.opener()._pagePromise) {
|
const opener = target.opener();
|
||||||
const openerPage = await target.opener()._pagePromise;
|
if (opener && opener._pagePromise) {
|
||||||
|
const openerPage = await opener._pagePromise;
|
||||||
if (openerPage.listenerCount(Events.Page.Popup)) {
|
if (openerPage.listenerCount(Events.Page.Popup)) {
|
||||||
const popupPage = await target.page();
|
const popupPage = await target.page();
|
||||||
openerPage.emit(Events.Page.Popup, popupPage);
|
openerPage.emit(Events.Page.Popup, popupPage);
|
||||||
|
@ -137,14 +140,16 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTargetDestroyed({targetId}) {
|
_onTargetDestroyed(payload: Protocol.Target.targetDestroyedPayload) {
|
||||||
const target = this._targets.get(targetId);
|
const {targetId} = payload;
|
||||||
|
const target = this._targets.get(targetId)!;
|
||||||
this._targets.delete(targetId);
|
this._targets.delete(targetId);
|
||||||
target._didClose();
|
target._didClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onTargetInfoChanged({targetId, url}) {
|
_onTargetInfoChanged(payload: Protocol.Target.targetInfoChangedPayload) {
|
||||||
const target = this._targets.get(targetId);
|
const {targetId, url} = payload;
|
||||||
|
const target = this._targets.get(targetId)!;
|
||||||
target._url = url;
|
target._url = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,14 +173,14 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
const {targetId} = await this._connection.send('Target.newPage', {
|
const {targetId} = await this._connection.send('Target.newPage', {
|
||||||
browserContextId: browserContextId || undefined
|
browserContextId: browserContextId || undefined
|
||||||
});
|
});
|
||||||
const target = this._targets.get(targetId);
|
const target = this._targets.get(targetId)!;
|
||||||
return target.page();
|
return target.page();
|
||||||
},
|
},
|
||||||
|
|
||||||
close: async (): Promise<void> => {
|
close: async (): Promise<void> => {
|
||||||
assert(browserContextId, 'Non-incognito profiles cannot be closed!');
|
assert(browserContextId, 'Non-incognito profiles cannot be closed!');
|
||||||
await this._connection.send('Target.removeBrowserContext', { browserContextId });
|
await this._connection.send('Target.removeBrowserContext', { browserContextId: browserContextId! });
|
||||||
this._contexts.delete(browserContextId);
|
this._contexts.delete(browserContextId!);
|
||||||
},
|
},
|
||||||
|
|
||||||
cookies: async (): Promise<network.NetworkCookie[]> => {
|
cookies: async (): Promise<network.NetworkCookie[]> => {
|
||||||
|
@ -196,7 +201,7 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
||||||
},
|
},
|
||||||
|
|
||||||
setPermissions: async (origin: string, permissions: string[]): Promise<void> => {
|
setPermissions: async (origin: string, permissions: string[]): Promise<void> => {
|
||||||
const webPermissionToProtocol = new Map([
|
const webPermissionToProtocol = new Map<string, 'geo' | 'microphone' | 'camera' | 'desktop-notifications'>([
|
||||||
['geolocation', 'geo'],
|
['geolocation', 'geo'],
|
||||||
['microphone', 'microphone'],
|
['microphone', 'microphone'],
|
||||||
['camera', 'camera'],
|
['camera', 'camera'],
|
||||||
|
@ -232,7 +237,7 @@ class Target {
|
||||||
private readonly _targetId: string;
|
private readonly _targetId: string;
|
||||||
private readonly _type: 'page' | 'browser';
|
private readonly _type: 'page' | 'browser';
|
||||||
_url: string;
|
_url: string;
|
||||||
private readonly _openerId: string;
|
private readonly _openerId: string | undefined;
|
||||||
|
|
||||||
constructor(connection: any, browser: FFBrowser, context: BrowserContext, targetId: string, type: 'page' | 'browser', url: string, openerId: string | undefined) {
|
constructor(connection: any, browser: FFBrowser, context: BrowserContext, targetId: string, type: 'page' | 'browser', url: string, openerId: string | undefined) {
|
||||||
this._browser = browser;
|
this._browser = browser;
|
||||||
|
@ -250,7 +255,7 @@ class Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
opener(): Target | null {
|
opener(): Target | null {
|
||||||
return this._openerId ? this._browser._targets.get(this._openerId) : null;
|
return this._openerId ? this._browser._targets.get(this._openerId)! : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
type(): 'page' | 'browser' {
|
type(): 'page' | 'browser' {
|
||||||
|
@ -266,7 +271,9 @@ class Target {
|
||||||
}
|
}
|
||||||
|
|
||||||
page(): Promise<Page> {
|
page(): Promise<Page> {
|
||||||
if (this._type === 'page' && !this._pagePromise) {
|
if (this._type !== 'page')
|
||||||
|
throw new Error(`Cannot create page for "${this._type}" target`);
|
||||||
|
if (!this._pagePromise) {
|
||||||
this._pagePromise = new Promise(async f => {
|
this._pagePromise = new Promise(async f => {
|
||||||
const session = await this._connection.createSession(this._targetId);
|
const session = await this._connection.createSession(this._targetId);
|
||||||
this._ffPage = new FFPage(session, this._context);
|
this._ffPage = new FFPage(session, this._context);
|
||||||
|
@ -291,5 +298,5 @@ export async function createTransport(options: FFConnectOptions): Promise<Connec
|
||||||
transport = options.transport;
|
transport = options.transport;
|
||||||
else if (options.browserWSEndpoint)
|
else if (options.browserWSEndpoint)
|
||||||
transport = await platform.createWebSocketTransport(options.browserWSEndpoint);
|
transport = await platform.createWebSocketTransport(options.browserWSEndpoint);
|
||||||
return SlowMoTransport.wrap(transport, options.slowMo);
|
return SlowMoTransport.wrap(transport!, options.slowMo);
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,6 +33,12 @@ export class FFConnection extends platform.EventEmitter {
|
||||||
private _sessions: Map<string, FFSession>;
|
private _sessions: Map<string, FFSession>;
|
||||||
_closed: boolean;
|
_closed: boolean;
|
||||||
|
|
||||||
|
on: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
addListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
off: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
removeListener: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
once: <T extends keyof Protocol.Events | symbol>(event: T, listener: (payload: T extends symbol ? any : Protocol.Events[T extends keyof Protocol.Events ? T : never]) => void) => this;
|
||||||
|
|
||||||
constructor(transport: ConnectionTransport) {
|
constructor(transport: ConnectionTransport) {
|
||||||
super();
|
super();
|
||||||
this._transport = transport;
|
this._transport = transport;
|
||||||
|
@ -43,17 +49,26 @@ export class FFConnection extends platform.EventEmitter {
|
||||||
this._transport.onclose = this._onClose.bind(this);
|
this._transport.onclose = this._onClose.bind(this);
|
||||||
this._sessions = new Map();
|
this._sessions = new Map();
|
||||||
this._closed = false;
|
this._closed = false;
|
||||||
|
|
||||||
|
this.on = super.on;
|
||||||
|
this.addListener = super.addListener;
|
||||||
|
this.off = super.removeListener;
|
||||||
|
this.removeListener = super.removeListener;
|
||||||
|
this.once = super.once;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromSession(session: FFSession): FFConnection {
|
static fromSession(session: FFSession): FFConnection {
|
||||||
return session._connection;
|
return session._connection!;
|
||||||
}
|
}
|
||||||
|
|
||||||
session(sessionId: string): FFSession | null {
|
session(sessionId: string): FFSession | null {
|
||||||
return this._sessions.get(sessionId) || null;
|
return this._sessions.get(sessionId) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
send(method: string, params: object | undefined = {}): Promise<any> {
|
send<T extends keyof Protocol.CommandParameters>(
|
||||||
|
method: T,
|
||||||
|
params?: Protocol.CommandParameters[T]
|
||||||
|
): Promise<Protocol.CommandReturnValues[T]> {
|
||||||
const id = this._rawSend({method, params});
|
const id = this._rawSend({method, params});
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
|
this._callbacks.set(id, {resolve, reject, error: new Error(), method});
|
||||||
|
@ -105,8 +120,8 @@ export class FFConnection extends platform.EventEmitter {
|
||||||
if (this._closed)
|
if (this._closed)
|
||||||
return;
|
return;
|
||||||
this._closed = true;
|
this._closed = true;
|
||||||
this._transport.onmessage = null;
|
this._transport.onmessage = undefined;
|
||||||
this._transport.onclose = null;
|
this._transport.onclose = undefined;
|
||||||
for (const callback of this._callbacks.values())
|
for (const callback of this._callbacks.values())
|
||||||
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
|
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
|
||||||
this._callbacks.clear();
|
this._callbacks.clear();
|
||||||
|
@ -123,7 +138,7 @@ export class FFConnection extends platform.EventEmitter {
|
||||||
|
|
||||||
async createSession(targetId: string): Promise<FFSession> {
|
async createSession(targetId: string): Promise<FFSession> {
|
||||||
const {sessionId} = await this.send('Target.attachToTarget', {targetId});
|
const {sessionId} = await this.send('Target.attachToTarget', {targetId});
|
||||||
return this._sessions.get(sessionId);
|
return this._sessions.get(sessionId)!;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,7 +147,7 @@ export const FFSessionEvents = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export class FFSession extends platform.EventEmitter {
|
export class FFSession extends platform.EventEmitter {
|
||||||
_connection: FFConnection;
|
_connection: FFConnection | null;
|
||||||
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
|
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
|
||||||
private _targetType: string;
|
private _targetType: string;
|
||||||
private _sessionId: string;
|
private _sessionId: string;
|
||||||
|
@ -148,6 +163,12 @@ export class FFSession extends platform.EventEmitter {
|
||||||
this._connection = connection;
|
this._connection = connection;
|
||||||
this._targetType = targetType;
|
this._targetType = targetType;
|
||||||
this._sessionId = sessionId;
|
this._sessionId = sessionId;
|
||||||
|
|
||||||
|
this.on = super.on;
|
||||||
|
this.addListener = super.addListener;
|
||||||
|
this.off = super.removeListener;
|
||||||
|
this.removeListener = super.removeListener;
|
||||||
|
this.once = super.once;
|
||||||
}
|
}
|
||||||
|
|
||||||
send<T extends keyof Protocol.CommandParameters>(
|
send<T extends keyof Protocol.CommandParameters>(
|
||||||
|
@ -164,7 +185,7 @@ export class FFSession extends platform.EventEmitter {
|
||||||
|
|
||||||
_onMessage(object: { id?: number; method: string; params: object; error: { message: string; data: any; }; result?: any; }) {
|
_onMessage(object: { id?: number; method: string; params: object; error: { message: string; data: any; }; result?: any; }) {
|
||||||
if (object.id && this._callbacks.has(object.id)) {
|
if (object.id && this._callbacks.has(object.id)) {
|
||||||
const callback = this._callbacks.get(object.id);
|
const callback = this._callbacks.get(object.id)!;
|
||||||
this._callbacks.delete(object.id);
|
this._callbacks.delete(object.id);
|
||||||
if (object.error)
|
if (object.error)
|
||||||
callback.reject(createProtocolError(callback.error, callback.method, object));
|
callback.reject(createProtocolError(callback.error, callback.method, object));
|
||||||
|
@ -176,12 +197,6 @@ export class FFSession extends platform.EventEmitter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async detach() {
|
|
||||||
if (!this._connection)
|
|
||||||
throw new Error(`Session already detached. Most likely the ${this._targetType} has been closed.`);
|
|
||||||
await this._connection.send('Target.detachFromTarget', {sessionId: this._sessionId});
|
|
||||||
}
|
|
||||||
|
|
||||||
_onClosed() {
|
_onClosed() {
|
||||||
for (const callback of this._callbacks.values())
|
for (const callback of this._callbacks.values())
|
||||||
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
|
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
|
||||||
|
|
|
@ -105,7 +105,7 @@ export class FFExecutionContext implements js.ExecutionContextDelegate {
|
||||||
checkException(payload.exceptionDetails);
|
checkException(payload.exceptionDetails);
|
||||||
return context._createHandle(payload.result);
|
return context._createHandle(payload.result);
|
||||||
|
|
||||||
function rewriteError(error) : never {
|
function rewriteError(error: Error) : never {
|
||||||
if (error.message.includes('Failed to find execution context with id') || error.message.includes('Execution context was destroyed!'))
|
if (error.message.includes('Failed to find execution context with id') || error.message.includes('Execution context was destroyed!'))
|
||||||
throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
throw new Error('Execution context was destroyed, most likely because of a navigation.');
|
||||||
throw error;
|
throw error;
|
||||||
|
@ -146,10 +146,10 @@ export class FFExecutionContext implements js.ExecutionContextDelegate {
|
||||||
const simpleValue = await this._session.send('Runtime.callFunction', {
|
const simpleValue = await this._session.send('Runtime.callFunction', {
|
||||||
executionContextId: this._executionContextId,
|
executionContextId: this._executionContextId,
|
||||||
returnByValue: true,
|
returnByValue: true,
|
||||||
functionDeclaration: (e => e).toString(),
|
functionDeclaration: ((e: any) => e).toString(),
|
||||||
args: [this._toCallArgument(payload)],
|
args: [this._toCallArgument(payload)],
|
||||||
});
|
});
|
||||||
return deserializeValue(simpleValue.result);
|
return deserializeValue(simpleValue.result!);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToString(handle: js.JSHandle, includeType: boolean): string {
|
handleToString(handle: js.JSHandle, includeType: boolean): string {
|
||||||
|
|
|
@ -38,6 +38,7 @@ function toButtonNumber(button: input.Button): number {
|
||||||
return 1;
|
return 1;
|
||||||
if (button === 'right')
|
if (button === 'right')
|
||||||
return 2;
|
return 2;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toButtonsMask(buttons: Set<input.Button>): number {
|
function toButtonsMask(buttons: Set<input.Button>): number {
|
||||||
|
|
|
@ -21,6 +21,7 @@ import { Page } from '../page';
|
||||||
import * as network from '../network';
|
import * as network from '../network';
|
||||||
import * as frames from '../frames';
|
import * as frames from '../frames';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
|
import { Protocol } from './protocol';
|
||||||
|
|
||||||
export class FFNetworkManager {
|
export class FFNetworkManager {
|
||||||
private _session: FFSession;
|
private _session: FFSession;
|
||||||
|
@ -46,11 +47,11 @@ export class FFNetworkManager {
|
||||||
helper.removeEventListeners(this._eventListeners);
|
helper.removeEventListeners(this._eventListeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRequestInterception(enabled) {
|
async setRequestInterception(enabled: boolean) {
|
||||||
await this._session.send('Network.setRequestInterception', {enabled});
|
await this._session.send('Network.setRequestInterception', {enabled});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRequestWillBeSent(event) {
|
_onRequestWillBeSent(event: Protocol.Network.requestWillBeSentPayload) {
|
||||||
const redirected = event.redirectedFrom ? this._requests.get(event.redirectedFrom) : null;
|
const redirected = event.redirectedFrom ? this._requests.get(event.redirectedFrom) : null;
|
||||||
const frame = redirected ? redirected.request.frame() : (event.frameId ? this._page._frameManager.frame(event.frameId) : null);
|
const frame = redirected ? redirected.request.frame() : (event.frameId ? this._page._frameManager.frame(event.frameId) : null);
|
||||||
if (!frame)
|
if (!frame)
|
||||||
|
@ -66,11 +67,11 @@ export class FFNetworkManager {
|
||||||
this._page._frameManager.requestStarted(request.request);
|
this._page._frameManager.requestStarted(request.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onResponseReceived(event) {
|
_onResponseReceived(event: Protocol.Network.responseReceivedPayload) {
|
||||||
const request = this._requests.get(event.requestId);
|
const request = this._requests.get(event.requestId);
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
const remoteAddress: network.RemoteAddress = { ip: event.remoteIPAddress, port: event.remotePort };
|
const remoteAddress: network.RemoteAddress = { ip: event.remoteIPAddress || '', port: event.remotePort || 0 };
|
||||||
const getResponseBody = async () => {
|
const getResponseBody = async () => {
|
||||||
const response = await this._session.send('Network.getResponseBody', {
|
const response = await this._session.send('Network.getResponseBody', {
|
||||||
requestId: request._id
|
requestId: request._id
|
||||||
|
@ -86,11 +87,11 @@ export class FFNetworkManager {
|
||||||
this._page._frameManager.requestReceivedResponse(response);
|
this._page._frameManager.requestReceivedResponse(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRequestFinished(event) {
|
_onRequestFinished(event: Protocol.Network.requestFinishedPayload) {
|
||||||
const request = this._requests.get(event.requestId);
|
const request = this._requests.get(event.requestId);
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
const response = request.request.response();
|
const response = request.request.response()!;
|
||||||
// Keep redirected requests in the map for future reference in redirectChain.
|
// Keep redirected requests in the map for future reference in redirectChain.
|
||||||
const isRedirected = response.status() >= 300 && response.status() <= 399;
|
const isRedirected = response.status() >= 300 && response.status() <= 399;
|
||||||
if (isRedirected) {
|
if (isRedirected) {
|
||||||
|
@ -102,19 +103,20 @@ export class FFNetworkManager {
|
||||||
this._page._frameManager.requestFinished(request.request);
|
this._page._frameManager.requestFinished(request.request);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRequestFailed(event) {
|
_onRequestFailed(event: Protocol.Network.requestFailedPayload) {
|
||||||
const request = this._requests.get(event.requestId);
|
const request = this._requests.get(event.requestId);
|
||||||
if (!request)
|
if (!request)
|
||||||
return;
|
return;
|
||||||
this._requests.delete(request._id);
|
this._requests.delete(request._id);
|
||||||
if (request.request.response())
|
const response = request.request.response();
|
||||||
request.request.response()._requestFinished();
|
if (response)
|
||||||
|
response._requestFinished();
|
||||||
request.request._setFailureText(event.errorCode);
|
request.request._setFailureText(event.errorCode);
|
||||||
this._page._frameManager.requestFailed(request.request, event.errorCode === 'NS_BINDING_ABORTED');
|
this._page._frameManager.requestFailed(request.request, event.errorCode === 'NS_BINDING_ABORTED');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const causeToResourceType = {
|
const causeToResourceType: {[key: string]: string} = {
|
||||||
TYPE_INVALID: 'other',
|
TYPE_INVALID: 'other',
|
||||||
TYPE_OTHER: 'other',
|
TYPE_OTHER: 'other',
|
||||||
TYPE_SCRIPT: 'script',
|
TYPE_SCRIPT: 'script',
|
||||||
|
@ -145,7 +147,7 @@ class InterceptableRequest implements network.RequestDelegate {
|
||||||
_id: string;
|
_id: string;
|
||||||
private _session: FFSession;
|
private _session: FFSession;
|
||||||
|
|
||||||
constructor(session: FFSession, frame: frames.Frame, redirectChain: network.Request[], payload: any) {
|
constructor(session: FFSession, frame: frames.Frame, redirectChain: network.Request[], payload: Protocol.Network.requestWillBeSentPayload) {
|
||||||
this._id = payload.requestId;
|
this._id = payload.requestId;
|
||||||
this._session = session;
|
this._session = session;
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,8 @@ export class FFPage implements PageDelegate {
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onExecutionContextCreated({executionContextId, auxData}) {
|
_onExecutionContextCreated(payload: Protocol.Runtime.executionContextCreatedPayload) {
|
||||||
|
const {executionContextId, auxData} = payload;
|
||||||
const frame = this._page._frameManager.frame(auxData ? auxData.frameId : null);
|
const frame = this._page._frameManager.frame(auxData ? auxData.frameId : null);
|
||||||
if (!frame)
|
if (!frame)
|
||||||
return;
|
return;
|
||||||
|
@ -98,7 +99,8 @@ export class FFPage implements PageDelegate {
|
||||||
this._contextIdToContext.set(executionContextId, context);
|
this._contextIdToContext.set(executionContextId, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onExecutionContextDestroyed({executionContextId}) {
|
_onExecutionContextDestroyed(payload: Protocol.Runtime.executionContextDestroyedPayload) {
|
||||||
|
const {executionContextId} = payload;
|
||||||
const context = this._contextIdToContext.get(executionContextId);
|
const context = this._contextIdToContext.get(executionContextId);
|
||||||
if (!context)
|
if (!context)
|
||||||
return;
|
return;
|
||||||
|
@ -110,7 +112,7 @@ export class FFPage implements PageDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onNavigationAborted(params: Protocol.Page.navigationAbortedPayload) {
|
_onNavigationAborted(params: Protocol.Page.navigationAbortedPayload) {
|
||||||
const frame = this._page._frameManager.frame(params.frameId);
|
const frame = this._page._frameManager.frame(params.frameId)!;
|
||||||
for (const watcher of this._page._frameManager._lifecycleWatchers)
|
for (const watcher of this._page._frameManager._lifecycleWatchers)
|
||||||
watcher._onAbortedNewDocumentNavigation(frame, params.navigationId, params.errorText);
|
watcher._onAbortedNewDocumentNavigation(frame, params.navigationId, params.errorText);
|
||||||
}
|
}
|
||||||
|
@ -131,7 +133,8 @@ export class FFPage implements PageDelegate {
|
||||||
this._page._frameManager.frameDetached(params.frameId);
|
this._page._frameManager.frameDetached(params.frameId);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onEventFired({frameId, name}) {
|
_onEventFired(payload: Protocol.Page.eventFiredPayload) {
|
||||||
|
const {frameId, name} = payload;
|
||||||
if (name === 'load')
|
if (name === 'load')
|
||||||
this._page._frameManager.frameLifecycleEvent(frameId, 'load');
|
this._page._frameManager.frameLifecycleEvent(frameId, 'load');
|
||||||
if (name === 'DOMContentLoaded')
|
if (name === 'DOMContentLoaded')
|
||||||
|
@ -144,8 +147,9 @@ export class FFPage implements PageDelegate {
|
||||||
this._page.emit(Events.Page.PageError, error);
|
this._page.emit(Events.Page.PageError, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onConsole({type, args, executionContextId, location}) {
|
_onConsole(payload: Protocol.Runtime.consolePayload) {
|
||||||
const context = this._contextIdToContext.get(executionContextId);
|
const {type, args, executionContextId, location} = payload;
|
||||||
|
const context = this._contextIdToContext.get(executionContextId)!;
|
||||||
this._page._addConsoleMessage(type, args.map(arg => context._createHandle(arg)), location);
|
this._page._addConsoleMessage(type, args.map(arg => context._createHandle(arg)), location);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,12 +164,13 @@ export class FFPage implements PageDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onBindingCalled(event: Protocol.Page.bindingCalledPayload) {
|
_onBindingCalled(event: Protocol.Page.bindingCalledPayload) {
|
||||||
const context = this._contextIdToContext.get(event.executionContextId);
|
const context = this._contextIdToContext.get(event.executionContextId)!;
|
||||||
this._page._onBindingCalled(event.payload, context);
|
this._page._onBindingCalled(event.payload, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFileChooserOpened({executionContextId, element}) {
|
async _onFileChooserOpened(payload: Protocol.Page.fileChooserOpenedPayload) {
|
||||||
const context = this._contextIdToContext.get(executionContextId);
|
const {executionContextId, element} = payload;
|
||||||
|
const context = this._contextIdToContext.get(executionContextId)!;
|
||||||
const handle = context._createHandle(element).asElement()!;
|
const handle = context._createHandle(element).asElement()!;
|
||||||
this._page._onFileChooserOpened(handle);
|
this._page._onFileChooserOpened(handle);
|
||||||
}
|
}
|
||||||
|
@ -184,7 +189,7 @@ export class FFPage implements PageDelegate {
|
||||||
|
|
||||||
async navigateFrame(frame: frames.Frame, url: string, referer: string | undefined): Promise<frames.GotoResult> {
|
async navigateFrame(frame: frames.Frame, url: string, referer: string | undefined): Promise<frames.GotoResult> {
|
||||||
const response = await this._session.send('Page.navigate', { url, referer, frameId: frame._id });
|
const response = await this._session.send('Page.navigate', { url, referer, frameId: frame._id });
|
||||||
return { newDocumentId: response.navigationId, isSameDocument: !response.navigationId };
|
return { newDocumentId: response.navigationId || undefined, isSameDocument: !response.navigationId };
|
||||||
}
|
}
|
||||||
|
|
||||||
needsLifecycleResetOnSetContent(): boolean {
|
needsLifecycleResetOnSetContent(): boolean {
|
||||||
|
@ -292,7 +297,7 @@ export class FFPage implements PageDelegate {
|
||||||
async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
|
async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
|
||||||
const { frameId } = await this._session.send('Page.contentFrame', {
|
const { frameId } = await this._session.send('Page.contentFrame', {
|
||||||
frameId: handle._context.frame._id,
|
frameId: handle._context.frame._id,
|
||||||
objectId: toRemoteObject(handle).objectId,
|
objectId: toRemoteObject(handle).objectId!,
|
||||||
});
|
});
|
||||||
if (!frameId)
|
if (!frameId)
|
||||||
return null;
|
return null;
|
||||||
|
@ -329,7 +334,7 @@ export class FFPage implements PageDelegate {
|
||||||
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
async getContentQuads(handle: dom.ElementHandle): Promise<types.Quad[] | null> {
|
||||||
const result = await this._session.send('Page.getContentQuads', {
|
const result = await this._session.send('Page.getContentQuads', {
|
||||||
frameId: handle._context.frame._id,
|
frameId: handle._context.frame._id,
|
||||||
objectId: toRemoteObject(handle).objectId,
|
objectId: toRemoteObject(handle).objectId!,
|
||||||
}).catch(debugError);
|
}).catch(debugError);
|
||||||
if (!result)
|
if (!result)
|
||||||
return null;
|
return null;
|
||||||
|
@ -340,7 +345,7 @@ export class FFPage implements PageDelegate {
|
||||||
return this._page.evaluate(() => ({ width: innerWidth, height: innerHeight }));
|
return this._page.evaluate(() => ({ width: innerWidth, height: innerHeight }));
|
||||||
}
|
}
|
||||||
|
|
||||||
async setInputFiles(handle: dom.ElementHandle, files: types.FilePayload[]): Promise<void> {
|
async setInputFiles(handle: dom.ElementHandle<HTMLInputElement>, files: types.FilePayload[]): Promise<void> {
|
||||||
await handle.evaluate(dom.setFileInputFunction, files);
|
await handle.evaluate(dom.setFileInputFunction, files);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -69,7 +69,7 @@ class Helper {
|
||||||
const value = target[key];
|
const value = target[key];
|
||||||
if (typeof key === 'string' && key.startsWith('_') || typeof value !== 'function')
|
if (typeof key === 'string' && key.startsWith('_') || typeof value !== 'function')
|
||||||
return value;
|
return value;
|
||||||
return function(...args: any) {
|
return function(this: any, ...args: any) {
|
||||||
if (args.length)
|
if (args.length)
|
||||||
log(`${className}.${key} %o`, args);
|
log(`${className}.${key} %o`, args);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true
|
|
||||||
},
|
|
||||||
"extends": "../../tsconfig.json"
|
|
||||||
}
|
|
|
@ -108,7 +108,7 @@ export class Screenshotter {
|
||||||
const viewport = this._page.viewport();
|
const viewport = this._page.viewport();
|
||||||
if (!this._page._delegate.canScreenshotOutsideViewport()) {
|
if (!this._page._delegate.canScreenshotOutsideViewport()) {
|
||||||
if (!viewport) {
|
if (!viewport) {
|
||||||
viewportSize = await this._page.evaluate(() => {
|
const maybeViewportSize = await this._page.evaluate(() => {
|
||||||
if (!document.body || !document.documentElement)
|
if (!document.body || !document.documentElement)
|
||||||
return;
|
return;
|
||||||
return {
|
return {
|
||||||
|
@ -116,8 +116,9 @@ export class Screenshotter {
|
||||||
height: Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
|
height: Math.max(document.body.offsetHeight, document.documentElement.offsetHeight),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
if (!viewportSize)
|
if (!maybeViewportSize)
|
||||||
throw new Error(kScreenshotDuringNavigationError);
|
throw new Error(kScreenshotDuringNavigationError);
|
||||||
|
viewportSize = maybeViewportSize!;
|
||||||
} else {
|
} else {
|
||||||
viewportSize = viewport;
|
viewportSize = viewport;
|
||||||
}
|
}
|
||||||
|
@ -137,7 +138,7 @@ export class Screenshotter {
|
||||||
if (!overridenViewport)
|
if (!overridenViewport)
|
||||||
rewrittenOptions.clip = boundingBox;
|
rewrittenOptions.clip = boundingBox;
|
||||||
|
|
||||||
const result = await this._screenshot(format, rewrittenOptions, overridenViewport || viewport);
|
const result = await this._screenshot(format, rewrittenOptions, (overridenViewport || viewport)!);
|
||||||
|
|
||||||
if (overridenViewport) {
|
if (overridenViewport) {
|
||||||
if (viewport)
|
if (viewport)
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true
|
|
||||||
},
|
|
||||||
"extends": "../../tsconfig.json"
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"strict": true
|
|
||||||
},
|
|
||||||
"extends": "../../tsconfig.json"
|
|
||||||
}
|
|
|
@ -101,12 +101,8 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
role: this._payload.role,
|
role: this._payload.role,
|
||||||
name: this._payload.name || '',
|
name: this._payload.name || '',
|
||||||
};
|
};
|
||||||
type AXPropertyOfType<Type> = {
|
|
||||||
[Key in keyof Protocol.Page.AXNode]:
|
|
||||||
Protocol.Page.AXNode[Key] extends Type ? Key : never
|
|
||||||
}[keyof Protocol.Page.AXNode];
|
|
||||||
|
|
||||||
const userStringProperties: AXPropertyOfType<string>[] = [
|
const userStringProperties: string[] = [
|
||||||
'value',
|
'value',
|
||||||
'description',
|
'description',
|
||||||
'keyshortcuts',
|
'keyshortcuts',
|
||||||
|
@ -116,10 +112,10 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
for (const userStringProperty of userStringProperties) {
|
for (const userStringProperty of userStringProperties) {
|
||||||
if (!(userStringProperty in this._payload))
|
if (!(userStringProperty in this._payload))
|
||||||
continue;
|
continue;
|
||||||
node[userStringProperty] = this._payload[userStringProperty];
|
(node as any)[userStringProperty] = (this._payload as any)[userStringProperty];
|
||||||
}
|
}
|
||||||
|
|
||||||
const booleanProperties: AXPropertyOfType<boolean>[] = [
|
const booleanProperties: string[] = [
|
||||||
'disabled',
|
'disabled',
|
||||||
'expanded',
|
'expanded',
|
||||||
'focused',
|
'focused',
|
||||||
|
@ -135,10 +131,10 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
// not whether focus is specifically on the root node.
|
// not whether focus is specifically on the root node.
|
||||||
if (booleanProperty === 'focused' && (this._payload.role === 'WebArea' || this._payload.role === 'ScrollArea'))
|
if (booleanProperty === 'focused' && (this._payload.role === 'WebArea' || this._payload.role === 'ScrollArea'))
|
||||||
continue;
|
continue;
|
||||||
const value = this._payload[booleanProperty];
|
const value = (this._payload as any)[booleanProperty];
|
||||||
if (!value)
|
if (!value)
|
||||||
continue;
|
continue;
|
||||||
node[booleanProperty] = value;
|
(node as any)[booleanProperty] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tristateProperties: ('checked'|'pressed')[] = [
|
const tristateProperties: ('checked'|'pressed')[] = [
|
||||||
|
@ -151,7 +147,7 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
const value = this._payload[tristateProperty];
|
const value = this._payload[tristateProperty];
|
||||||
node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
|
node[tristateProperty] = value === 'mixed' ? 'mixed' : value === 'true' ? true : false;
|
||||||
}
|
}
|
||||||
const numericalProperties: AXPropertyOfType<number>[] = [
|
const numericalProperties: string[] = [
|
||||||
'level',
|
'level',
|
||||||
'valuemax',
|
'valuemax',
|
||||||
'valuemin',
|
'valuemin',
|
||||||
|
@ -159,18 +155,18 @@ class WKAXNode implements accessibility.AXNode {
|
||||||
for (const numericalProperty of numericalProperties) {
|
for (const numericalProperty of numericalProperties) {
|
||||||
if (!(numericalProperty in this._payload))
|
if (!(numericalProperty in this._payload))
|
||||||
continue;
|
continue;
|
||||||
node[numericalProperty] = this._payload[numericalProperty];
|
(node as any)[numericalProperty] = (this._payload as any)[numericalProperty];
|
||||||
}
|
}
|
||||||
const tokenProperties: AXPropertyOfType<string>[] = [
|
const tokenProperties: string[] = [
|
||||||
'autocomplete',
|
'autocomplete',
|
||||||
'haspopup',
|
'haspopup',
|
||||||
'invalid',
|
'invalid',
|
||||||
];
|
];
|
||||||
for (const tokenProperty of tokenProperties) {
|
for (const tokenProperty of tokenProperties) {
|
||||||
const value = this._payload[tokenProperty];
|
const value = (this._payload as any)[tokenProperty];
|
||||||
if (!value || value === 'false')
|
if (!value || value === 'false')
|
||||||
continue;
|
continue;
|
||||||
node[tokenProperty] = value;
|
(node as any)[tokenProperty] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const orientationIsApplicable = new Set([
|
const orientationIsApplicable = new Set([
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"rootDir": "./src",
|
"rootDir": "./src",
|
||||||
"outDir": "./lib",
|
"outDir": "./lib",
|
||||||
"strictBindCallApply": true,
|
"strict": true,
|
||||||
"declaration": true
|
"declaration": true
|
||||||
},
|
},
|
||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
|
|
|
@ -9,7 +9,7 @@ async function generateChromiunProtocol(revision) {
|
||||||
const outputPath = path.join(__dirname, '..', '..', 'src', 'chromium', 'protocol.ts');
|
const outputPath = path.join(__dirname, '..', '..', 'src', 'chromium', 'protocol.ts');
|
||||||
if (revision.local && fs.existsSync(outputPath))
|
if (revision.local && fs.existsSync(outputPath))
|
||||||
return;
|
return;
|
||||||
const playwright = await require('../../chromium');
|
const playwright = await require('../../index').chromium;
|
||||||
const browserServer = await playwright.launchServer({executablePath: revision.executablePath});
|
const browserServer = await playwright.launchServer({executablePath: revision.executablePath});
|
||||||
const origin = browserServer.wsEndpoint().match(/ws:\/\/([0-9A-Za-z:\.]*)\//)[1];
|
const origin = browserServer.wsEndpoint().match(/ws:\/\/([0-9A-Za-z:\.]*)\//)[1];
|
||||||
const page = await (await browserServer.connect()).defaultContext().newPage();
|
const page = await (await browserServer.connect()).defaultContext().newPage();
|
||||||
|
@ -211,7 +211,7 @@ function firefoxTypeToString(type, indent=' ') {
|
||||||
if (type['$type'] === 'array')
|
if (type['$type'] === 'array')
|
||||||
return firefoxTypeToString(type['$items'], indent) + '[]';
|
return firefoxTypeToString(type['$items'], indent) + '[]';
|
||||||
if (type['$type'] === 'enum')
|
if (type['$type'] === 'enum')
|
||||||
return type['$values'].map(v => JSON.stringify(v)).join('|');
|
return '(' + type['$values'].map(v => JSON.stringify(v)).join('|') + ')';
|
||||||
return type['$type'];
|
return type['$type'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче