build: push tvapp v2 docker files

This commit is contained in:
2025-02-20 13:10:51 -07:00
parent bee45668cc
commit 9e79e42d09
536 changed files with 142093 additions and 5531 deletions

View File

@@ -0,0 +1,204 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.AndroidSocketDispatcher = exports.AndroidDispatcher = exports.AndroidDeviceDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _android = require("../android/android");
var _browserContextDispatcher = require("./browserContextDispatcher");
/**
* 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.
*/
class AndroidDispatcher extends _dispatcher.Dispatcher {
constructor(scope, android) {
super(scope, android, 'Android', {});
this._type_Android = true;
}
async devices(params) {
const devices = await this._object.devices(params);
return {
devices: devices.map(d => AndroidDeviceDispatcher.from(this, d))
};
}
async setDefaultTimeoutNoReply(params) {
this._object.setDefaultTimeout(params.timeout);
}
}
exports.AndroidDispatcher = AndroidDispatcher;
class AndroidDeviceDispatcher extends _dispatcher.Dispatcher {
static from(scope, device) {
const result = (0, _dispatcher.existingDispatcher)(device);
return result || new AndroidDeviceDispatcher(scope, device);
}
constructor(scope, device) {
super(scope, device, 'AndroidDevice', {
model: device.model,
serial: device.serial
});
this._type_EventTarget = true;
this._type_AndroidDevice = true;
for (const webView of device.webViews()) this._dispatchEvent('webViewAdded', {
webView
});
this.addObjectListener(_android.AndroidDevice.Events.WebViewAdded, webView => this._dispatchEvent('webViewAdded', {
webView
}));
this.addObjectListener(_android.AndroidDevice.Events.WebViewRemoved, socketName => this._dispatchEvent('webViewRemoved', {
socketName
}));
this.addObjectListener(_android.AndroidDevice.Events.Close, socketName => this._dispatchEvent('close'));
}
async wait(params) {
await this._object.send('wait', params);
}
async fill(params) {
await this._object.send('click', {
selector: params.selector
});
await this._object.send('fill', params);
}
async tap(params) {
await this._object.send('click', params);
}
async drag(params) {
await this._object.send('drag', params);
}
async fling(params) {
await this._object.send('fling', params);
}
async longTap(params) {
await this._object.send('longClick', params);
}
async pinchClose(params) {
await this._object.send('pinchClose', params);
}
async pinchOpen(params) {
await this._object.send('pinchOpen', params);
}
async scroll(params) {
await this._object.send('scroll', params);
}
async swipe(params) {
await this._object.send('swipe', params);
}
async info(params) {
const info = await this._object.send('info', params);
fixupAndroidElementInfo(info);
return {
info
};
}
async inputType(params) {
const text = params.text;
const keyCodes = [];
for (let i = 0; i < text.length; ++i) {
const code = keyMap.get(text[i].toUpperCase());
if (code === undefined) throw new Error('No mapping for ' + text[i] + ' found');
keyCodes.push(code);
}
await Promise.all(keyCodes.map(keyCode => this._object.send('inputPress', {
keyCode
})));
}
async inputPress(params) {
if (!keyMap.has(params.key)) throw new Error('Unknown key: ' + params.key);
await this._object.send('inputPress', {
keyCode: keyMap.get(params.key)
});
}
async inputTap(params) {
await this._object.send('inputClick', params);
}
async inputSwipe(params) {
await this._object.send('inputSwipe', params);
}
async inputDrag(params) {
await this._object.send('inputDrag', params);
}
async screenshot(params) {
return {
binary: await this._object.screenshot()
};
}
async shell(params) {
return {
result: await this._object.shell(params.command)
};
}
async open(params, metadata) {
const socket = await this._object.open(params.command);
return {
socket: new AndroidSocketDispatcher(this, socket)
};
}
async installApk(params) {
await this._object.installApk(params.file, {
args: params.args
});
}
async push(params) {
await this._object.push(params.file, params.path, params.mode);
}
async launchBrowser(params) {
const context = await this._object.launchBrowser(params.pkg, params);
return {
context: new _browserContextDispatcher.BrowserContextDispatcher(this, context)
};
}
async close(params) {
await this._object.close();
}
async setDefaultTimeoutNoReply(params) {
this._object.setDefaultTimeout(params.timeout);
}
async connectToWebView(params) {
return {
context: new _browserContextDispatcher.BrowserContextDispatcher(this, await this._object.connectToWebView(params.socketName))
};
}
}
exports.AndroidDeviceDispatcher = AndroidDeviceDispatcher;
class AndroidSocketDispatcher extends _dispatcher.Dispatcher {
constructor(scope, socket) {
super(scope, socket, 'AndroidSocket', {});
this._type_AndroidSocket = true;
this.addObjectListener('data', data => this._dispatchEvent('data', {
data
}));
this.addObjectListener('close', () => {
this._dispatchEvent('close');
this._dispose();
});
}
async write(params, metadata) {
await this._object.write(params.data);
}
async close(params, metadata) {
this._object.close();
}
}
exports.AndroidSocketDispatcher = AndroidSocketDispatcher;
const keyMap = new Map([['Unknown', 0], ['SoftLeft', 1], ['SoftRight', 2], ['Home', 3], ['Back', 4], ['Call', 5], ['EndCall', 6], ['0', 7], ['1', 8], ['2', 9], ['3', 10], ['4', 11], ['5', 12], ['6', 13], ['7', 14], ['8', 15], ['9', 16], ['Star', 17], ['*', 17], ['Pound', 18], ['#', 18], ['DialUp', 19], ['DialDown', 20], ['DialLeft', 21], ['DialRight', 22], ['DialCenter', 23], ['VolumeUp', 24], ['VolumeDown', 25], ['Power', 26], ['Camera', 27], ['Clear', 28], ['A', 29], ['B', 30], ['C', 31], ['D', 32], ['E', 33], ['F', 34], ['G', 35], ['H', 36], ['I', 37], ['J', 38], ['K', 39], ['L', 40], ['M', 41], ['N', 42], ['O', 43], ['P', 44], ['Q', 45], ['R', 46], ['S', 47], ['T', 48], ['U', 49], ['V', 50], ['W', 51], ['X', 52], ['Y', 53], ['Z', 54], ['Comma', 55], [',', 55], ['Period', 56], ['.', 56], ['AltLeft', 57], ['AltRight', 58], ['ShiftLeft', 59], ['ShiftRight', 60], ['Tab', 61], ['\t', 61], ['Space', 62], [' ', 62], ['Sym', 63], ['Explorer', 64], ['Envelop', 65], ['Enter', 66], ['Del', 67], ['Grave', 68], ['Minus', 69], ['-', 69], ['Equals', 70], ['=', 70], ['LeftBracket', 71], ['(', 71], ['RightBracket', 72], [')', 72], ['Backslash', 73], ['\\', 73], ['Semicolon', 74], [';', 74], ['Apostrophe', 75], ['`', 75], ['Slash', 76], ['/', 76], ['At', 77], ['@', 77], ['Num', 78], ['HeadsetHook', 79], ['Focus', 80], ['Plus', 81], ['Menu', 82], ['Notification', 83], ['Search', 84], ['ChannelUp', 166], ['ChannelDown', 167], ['AppSwitch', 187], ['Assist', 219], ['Cut', 277], ['Copy', 278], ['Paste', 279]]);
function fixupAndroidElementInfo(info) {
// Some of the properties are nullable, see https://developer.android.com/reference/androidx/test/uiautomator/UiObject2.
info.clazz = info.clazz || '';
info.pkg = info.pkg || '';
info.res = info.res || '';
info.desc = info.desc || '';
info.text = info.text || '';
for (const child of info.children || []) fixupAndroidElementInfo(child);
}

View File

@@ -0,0 +1,118 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ArtifactDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _streamDispatcher = require("./streamDispatcher");
var _fs = _interopRequireDefault(require("fs"));
var _fileUtils = require("../../utils/fileUtils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 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.
*/
class ArtifactDispatcher extends _dispatcher.Dispatcher {
static from(parentScope, artifact) {
return ArtifactDispatcher.fromNullable(parentScope, artifact);
}
static fromNullable(parentScope, artifact) {
if (!artifact) return undefined;
const result = (0, _dispatcher.existingDispatcher)(artifact);
return result || new ArtifactDispatcher(parentScope, artifact);
}
constructor(scope, artifact) {
super(scope, artifact, 'Artifact', {
absolutePath: artifact.localPath()
});
this._type_Artifact = true;
}
async pathAfterFinished() {
const path = await this._object.localPathAfterFinished();
return {
value: path
};
}
async saveAs(params) {
return await new Promise((resolve, reject) => {
this._object.saveAs(async (localPath, error) => {
if (error) {
reject(error);
return;
}
try {
await (0, _fileUtils.mkdirIfNeeded)(params.path);
await _fs.default.promises.copyFile(localPath, params.path);
resolve();
} catch (e) {
reject(e);
}
});
});
}
async saveAsStream() {
return await new Promise((resolve, reject) => {
this._object.saveAs(async (localPath, error) => {
if (error) {
reject(error);
return;
}
try {
const readable = _fs.default.createReadStream(localPath, {
highWaterMark: 1024 * 1024
});
const stream = new _streamDispatcher.StreamDispatcher(this, readable);
// Resolve with a stream, so that client starts saving the data.
resolve({
stream
});
// Block the Artifact until the stream is consumed.
await new Promise(resolve => {
readable.on('close', resolve);
readable.on('end', resolve);
readable.on('error', resolve);
});
} catch (e) {
reject(e);
}
});
});
}
async stream() {
const fileName = await this._object.localPathAfterFinished();
const readable = _fs.default.createReadStream(fileName, {
highWaterMark: 1024 * 1024
});
return {
stream: new _streamDispatcher.StreamDispatcher(this, readable)
};
}
async failure() {
const error = await this._object.failureError();
return {
error: error || undefined
};
}
async cancel() {
await this._object.cancel();
}
async delete(_, metadata) {
metadata.potentiallyClosesScope = true;
await this._object.delete();
this._dispose();
}
}
exports.ArtifactDispatcher = ArtifactDispatcher;

View File

@@ -0,0 +1,368 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.BrowserContextDispatcher = void 0;
var _browserContext = require("../browserContext");
var _dispatcher = require("./dispatcher");
var _pageDispatcher = require("./pageDispatcher");
var _networkDispatchers = require("./networkDispatchers");
var _crBrowser = require("../chromium/crBrowser");
var _cdpSessionDispatcher = require("./cdpSessionDispatcher");
var _recorder = require("../recorder");
var _artifactDispatcher = require("./artifactDispatcher");
var _tracingDispatcher = require("./tracingDispatcher");
var fs = _interopRequireWildcard(require("fs"));
var path = _interopRequireWildcard(require("path"));
var _utils = require("../../utils");
var _writableStreamDispatcher = require("./writableStreamDispatcher");
var _dialogDispatcher = require("./dialogDispatcher");
var _errors = require("../errors");
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
var _recorderInTraceViewer = require("../recorder/recorderInTraceViewer");
var _recorderApp = require("../recorder/recorderApp");
var _webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* 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.
*/
class BrowserContextDispatcher extends _dispatcher.Dispatcher {
constructor(parentScope, context) {
// We will reparent these to the context below.
const requestContext = _networkDispatchers.APIRequestContextDispatcher.from(parentScope, context.fetchRequest);
const tracing = _tracingDispatcher.TracingDispatcher.from(parentScope, context.tracing);
super(parentScope, context, 'BrowserContext', {
isChromium: context._browser.options.isChromium,
isLocalBrowserOnServer: context._browser._isCollocatedWithServer,
requestContext,
tracing
});
this._type_EventTarget = true;
this._type_BrowserContext = true;
this._context = void 0;
this._subscriptions = new Set();
this._webSocketInterceptionPatterns = [];
this.adopt(requestContext);
this.adopt(tracing);
this._context = context;
// Note: when launching persistent context, dispatcher is created very late,
// so we can already have pages, videos and everything else.
const onVideo = artifact => {
// Note: Video must outlive Page and BrowserContext, so that client can saveAs it
// after closing the context. We use |scope| for it.
const artifactDispatcher = _artifactDispatcher.ArtifactDispatcher.from(parentScope, artifact);
this._dispatchEvent('video', {
artifact: artifactDispatcher
});
};
this.addObjectListener(_browserContext.BrowserContext.Events.VideoStarted, onVideo);
for (const video of context._browser._idToVideo.values()) {
if (video.context === context) onVideo(video.artifact);
}
for (const page of context.pages()) this._dispatchEvent('page', {
page: _pageDispatcher.PageDispatcher.from(this, page)
});
this.addObjectListener(_browserContext.BrowserContext.Events.Page, page => {
this._dispatchEvent('page', {
page: _pageDispatcher.PageDispatcher.from(this, page)
});
});
this.addObjectListener(_browserContext.BrowserContext.Events.Close, () => {
this._dispatchEvent('close');
this._dispose();
});
this.addObjectListener(_browserContext.BrowserContext.Events.PageError, (error, page) => {
this._dispatchEvent('pageError', {
error: (0, _errors.serializeError)(error),
page: _pageDispatcher.PageDispatcher.from(this, page)
});
});
this.addObjectListener(_browserContext.BrowserContext.Events.Console, message => {
const page = message.page();
if (this._shouldDispatchEvent(page, 'console')) {
const pageDispatcher = _pageDispatcher.PageDispatcher.from(this, page);
this._dispatchEvent('console', {
page: pageDispatcher,
type: message.type(),
text: message.text(),
args: message.args().map(a => _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(pageDispatcher, a)),
location: message.location()
});
}
});
this.addObjectListener(_browserContext.BrowserContext.Events.Dialog, dialog => {
if (this._shouldDispatchEvent(dialog.page(), 'dialog')) this._dispatchEvent('dialog', {
dialog: new _dialogDispatcher.DialogDispatcher(this, dialog)
});else dialog.close().catch(() => {});
});
if (context._browser.options.name === 'chromium') {
for (const page of context.backgroundPages()) this._dispatchEvent('backgroundPage', {
page: _pageDispatcher.PageDispatcher.from(this, page)
});
this.addObjectListener(_crBrowser.CRBrowserContext.CREvents.BackgroundPage, page => this._dispatchEvent('backgroundPage', {
page: _pageDispatcher.PageDispatcher.from(this, page)
}));
for (const serviceWorker of context.serviceWorkers()) this._dispatchEvent('serviceWorker', {
worker: new _pageDispatcher.WorkerDispatcher(this, serviceWorker)
});
this.addObjectListener(_crBrowser.CRBrowserContext.CREvents.ServiceWorker, serviceWorker => this._dispatchEvent('serviceWorker', {
worker: new _pageDispatcher.WorkerDispatcher(this, serviceWorker)
}));
}
this.addObjectListener(_browserContext.BrowserContext.Events.Request, request => {
var _request$frame;
// Create dispatcher, if:
// - There are listeners to the requests.
// - We are redirected from a reported request so that redirectedTo was updated on client.
// - We are a navigation request and dispatcher will be reported as a part of the goto return value and newDocument param anyways.
// By the time requestFinished is triggered to update the request, we should have a request on the client already.
const redirectFromDispatcher = request.redirectedFrom() && (0, _dispatcher.existingDispatcher)(request.redirectedFrom());
if (!redirectFromDispatcher && !this._shouldDispatchNetworkEvent(request, 'request') && !request.isNavigationRequest()) return;
const requestDispatcher = _networkDispatchers.RequestDispatcher.from(this, request);
this._dispatchEvent('request', {
request: requestDispatcher,
page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame = request.frame()) === null || _request$frame === void 0 ? void 0 : _request$frame._page.initializedOrUndefined())
});
});
this.addObjectListener(_browserContext.BrowserContext.Events.Response, response => {
var _response$frame;
const requestDispatcher = (0, _dispatcher.existingDispatcher)(response.request());
if (!requestDispatcher && !this._shouldDispatchNetworkEvent(response.request(), 'response')) return;
this._dispatchEvent('response', {
response: _networkDispatchers.ResponseDispatcher.from(this, response),
page: _pageDispatcher.PageDispatcher.fromNullable(this, (_response$frame = response.frame()) === null || _response$frame === void 0 ? void 0 : _response$frame._page.initializedOrUndefined())
});
});
this.addObjectListener(_browserContext.BrowserContext.Events.RequestFailed, request => {
var _request$frame2;
const requestDispatcher = (0, _dispatcher.existingDispatcher)(request);
if (!requestDispatcher && !this._shouldDispatchNetworkEvent(request, 'requestFailed')) return;
this._dispatchEvent('requestFailed', {
request: _networkDispatchers.RequestDispatcher.from(this, request),
failureText: request._failureText || undefined,
responseEndTiming: request._responseEndTiming,
page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame2 = request.frame()) === null || _request$frame2 === void 0 ? void 0 : _request$frame2._page.initializedOrUndefined())
});
});
this.addObjectListener(_browserContext.BrowserContext.Events.RequestFinished, ({
request,
response
}) => {
var _request$frame3;
const requestDispatcher = (0, _dispatcher.existingDispatcher)(request);
if (!requestDispatcher && !this._shouldDispatchNetworkEvent(request, 'requestFinished')) return;
this._dispatchEvent('requestFinished', {
request: _networkDispatchers.RequestDispatcher.from(this, request),
response: _networkDispatchers.ResponseDispatcher.fromNullable(this, response),
responseEndTiming: request._responseEndTiming,
page: _pageDispatcher.PageDispatcher.fromNullable(this, (_request$frame3 = request.frame()) === null || _request$frame3 === void 0 ? void 0 : _request$frame3._page.initializedOrUndefined())
});
});
}
_shouldDispatchNetworkEvent(request, event) {
var _request$frame4;
return this._shouldDispatchEvent((_request$frame4 = request.frame()) === null || _request$frame4 === void 0 || (_request$frame4 = _request$frame4._page) === null || _request$frame4 === void 0 ? void 0 : _request$frame4.initializedOrUndefined(), event);
}
_shouldDispatchEvent(page, event) {
if (this._subscriptions.has(event)) return true;
const pageDispatcher = page ? (0, _dispatcher.existingDispatcher)(page) : undefined;
if (pageDispatcher !== null && pageDispatcher !== void 0 && pageDispatcher._subscriptions.has(event)) return true;
return false;
}
async createTempFiles(params) {
const dir = this._context._browser.options.artifactsDir;
const tmpDir = path.join(dir, 'upload-' + (0, _utils.createGuid)());
const tempDirWithRootName = params.rootDirName ? path.join(tmpDir, path.basename(params.rootDirName)) : tmpDir;
await fs.promises.mkdir(tempDirWithRootName, {
recursive: true
});
this._context._tempDirs.push(tmpDir);
return {
rootDir: params.rootDirName ? new _writableStreamDispatcher.WritableStreamDispatcher(this, tempDirWithRootName) : undefined,
writableStreams: await Promise.all(params.items.map(async item => {
await fs.promises.mkdir(path.dirname(path.join(tempDirWithRootName, item.name)), {
recursive: true
});
const file = fs.createWriteStream(path.join(tempDirWithRootName, item.name));
return new _writableStreamDispatcher.WritableStreamDispatcher(this, file, item.lastModifiedMs);
}))
};
}
async setDefaultNavigationTimeoutNoReply(params) {
this._context.setDefaultNavigationTimeout(params.timeout);
}
async setDefaultTimeoutNoReply(params) {
this._context.setDefaultTimeout(params.timeout);
}
async exposeBinding(params) {
await this._context.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
// When reusing the context, we might have some bindings called late enough,
// after context and page dispatchers have been disposed.
if (this._disposed) return;
const pageDispatcher = _pageDispatcher.PageDispatcher.from(this, source.page);
const binding = new _pageDispatcher.BindingCallDispatcher(pageDispatcher, params.name, !!params.needsHandle, source, args);
this._dispatchEvent('bindingCall', {
binding
});
return binding.promise();
});
}
async newPage(params, metadata) {
return {
page: _pageDispatcher.PageDispatcher.from(this, await this._context.newPage(metadata))
};
}
async cookies(params) {
return {
cookies: await this._context.cookies(params.urls)
};
}
async addCookies(params) {
await this._context.addCookies(params.cookies);
}
async clearCookies(params) {
const nameRe = params.nameRegexSource !== undefined && params.nameRegexFlags !== undefined ? new RegExp(params.nameRegexSource, params.nameRegexFlags) : undefined;
const domainRe = params.domainRegexSource !== undefined && params.domainRegexFlags !== undefined ? new RegExp(params.domainRegexSource, params.domainRegexFlags) : undefined;
const pathRe = params.pathRegexSource !== undefined && params.pathRegexFlags !== undefined ? new RegExp(params.pathRegexSource, params.pathRegexFlags) : undefined;
await this._context.clearCookies({
name: nameRe || params.name,
domain: domainRe || params.domain,
path: pathRe || params.path
});
}
async grantPermissions(params) {
await this._context.grantPermissions(params.permissions, params.origin);
}
async clearPermissions() {
await this._context.clearPermissions();
}
async setGeolocation(params) {
await this._context.setGeolocation(params.geolocation);
}
async setExtraHTTPHeaders(params) {
await this._context.setExtraHTTPHeaders(params.headers);
}
async setOffline(params) {
await this._context.setOffline(params.offline);
}
async setHTTPCredentials(params) {
await this._context.setHTTPCredentials(params.httpCredentials);
}
async addInitScript(params) {
await this._context.addInitScript(params.source);
}
async setNetworkInterceptionPatterns(params) {
if (!params.patterns.length) {
await this._context.setRequestInterceptor(undefined);
return;
}
const urlMatchers = params.patterns.map(pattern => pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob);
await this._context.setRequestInterceptor((route, request) => {
const matchesSome = urlMatchers.some(urlMatch => (0, _utils.urlMatches)(this._context._options.baseURL, request.url(), urlMatch));
if (!matchesSome) return false;
this._dispatchEvent('route', {
route: _networkDispatchers.RouteDispatcher.from(_networkDispatchers.RequestDispatcher.from(this, request), route)
});
return true;
});
}
async setWebSocketInterceptionPatterns(params, metadata) {
this._webSocketInterceptionPatterns = params.patterns;
if (params.patterns.length) await _webSocketRouteDispatcher.WebSocketRouteDispatcher.installIfNeeded(this, this._context);
}
async storageState(params, metadata) {
return await this._context.storageState();
}
async close(params, metadata) {
metadata.potentiallyClosesScope = true;
await this._context.close(params);
}
async enableRecorder(params) {
if (params.codegenMode === 'trace-events') {
await this._context.tracing.start({
name: 'trace',
snapshots: true,
screenshots: true,
live: true
});
await _recorder.Recorder.show('trace-events', this._context, _recorderInTraceViewer.RecorderInTraceViewer.factory(this._context), params);
} else {
await _recorder.Recorder.show('actions', this._context, _recorderApp.RecorderApp.factory(this._context), params);
}
}
async pause(params, metadata) {
// Debugger will take care of this.
}
async newCDPSession(params) {
if (!this._object._browser.options.isChromium) throw new Error(`CDP session is only available in Chromium`);
if (!params.page && !params.frame || params.page && params.frame) throw new Error(`CDP session must be initiated with either Page or Frame, not none or both`);
const crBrowserContext = this._object;
return {
session: new _cdpSessionDispatcher.CDPSessionDispatcher(this, await crBrowserContext.newCDPSession((params.page ? params.page : params.frame)._object))
};
}
async harStart(params) {
const harId = await this._context._harStart(params.page ? params.page._object : null, params.options);
return {
harId
};
}
async harExport(params) {
const artifact = await this._context._harExport(params.harId);
if (!artifact) throw new Error('No HAR artifact. Ensure record.harPath is set.');
return {
artifact: _artifactDispatcher.ArtifactDispatcher.from(this, artifact)
};
}
async clockFastForward(params, metadata) {
var _ref, _params$ticksString;
await this._context.clock.fastForward((_ref = (_params$ticksString = params.ticksString) !== null && _params$ticksString !== void 0 ? _params$ticksString : params.ticksNumber) !== null && _ref !== void 0 ? _ref : 0);
}
async clockInstall(params, metadata) {
var _ref2, _params$timeString;
await this._context.clock.install((_ref2 = (_params$timeString = params.timeString) !== null && _params$timeString !== void 0 ? _params$timeString : params.timeNumber) !== null && _ref2 !== void 0 ? _ref2 : undefined);
}
async clockPauseAt(params, metadata) {
var _ref3, _params$timeString2;
await this._context.clock.pauseAt((_ref3 = (_params$timeString2 = params.timeString) !== null && _params$timeString2 !== void 0 ? _params$timeString2 : params.timeNumber) !== null && _ref3 !== void 0 ? _ref3 : 0);
}
async clockResume(params, metadata) {
await this._context.clock.resume();
}
async clockRunFor(params, metadata) {
var _ref4, _params$ticksString2;
await this._context.clock.runFor((_ref4 = (_params$ticksString2 = params.ticksString) !== null && _params$ticksString2 !== void 0 ? _params$ticksString2 : params.ticksNumber) !== null && _ref4 !== void 0 ? _ref4 : 0);
}
async clockSetFixedTime(params, metadata) {
var _ref5, _params$timeString3;
await this._context.clock.setFixedTime((_ref5 = (_params$timeString3 = params.timeString) !== null && _params$timeString3 !== void 0 ? _params$timeString3 : params.timeNumber) !== null && _ref5 !== void 0 ? _ref5 : 0);
}
async clockSetSystemTime(params, metadata) {
var _ref6, _params$timeString4;
await this._context.clock.setSystemTime((_ref6 = (_params$timeString4 = params.timeString) !== null && _params$timeString4 !== void 0 ? _params$timeString4 : params.timeNumber) !== null && _ref6 !== void 0 ? _ref6 : 0);
}
async updateSubscription(params) {
if (params.enabled) this._subscriptions.add(params.event);else this._subscriptions.delete(params.event);
}
_onDispose() {
// Avoid protocol calls for the closed context.
if (!this._context.isClosingOrClosed()) this._context.setRequestInterceptor(undefined).catch(() => {});
}
}
exports.BrowserContextDispatcher = BrowserContextDispatcher;

View File

@@ -0,0 +1,170 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ConnectedBrowserDispatcher = exports.BrowserDispatcher = void 0;
var _browser = require("../browser");
var _browserContextDispatcher = require("./browserContextDispatcher");
var _cdpSessionDispatcher = require("./cdpSessionDispatcher");
var _dispatcher = require("./dispatcher");
var _browserContext = require("../browserContext");
var _selectors = require("../selectors");
var _artifactDispatcher = require("./artifactDispatcher");
/**
* 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.
*/
class BrowserDispatcher extends _dispatcher.Dispatcher {
constructor(scope, browser) {
super(scope, browser, 'Browser', {
version: browser.version(),
name: browser.options.name
});
this._type_Browser = true;
this.addObjectListener(_browser.Browser.Events.Disconnected, () => this._didClose());
}
_didClose() {
this._dispatchEvent('close');
this._dispose();
}
async newContext(params, metadata) {
const context = await this._object.newContext(metadata, params);
return {
context: new _browserContextDispatcher.BrowserContextDispatcher(this, context)
};
}
async newContextForReuse(params, metadata) {
return await newContextForReuse(this._object, this, params, null, metadata);
}
async stopPendingOperations(params, metadata) {
await this._object.stopPendingOperations(params.reason);
}
async close(params, metadata) {
metadata.potentiallyClosesScope = true;
await this._object.close(params);
}
async killForTests(_, metadata) {
metadata.potentiallyClosesScope = true;
await this._object.killForTests();
}
async defaultUserAgentForTest() {
return {
userAgent: this._object.userAgent()
};
}
async newBrowserCDPSession() {
if (!this._object.options.isChromium) throw new Error(`CDP session is only available in Chromium`);
const crBrowser = this._object;
return {
session: new _cdpSessionDispatcher.CDPSessionDispatcher(this, await crBrowser.newBrowserCDPSession())
};
}
async startTracing(params) {
if (!this._object.options.isChromium) throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object;
await crBrowser.startTracing(params.page ? params.page._object : undefined, params);
}
async stopTracing() {
if (!this._object.options.isChromium) throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object;
return {
artifact: _artifactDispatcher.ArtifactDispatcher.from(this, await crBrowser.stopTracing())
};
}
}
// This class implements multiplexing browser dispatchers over a single Browser instance.
exports.BrowserDispatcher = BrowserDispatcher;
class ConnectedBrowserDispatcher extends _dispatcher.Dispatcher {
constructor(scope, browser) {
super(scope, browser, 'Browser', {
version: browser.version(),
name: browser.options.name
});
// When we have a remotely-connected browser, each client gets a fresh Selector instance,
// so that two clients do not interfere between each other.
this._type_Browser = true;
this._contexts = new Set();
this.selectors = void 0;
this.selectors = new _selectors.Selectors();
}
async newContext(params, metadata) {
if (params.recordVideo) params.recordVideo.dir = this._object.options.artifactsDir;
const context = await this._object.newContext(metadata, params);
this._contexts.add(context);
context.setSelectors(this.selectors);
context.on(_browserContext.BrowserContext.Events.Close, () => this._contexts.delete(context));
return {
context: new _browserContextDispatcher.BrowserContextDispatcher(this, context)
};
}
async newContextForReuse(params, metadata) {
return await newContextForReuse(this._object, this, params, this.selectors, metadata);
}
async stopPendingOperations(params, metadata) {
await this._object.stopPendingOperations(params.reason);
}
async close() {
// Client should not send us Browser.close.
}
async killForTests() {
// Client should not send us Browser.killForTests.
}
async defaultUserAgentForTest() {
throw new Error('Client should not send us Browser.defaultUserAgentForTest');
}
async newBrowserCDPSession() {
if (!this._object.options.isChromium) throw new Error(`CDP session is only available in Chromium`);
const crBrowser = this._object;
return {
session: new _cdpSessionDispatcher.CDPSessionDispatcher(this, await crBrowser.newBrowserCDPSession())
};
}
async startTracing(params) {
if (!this._object.options.isChromium) throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object;
await crBrowser.startTracing(params.page ? params.page._object : undefined, params);
}
async stopTracing() {
if (!this._object.options.isChromium) throw new Error(`Tracing is only available in Chromium`);
const crBrowser = this._object;
return {
artifact: _artifactDispatcher.ArtifactDispatcher.from(this, await crBrowser.stopTracing())
};
}
async cleanupContexts() {
await Promise.all(Array.from(this._contexts).map(context => context.close({
reason: 'Global context cleanup (connection terminated)'
})));
}
}
exports.ConnectedBrowserDispatcher = ConnectedBrowserDispatcher;
async function newContextForReuse(browser, scope, params, selectors, metadata) {
const {
context,
needsReset
} = await browser.newContextForReuse(params, metadata);
if (needsReset) {
const oldContextDispatcher = (0, _dispatcher.existingDispatcher)(context);
if (oldContextDispatcher) oldContextDispatcher._dispose();
await context.resetForReuse(metadata, params);
}
if (selectors) context.setSelectors(selectors);
const contextDispatcher = new _browserContextDispatcher.BrowserContextDispatcher(scope, context);
return {
context: contextDispatcher
};
}

View File

@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.BrowserTypeDispatcher = void 0;
var _browserDispatcher = require("./browserDispatcher");
var _dispatcher = require("./dispatcher");
var _browserContextDispatcher = require("./browserContextDispatcher");
/**
* 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.
*/
class BrowserTypeDispatcher extends _dispatcher.Dispatcher {
constructor(scope, browserType) {
super(scope, browserType, 'BrowserType', {
executablePath: browserType.executablePath(),
name: browserType.name()
});
this._type_BrowserType = true;
}
async launch(params, metadata) {
const browser = await this._object.launch(metadata, params);
return {
browser: new _browserDispatcher.BrowserDispatcher(this, browser)
};
}
async launchPersistentContext(params, metadata) {
const browserContext = await this._object.launchPersistentContext(metadata, params.userDataDir, params);
return {
context: new _browserContextDispatcher.BrowserContextDispatcher(this, browserContext)
};
}
async connectOverCDP(params, metadata) {
const browser = await this._object.connectOverCDP(metadata, params.endpointURL, params, params.timeout);
const browserDispatcher = new _browserDispatcher.BrowserDispatcher(this, browser);
return {
browser: browserDispatcher,
defaultContext: browser._defaultContext ? new _browserContextDispatcher.BrowserContextDispatcher(browserDispatcher, browser._defaultContext) : undefined
};
}
}
exports.BrowserTypeDispatcher = BrowserTypeDispatcher;

View File

@@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.CDPSessionDispatcher = void 0;
var _crConnection = require("../chromium/crConnection");
var _dispatcher = require("./dispatcher");
/**
* 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.
*/
class CDPSessionDispatcher extends _dispatcher.Dispatcher {
constructor(scope, cdpSession) {
super(scope, cdpSession, 'CDPSession', {});
this._type_CDPSession = true;
this.addObjectListener(_crConnection.CDPSession.Events.Event, ({
method,
params
}) => this._dispatchEvent('event', {
method,
params
}));
this.addObjectListener(_crConnection.CDPSession.Events.Closed, () => this._dispose());
}
async send(params) {
return {
result: await this._object.send(params.method, params.params)
};
}
async detach(_, metadata) {
metadata.potentiallyClosesScope = true;
await this._object.detach();
}
}
exports.CDPSessionDispatcher = CDPSessionDispatcher;

View File

@@ -0,0 +1,103 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DebugControllerDispatcher = void 0;
var _utils = require("../../utils");
var _debugController = require("../debugController");
var _dispatcher = require("./dispatcher");
/**
* 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.
*/
class DebugControllerDispatcher extends _dispatcher.Dispatcher {
constructor(connection, debugController) {
super(connection, debugController, 'DebugController', {});
this._type_DebugController = void 0;
this._listeners = void 0;
this._type_DebugController = true;
this._listeners = [_utils.eventsHelper.addEventListener(this._object, _debugController.DebugController.Events.StateChanged, params => {
this._dispatchEvent('stateChanged', params);
}), _utils.eventsHelper.addEventListener(this._object, _debugController.DebugController.Events.InspectRequested, ({
selector,
locator
}) => {
this._dispatchEvent('inspectRequested', {
selector,
locator
});
}), _utils.eventsHelper.addEventListener(this._object, _debugController.DebugController.Events.SourceChanged, ({
text,
header,
footer,
actions
}) => {
this._dispatchEvent('sourceChanged', {
text,
header,
footer,
actions
});
}), _utils.eventsHelper.addEventListener(this._object, _debugController.DebugController.Events.Paused, ({
paused
}) => {
this._dispatchEvent('paused', {
paused
});
}), _utils.eventsHelper.addEventListener(this._object, _debugController.DebugController.Events.SetModeRequested, ({
mode
}) => {
this._dispatchEvent('setModeRequested', {
mode
});
})];
}
async initialize(params) {
this._object.initialize(params.codegenId, params.sdkLanguage);
}
async setReportStateChanged(params) {
this._object.setReportStateChanged(params.enabled);
}
async resetForReuse() {
await this._object.resetForReuse();
}
async navigate(params) {
await this._object.navigate(params.url);
}
async setRecorderMode(params) {
await this._object.setRecorderMode(params);
}
async highlight(params) {
await this._object.highlight(params);
}
async hideHighlight() {
await this._object.hideHighlight();
}
async resume() {
await this._object.resume();
}
async kill() {
await this._object.kill();
}
async closeAllBrowsers() {
await this._object.closeAllBrowsers();
}
_onDispose() {
_utils.eventsHelper.removeEventListeners(this._listeners);
this._object.dispose();
}
}
exports.DebugControllerDispatcher = DebugControllerDispatcher;

View File

@@ -0,0 +1,44 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.DialogDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _pageDispatcher = require("./pageDispatcher");
/**
* 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.
*/
class DialogDispatcher extends _dispatcher.Dispatcher {
constructor(scope, dialog) {
const page = _pageDispatcher.PageDispatcher.fromNullable(scope, dialog.page().initializedOrUndefined());
// Prefer scoping to the page, unless we don't have one.
super(page || scope, dialog, 'Dialog', {
page,
type: dialog.type(),
message: dialog.message(),
defaultValue: dialog.defaultValue()
});
this._type_Dialog = true;
}
async accept(params) {
await this._object.accept(params.promptText);
}
async dismiss() {
await this._object.dismiss();
}
}
exports.DialogDispatcher = DialogDispatcher;

View File

@@ -0,0 +1,395 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.dispatcherSymbol = exports.RootDispatcher = exports.DispatcherConnection = exports.Dispatcher = void 0;
exports.existingDispatcher = existingDispatcher;
exports.setMaxDispatchersForTest = setMaxDispatchersForTest;
var _events = require("events");
var _validator = require("../../protocol/validator");
var _utils = require("../../utils");
var _errors = require("../errors");
var _instrumentation = require("../instrumentation");
var _eventsHelper = require("../..//utils/eventsHelper");
var _protocolError = require("../protocolError");
/**
* 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.
*/
const dispatcherSymbol = exports.dispatcherSymbol = Symbol('dispatcher');
const metadataValidator = (0, _validator.createMetadataValidator)();
function existingDispatcher(object) {
return object[dispatcherSymbol];
}
let maxDispatchersOverride;
function setMaxDispatchersForTest(value) {
maxDispatchersOverride = value;
}
function maxDispatchersForBucket(gcBucket) {
var _ref, _maxDispatchersOverri;
return (_ref = (_maxDispatchersOverri = maxDispatchersOverride) !== null && _maxDispatchersOverri !== void 0 ? _maxDispatchersOverri : {
'JSHandle': 100000,
'ElementHandle': 100000
}[gcBucket]) !== null && _ref !== void 0 ? _ref : 10000;
}
class Dispatcher extends _events.EventEmitter {
constructor(parent, object, type, initializer, gcBucket) {
super();
this._connection = void 0;
// Parent is always "isScope".
this._parent = void 0;
// Only "isScope" channel owners have registered dispatchers inside.
this._dispatchers = new Map();
this._disposed = false;
this._eventListeners = [];
this._guid = void 0;
this._type = void 0;
this._gcBucket = void 0;
this._object = void 0;
this._openScope = new _utils.LongStandingScope();
this._connection = parent instanceof DispatcherConnection ? parent : parent._connection;
this._parent = parent instanceof DispatcherConnection ? undefined : parent;
const guid = object.guid;
this._guid = guid;
this._type = type;
this._object = object;
this._gcBucket = gcBucket !== null && gcBucket !== void 0 ? gcBucket : type;
object[dispatcherSymbol] = this;
this._connection.registerDispatcher(this);
if (this._parent) {
(0, _utils.assert)(!this._parent._dispatchers.has(guid));
this._parent._dispatchers.set(guid, this);
}
if (this._parent) this._connection.sendCreate(this._parent, type, guid, initializer);
this._connection.maybeDisposeStaleDispatchers(this._gcBucket);
}
parentScope() {
return this._parent;
}
addObjectListener(eventName, handler) {
this._eventListeners.push(_eventsHelper.eventsHelper.addEventListener(this._object, eventName, handler));
}
adopt(child) {
if (child._parent === this) return;
const oldParent = child._parent;
oldParent._dispatchers.delete(child._guid);
this._dispatchers.set(child._guid, child);
child._parent = this;
this._connection.sendAdopt(this, child);
}
async _handleCommand(callMetadata, method, validParams) {
const commandPromise = this[method](validParams, callMetadata);
try {
return await this._openScope.race(commandPromise);
} catch (e) {
if (callMetadata.potentiallyClosesScope && (0, _errors.isTargetClosedError)(e)) return await commandPromise;
throw e;
}
}
_dispatchEvent(method, params) {
if (this._disposed) {
if ((0, _utils.isUnderTest)()) throw new Error(`${this._guid} is sending "${String(method)}" event after being disposed`);
// Just ignore this event outside of tests.
return;
}
this._connection.sendEvent(this, method, params);
}
_dispose(reason) {
this._disposeRecursively(new _errors.TargetClosedError());
this._connection.sendDispose(this, reason);
}
_onDispose() {}
_disposeRecursively(error) {
var _this$_parent;
(0, _utils.assert)(!this._disposed, `${this._guid} is disposed more than once`);
this._onDispose();
this._disposed = true;
_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
// Clean up from parent and connection.
(_this$_parent = this._parent) === null || _this$_parent === void 0 || _this$_parent._dispatchers.delete(this._guid);
const list = this._connection._dispatchersByBucket.get(this._gcBucket);
list === null || list === void 0 || list.delete(this._guid);
this._connection._dispatchers.delete(this._guid);
// Dispose all children.
for (const dispatcher of [...this._dispatchers.values()]) dispatcher._disposeRecursively(error);
this._dispatchers.clear();
delete this._object[dispatcherSymbol];
this._openScope.close(error);
}
_debugScopeState() {
return {
_guid: this._guid,
objects: Array.from(this._dispatchers.values()).map(o => o._debugScopeState())
};
}
async waitForEventInfo() {
// Instrumentation takes care of this.
}
}
exports.Dispatcher = Dispatcher;
class RootDispatcher extends Dispatcher {
constructor(connection, createPlaywright) {
super(connection, {
guid: ''
}, 'Root', {});
this._initialized = false;
this.createPlaywright = createPlaywright;
}
async initialize(params) {
(0, _utils.assert)(this.createPlaywright);
(0, _utils.assert)(!this._initialized);
this._initialized = true;
return {
playwright: await this.createPlaywright(this, params)
};
}
}
exports.RootDispatcher = RootDispatcher;
class DispatcherConnection {
constructor(isLocal) {
this._dispatchers = new Map();
this._dispatchersByBucket = new Map();
this.onmessage = message => {};
this._waitOperations = new Map();
this._isLocal = void 0;
this._isLocal = !!isLocal;
}
sendEvent(dispatcher, event, params) {
const validator = (0, _validator.findValidator)(dispatcher._type, event, 'Event');
params = validator(params, '', {
tChannelImpl: this._tChannelImplToWire.bind(this),
binary: this._isLocal ? 'buffer' : 'toBase64'
});
this.onmessage({
guid: dispatcher._guid,
method: event,
params
});
}
sendCreate(parent, type, guid, initializer) {
const validator = (0, _validator.findValidator)(type, '', 'Initializer');
initializer = validator(initializer, '', {
tChannelImpl: this._tChannelImplToWire.bind(this),
binary: this._isLocal ? 'buffer' : 'toBase64'
});
this.onmessage({
guid: parent._guid,
method: '__create__',
params: {
type,
initializer,
guid
}
});
}
sendAdopt(parent, dispatcher) {
this.onmessage({
guid: parent._guid,
method: '__adopt__',
params: {
guid: dispatcher._guid
}
});
}
sendDispose(dispatcher, reason) {
this.onmessage({
guid: dispatcher._guid,
method: '__dispose__',
params: {
reason
}
});
}
_tChannelImplFromWire(names, arg, path, context) {
if (arg && typeof arg === 'object' && typeof arg.guid === 'string') {
const guid = arg.guid;
const dispatcher = this._dispatchers.get(guid);
if (!dispatcher) throw new _validator.ValidationError(`${path}: no object with guid ${guid}`);
if (names !== '*' && !names.includes(dispatcher._type)) throw new _validator.ValidationError(`${path}: object with guid ${guid} has type ${dispatcher._type}, expected ${names.toString()}`);
return dispatcher;
}
throw new _validator.ValidationError(`${path}: expected guid for ${names.toString()}`);
}
_tChannelImplToWire(names, arg, path, context) {
if (arg instanceof Dispatcher) {
if (names !== '*' && !names.includes(arg._type)) throw new _validator.ValidationError(`${path}: dispatcher with guid ${arg._guid} has type ${arg._type}, expected ${names.toString()}`);
return {
guid: arg._guid
};
}
throw new _validator.ValidationError(`${path}: expected dispatcher ${names.toString()}`);
}
registerDispatcher(dispatcher) {
(0, _utils.assert)(!this._dispatchers.has(dispatcher._guid));
this._dispatchers.set(dispatcher._guid, dispatcher);
let list = this._dispatchersByBucket.get(dispatcher._gcBucket);
if (!list) {
list = new Set();
this._dispatchersByBucket.set(dispatcher._gcBucket, list);
}
list.add(dispatcher._guid);
}
maybeDisposeStaleDispatchers(gcBucket) {
const maxDispatchers = maxDispatchersForBucket(gcBucket);
const list = this._dispatchersByBucket.get(gcBucket);
if (!list || list.size <= maxDispatchers) return;
const dispatchersArray = [...list];
const disposeCount = maxDispatchers / 10 | 0;
this._dispatchersByBucket.set(gcBucket, new Set(dispatchersArray.slice(disposeCount)));
for (let i = 0; i < disposeCount; ++i) {
const d = this._dispatchers.get(dispatchersArray[i]);
if (!d) continue;
d._dispose('gc');
}
}
async dispatch(message) {
var _sdkObject$attributio, _sdkObject$attributio2, _params$info;
const {
id,
guid,
method,
params,
metadata
} = message;
const dispatcher = this._dispatchers.get(guid);
if (!dispatcher) {
this.onmessage({
id,
error: (0, _errors.serializeError)(new _errors.TargetClosedError())
});
return;
}
let validParams;
let validMetadata;
try {
const validator = (0, _validator.findValidator)(dispatcher._type, method, 'Params');
validParams = validator(params, '', {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._isLocal ? 'buffer' : 'fromBase64'
});
validMetadata = metadataValidator(metadata, '', {
tChannelImpl: this._tChannelImplFromWire.bind(this),
binary: this._isLocal ? 'buffer' : 'fromBase64'
});
if (typeof dispatcher[method] !== 'function') throw new Error(`Mismatching dispatcher: "${dispatcher._type}" does not implement "${method}"`);
} catch (e) {
this.onmessage({
id,
error: (0, _errors.serializeError)(e)
});
return;
}
const sdkObject = dispatcher._object instanceof _instrumentation.SdkObject ? dispatcher._object : undefined;
const callMetadata = {
id: `call@${id}`,
location: validMetadata.location,
apiName: validMetadata.apiName,
internal: validMetadata.internal,
stepId: validMetadata.stepId,
objectId: sdkObject === null || sdkObject === void 0 ? void 0 : sdkObject.guid,
pageId: sdkObject === null || sdkObject === void 0 || (_sdkObject$attributio = sdkObject.attribution) === null || _sdkObject$attributio === void 0 || (_sdkObject$attributio = _sdkObject$attributio.page) === null || _sdkObject$attributio === void 0 ? void 0 : _sdkObject$attributio.guid,
frameId: sdkObject === null || sdkObject === void 0 || (_sdkObject$attributio2 = sdkObject.attribution) === null || _sdkObject$attributio2 === void 0 || (_sdkObject$attributio2 = _sdkObject$attributio2.frame) === null || _sdkObject$attributio2 === void 0 ? void 0 : _sdkObject$attributio2.guid,
startTime: (0, _utils.monotonicTime)(),
endTime: 0,
type: dispatcher._type,
method,
params: params || {},
log: []
};
if (sdkObject && params !== null && params !== void 0 && (_params$info = params.info) !== null && _params$info !== void 0 && _params$info.waitId) {
// Process logs for waitForNavigation/waitForLoadState/etc.
const info = params.info;
switch (info.phase) {
case 'before':
{
this._waitOperations.set(info.waitId, callMetadata);
await sdkObject.instrumentation.onBeforeCall(sdkObject, callMetadata);
this.onmessage({
id
});
return;
}
case 'log':
{
const originalMetadata = this._waitOperations.get(info.waitId);
originalMetadata.log.push(info.message);
sdkObject.instrumentation.onCallLog(sdkObject, originalMetadata, 'api', info.message);
this.onmessage({
id
});
return;
}
case 'after':
{
const originalMetadata = this._waitOperations.get(info.waitId);
originalMetadata.endTime = (0, _utils.monotonicTime)();
originalMetadata.error = info.error ? {
error: {
name: 'Error',
message: info.error
}
} : undefined;
this._waitOperations.delete(info.waitId);
await sdkObject.instrumentation.onAfterCall(sdkObject, originalMetadata);
this.onmessage({
id
});
return;
}
}
}
await (sdkObject === null || sdkObject === void 0 ? void 0 : sdkObject.instrumentation.onBeforeCall(sdkObject, callMetadata));
const response = {
id
};
try {
const result = await dispatcher._handleCommand(callMetadata, method, validParams);
const validator = (0, _validator.findValidator)(dispatcher._type, method, 'Result');
response.result = validator(result, '', {
tChannelImpl: this._tChannelImplToWire.bind(this),
binary: this._isLocal ? 'buffer' : 'toBase64'
});
callMetadata.result = result;
} catch (e) {
if ((0, _errors.isTargetClosedError)(e) && sdkObject) {
const reason = closeReason(sdkObject);
if (reason) (0, _utils.rewriteErrorMessage)(e, reason);
} else if ((0, _protocolError.isProtocolError)(e)) {
if (e.type === 'closed') {
const reason = sdkObject ? closeReason(sdkObject) : undefined;
e = new _errors.TargetClosedError(reason, e.browserLogMessage());
} else if (e.type === 'crashed') {
(0, _utils.rewriteErrorMessage)(e, 'Target crashed ' + e.browserLogMessage());
}
}
response.error = (0, _errors.serializeError)(e);
// The command handler could have set error in the metadata, do not reset it if there was no exception.
callMetadata.error = response.error;
} finally {
callMetadata.endTime = (0, _utils.monotonicTime)();
await (sdkObject === null || sdkObject === void 0 ? void 0 : sdkObject.instrumentation.onAfterCall(sdkObject, callMetadata));
}
if (response.error) response.log = (0, _utils.compressCallLog)(callMetadata.log);
this.onmessage(response);
}
}
exports.DispatcherConnection = DispatcherConnection;
function closeReason(sdkObject) {
var _sdkObject$attributio3, _sdkObject$attributio4, _sdkObject$attributio5;
return ((_sdkObject$attributio3 = sdkObject.attribution.page) === null || _sdkObject$attributio3 === void 0 ? void 0 : _sdkObject$attributio3._closeReason) || ((_sdkObject$attributio4 = sdkObject.attribution.context) === null || _sdkObject$attributio4 === void 0 ? void 0 : _sdkObject$attributio4._closeReason) || ((_sdkObject$attributio5 = sdkObject.attribution.browser) === null || _sdkObject$attributio5 === void 0 ? void 0 : _sdkObject$attributio5._closeReason);
}

View File

@@ -0,0 +1,93 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ElectronDispatcher = exports.ElectronApplicationDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _electron = require("../electron/electron");
var _browserContextDispatcher = require("./browserContextDispatcher");
var _jsHandleDispatcher = require("./jsHandleDispatcher");
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
/**
* 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.
*/
class ElectronDispatcher extends _dispatcher.Dispatcher {
constructor(scope, electron) {
super(scope, electron, 'Electron', {});
this._type_Electron = true;
}
async launch(params) {
const electronApplication = await this._object.launch(params);
return {
electronApplication: new ElectronApplicationDispatcher(this, electronApplication)
};
}
}
exports.ElectronDispatcher = ElectronDispatcher;
class ElectronApplicationDispatcher extends _dispatcher.Dispatcher {
constructor(scope, electronApplication) {
super(scope, electronApplication, 'ElectronApplication', {
context: new _browserContextDispatcher.BrowserContextDispatcher(scope, electronApplication.context())
});
this._type_EventTarget = true;
this._type_ElectronApplication = true;
this._subscriptions = new Set();
this.addObjectListener(_electron.ElectronApplication.Events.Close, () => {
this._dispatchEvent('close');
this._dispose();
});
this.addObjectListener(_electron.ElectronApplication.Events.Console, message => {
if (!this._subscriptions.has('console')) return;
this._dispatchEvent('console', {
type: message.type(),
text: message.text(),
args: message.args().map(a => _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, a)),
location: message.location()
});
});
}
async browserWindow(params) {
const handle = await this._object.browserWindow(params.page.page());
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, handle)
};
}
async evaluateExpression(params) {
const handle = await this._object._nodeElectronHandlePromise;
return {
value: (0, _jsHandleDispatcher.serializeResult)(await handle.evaluateExpression(params.expression, {
isFunction: params.isFunction
}, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async evaluateExpressionHandle(params) {
const handle = await this._object._nodeElectronHandlePromise;
const result = await handle.evaluateExpressionHandle(params.expression, {
isFunction: params.isFunction
}, (0, _jsHandleDispatcher.parseArgument)(params.arg));
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, result)
};
}
async updateSubscription(params) {
if (params.enabled) this._subscriptions.add(params.event);else this._subscriptions.delete(params.event);
}
async close() {
await this._object.close();
}
}
exports.ElectronApplicationDispatcher = ElectronApplicationDispatcher;

View File

@@ -0,0 +1,228 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.ElementHandleDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _jsHandleDispatcher = require("./jsHandleDispatcher");
var _frameDispatcher = require("./frameDispatcher");
var _browserContextDispatcher = require("./browserContextDispatcher");
var _pageDispatcher = require("./pageDispatcher");
/**
* 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.
*/
class ElementHandleDispatcher extends _jsHandleDispatcher.JSHandleDispatcher {
static from(scope, handle) {
return (0, _dispatcher.existingDispatcher)(handle) || new ElementHandleDispatcher(scope, handle);
}
static fromNullable(scope, handle) {
if (!handle) return undefined;
return (0, _dispatcher.existingDispatcher)(handle) || new ElementHandleDispatcher(scope, handle);
}
static fromJSHandle(scope, handle) {
const result = (0, _dispatcher.existingDispatcher)(handle);
if (result) return result;
return handle.asElement() ? new ElementHandleDispatcher(scope, handle.asElement()) : new _jsHandleDispatcher.JSHandleDispatcher(scope, handle);
}
constructor(scope, elementHandle) {
super(scope, elementHandle);
this._type_ElementHandle = true;
this._elementHandle = void 0;
this._elementHandle = elementHandle;
}
async ownerFrame(params, metadata) {
const frame = await this._elementHandle.ownerFrame();
return {
frame: frame ? _frameDispatcher.FrameDispatcher.from(this._browserContextDispatcher(), frame) : undefined
};
}
async contentFrame(params, metadata) {
const frame = await this._elementHandle.contentFrame();
return {
frame: frame ? _frameDispatcher.FrameDispatcher.from(this._browserContextDispatcher(), frame) : undefined
};
}
async getAttribute(params, metadata) {
const value = await this._elementHandle.getAttribute(metadata, params.name);
return {
value: value === null ? undefined : value
};
}
async inputValue(params, metadata) {
const value = await this._elementHandle.inputValue(metadata);
return {
value
};
}
async textContent(params, metadata) {
const value = await this._elementHandle.textContent(metadata);
return {
value: value === null ? undefined : value
};
}
async innerText(params, metadata) {
return {
value: await this._elementHandle.innerText(metadata)
};
}
async innerHTML(params, metadata) {
return {
value: await this._elementHandle.innerHTML(metadata)
};
}
async isChecked(params, metadata) {
return {
value: await this._elementHandle.isChecked(metadata)
};
}
async isDisabled(params, metadata) {
return {
value: await this._elementHandle.isDisabled(metadata)
};
}
async isEditable(params, metadata) {
return {
value: await this._elementHandle.isEditable(metadata)
};
}
async isEnabled(params, metadata) {
return {
value: await this._elementHandle.isEnabled(metadata)
};
}
async isHidden(params, metadata) {
return {
value: await this._elementHandle.isHidden(metadata)
};
}
async isVisible(params, metadata) {
return {
value: await this._elementHandle.isVisible(metadata)
};
}
async dispatchEvent(params, metadata) {
await this._elementHandle.dispatchEvent(metadata, params.type, (0, _jsHandleDispatcher.parseArgument)(params.eventInit));
}
async scrollIntoViewIfNeeded(params, metadata) {
await this._elementHandle.scrollIntoViewIfNeeded(metadata, params);
}
async hover(params, metadata) {
return await this._elementHandle.hover(metadata, params);
}
async click(params, metadata) {
return await this._elementHandle.click(metadata, params);
}
async dblclick(params, metadata) {
return await this._elementHandle.dblclick(metadata, params);
}
async tap(params, metadata) {
return await this._elementHandle.tap(metadata, params);
}
async selectOption(params, metadata) {
const elements = (params.elements || []).map(e => e._elementHandle);
return {
values: await this._elementHandle.selectOption(metadata, elements, params.options || [], params)
};
}
async fill(params, metadata) {
return await this._elementHandle.fill(metadata, params.value, params);
}
async selectText(params, metadata) {
await this._elementHandle.selectText(metadata, params);
}
async setInputFiles(params, metadata) {
return await this._elementHandle.setInputFiles(metadata, params);
}
async focus(params, metadata) {
await this._elementHandle.focus(metadata);
}
async type(params, metadata) {
return await this._elementHandle.type(metadata, params.text, params);
}
async press(params, metadata) {
return await this._elementHandle.press(metadata, params.key, params);
}
async check(params, metadata) {
return await this._elementHandle.check(metadata, params);
}
async uncheck(params, metadata) {
return await this._elementHandle.uncheck(metadata, params);
}
async boundingBox(params, metadata) {
const value = await this._elementHandle.boundingBox();
return {
value: value || undefined
};
}
async screenshot(params, metadata) {
const mask = (params.mask || []).map(({
frame,
selector
}) => ({
frame: frame._object,
selector
}));
return {
binary: await this._elementHandle.screenshot(metadata, {
...params,
mask
})
};
}
async querySelector(params, metadata) {
const handle = await this._elementHandle.querySelector(params.selector, params);
return {
element: ElementHandleDispatcher.fromNullable(this.parentScope(), handle)
};
}
async querySelectorAll(params, metadata) {
const elements = await this._elementHandle.querySelectorAll(params.selector);
return {
elements: elements.map(e => ElementHandleDispatcher.from(this.parentScope(), e))
};
}
async evalOnSelector(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._elementHandle.evalOnSelector(params.selector, !!params.strict, params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async evalOnSelectorAll(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._elementHandle.evalOnSelectorAll(params.selector, params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async waitForElementState(params, metadata) {
await this._elementHandle.waitForElementState(metadata, params.state, params);
}
async waitForSelector(params, metadata) {
return {
element: ElementHandleDispatcher.fromNullable(this.parentScope(), await this._elementHandle.waitForSelector(metadata, params.selector, params))
};
}
_browserContextDispatcher() {
const scope = this.parentScope();
if (scope instanceof _browserContextDispatcher.BrowserContextDispatcher) return scope;
if (scope instanceof _pageDispatcher.PageDispatcher) return scope.parentScope();
if (scope instanceof _pageDispatcher.WorkerDispatcher || scope instanceof _frameDispatcher.FrameDispatcher) {
const parentScope = scope.parentScope();
if (parentScope instanceof _browserContextDispatcher.BrowserContextDispatcher) return parentScope;
return parentScope.parentScope();
}
throw new Error('ElementHandle belongs to unexpected scope');
}
}
exports.ElementHandleDispatcher = ElementHandleDispatcher;

View File

@@ -0,0 +1,293 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.FrameDispatcher = void 0;
var _frames = require("../frames");
var _dispatcher = require("./dispatcher");
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
var _jsHandleDispatcher = require("./jsHandleDispatcher");
var _networkDispatchers = require("./networkDispatchers");
var _utils = require("../../utils");
var _ariaSnapshot = require("../ariaSnapshot");
/**
* 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.
*/
class FrameDispatcher extends _dispatcher.Dispatcher {
static from(scope, frame) {
const result = (0, _dispatcher.existingDispatcher)(frame);
return result || new FrameDispatcher(scope, frame);
}
static fromNullable(scope, frame) {
if (!frame) return;
return FrameDispatcher.from(scope, frame);
}
constructor(scope, frame) {
// Main frames are gc'ed separately from any other frames, so that
// methods on Page that redirect to the main frame remain operational.
// Note: we cannot check parentFrame() here because it may be null after the frame has been detached.
(0, _utils.debugAssert)(frame._page.mainFrame(), 'Cannot determine whether the frame is a main frame');
const gcBucket = frame._page.mainFrame() === frame ? 'MainFrame' : 'Frame';
const pageDispatcher = (0, _dispatcher.existingDispatcher)(frame._page);
super(pageDispatcher || scope, frame, 'Frame', {
url: frame.url(),
name: frame.name(),
parentFrame: FrameDispatcher.fromNullable(scope, frame.parentFrame()),
loadStates: Array.from(frame._firedLifecycleEvents)
}, gcBucket);
this._type_Frame = true;
this._frame = void 0;
this._browserContextDispatcher = void 0;
this._browserContextDispatcher = scope;
this._frame = frame;
this.addObjectListener(_frames.Frame.Events.AddLifecycle, lifecycleEvent => {
this._dispatchEvent('loadstate', {
add: lifecycleEvent
});
});
this.addObjectListener(_frames.Frame.Events.RemoveLifecycle, lifecycleEvent => {
this._dispatchEvent('loadstate', {
remove: lifecycleEvent
});
});
this.addObjectListener(_frames.Frame.Events.InternalNavigation, event => {
if (!event.isPublic) return;
const params = {
url: event.url,
name: event.name,
error: event.error ? event.error.message : undefined
};
if (event.newDocument) params.newDocument = {
request: _networkDispatchers.RequestDispatcher.fromNullable(this._browserContextDispatcher, event.newDocument.request || null)
};
this._dispatchEvent('navigated', params);
});
}
async goto(params, metadata) {
return {
response: _networkDispatchers.ResponseDispatcher.fromNullable(this._browserContextDispatcher, await this._frame.goto(metadata, params.url, params))
};
}
async frameElement() {
return {
element: _elementHandlerDispatcher.ElementHandleDispatcher.from(this, await this._frame.frameElement())
};
}
async evaluateExpression(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._frame.evaluateExpression(params.expression, {
isFunction: params.isFunction
}, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async evaluateExpressionHandle(params, metadata) {
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, await this._frame.evaluateExpressionHandle(params.expression, {
isFunction: params.isFunction
}, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async waitForSelector(params, metadata) {
return {
element: _elementHandlerDispatcher.ElementHandleDispatcher.fromNullable(this, await this._frame.waitForSelector(metadata, params.selector, params))
};
}
async dispatchEvent(params, metadata) {
return this._frame.dispatchEvent(metadata, params.selector, params.type, (0, _jsHandleDispatcher.parseArgument)(params.eventInit), params);
}
async evalOnSelector(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._frame.evalOnSelector(params.selector, !!params.strict, params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async evalOnSelectorAll(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._frame.evalOnSelectorAll(params.selector, params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async querySelector(params, metadata) {
return {
element: _elementHandlerDispatcher.ElementHandleDispatcher.fromNullable(this, await this._frame.querySelector(params.selector, params))
};
}
async querySelectorAll(params, metadata) {
const elements = await this._frame.querySelectorAll(params.selector);
return {
elements: elements.map(e => _elementHandlerDispatcher.ElementHandleDispatcher.from(this, e))
};
}
async queryCount(params) {
return {
value: await this._frame.queryCount(params.selector)
};
}
async content() {
return {
value: await this._frame.content()
};
}
async setContent(params, metadata) {
return await this._frame.setContent(metadata, params.html, params);
}
async addScriptTag(params, metadata) {
return {
element: _elementHandlerDispatcher.ElementHandleDispatcher.from(this, await this._frame.addScriptTag(params))
};
}
async addStyleTag(params, metadata) {
return {
element: _elementHandlerDispatcher.ElementHandleDispatcher.from(this, await this._frame.addStyleTag(params))
};
}
async click(params, metadata) {
metadata.potentiallyClosesScope = true;
return await this._frame.click(metadata, params.selector, params);
}
async dblclick(params, metadata) {
return await this._frame.dblclick(metadata, params.selector, params);
}
async dragAndDrop(params, metadata) {
return await this._frame.dragAndDrop(metadata, params.source, params.target, params);
}
async tap(params, metadata) {
return await this._frame.tap(metadata, params.selector, params);
}
async fill(params, metadata) {
return await this._frame.fill(metadata, params.selector, params.value, params);
}
async focus(params, metadata) {
await this._frame.focus(metadata, params.selector, params);
}
async blur(params, metadata) {
await this._frame.blur(metadata, params.selector, params);
}
async textContent(params, metadata) {
const value = await this._frame.textContent(metadata, params.selector, params);
return {
value: value === null ? undefined : value
};
}
async innerText(params, metadata) {
return {
value: await this._frame.innerText(metadata, params.selector, params)
};
}
async innerHTML(params, metadata) {
return {
value: await this._frame.innerHTML(metadata, params.selector, params)
};
}
async getAttribute(params, metadata) {
const value = await this._frame.getAttribute(metadata, params.selector, params.name, params);
return {
value: value === null ? undefined : value
};
}
async inputValue(params, metadata) {
const value = await this._frame.inputValue(metadata, params.selector, params);
return {
value
};
}
async isChecked(params, metadata) {
return {
value: await this._frame.isChecked(metadata, params.selector, params)
};
}
async isDisabled(params, metadata) {
return {
value: await this._frame.isDisabled(metadata, params.selector, params)
};
}
async isEditable(params, metadata) {
return {
value: await this._frame.isEditable(metadata, params.selector, params)
};
}
async isEnabled(params, metadata) {
return {
value: await this._frame.isEnabled(metadata, params.selector, params)
};
}
async isHidden(params, metadata) {
return {
value: await this._frame.isHidden(metadata, params.selector, params)
};
}
async isVisible(params, metadata) {
return {
value: await this._frame.isVisible(metadata, params.selector, params)
};
}
async hover(params, metadata) {
return await this._frame.hover(metadata, params.selector, params);
}
async selectOption(params, metadata) {
const elements = (params.elements || []).map(e => e._elementHandle);
return {
values: await this._frame.selectOption(metadata, params.selector, elements, params.options || [], params)
};
}
async setInputFiles(params, metadata) {
return await this._frame.setInputFiles(metadata, params.selector, params);
}
async type(params, metadata) {
return await this._frame.type(metadata, params.selector, params.text, params);
}
async press(params, metadata) {
return await this._frame.press(metadata, params.selector, params.key, params);
}
async check(params, metadata) {
return await this._frame.check(metadata, params.selector, params);
}
async uncheck(params, metadata) {
return await this._frame.uncheck(metadata, params.selector, params);
}
async waitForTimeout(params, metadata) {
return await this._frame.waitForTimeout(metadata, params.timeout);
}
async waitForFunction(params, metadata) {
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, await this._frame._waitForFunctionExpression(metadata, params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg), params))
};
}
async title(params, metadata) {
return {
value: await this._frame.title()
};
}
async highlight(params, metadata) {
return await this._frame.highlight(params.selector);
}
async expect(params, metadata) {
metadata.potentiallyClosesScope = true;
let expectedValue = params.expectedValue ? (0, _jsHandleDispatcher.parseArgument)(params.expectedValue) : undefined;
if (params.expression === 'to.match.aria' && expectedValue) expectedValue = (0, _ariaSnapshot.parseAriaSnapshot)(expectedValue);
const result = await this._frame.expect(metadata, params.selector, {
...params,
expectedValue
});
if (result.received !== undefined) result.received = (0, _jsHandleDispatcher.serializeResult)(result.received);
return result;
}
async ariaSnapshot(params, metadata) {
return {
snapshot: await this._frame.ariaSnapshot(metadata, params.selector, params)
};
}
}
exports.FrameDispatcher = FrameDispatcher;

View File

@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.JSHandleDispatcher = void 0;
exports.parseArgument = parseArgument;
exports.parseValue = parseValue;
exports.serializeResult = serializeResult;
var _dispatcher = require("./dispatcher");
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
var _serializers = require("../../protocol/serializers");
/**
* 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.
*/
class JSHandleDispatcher extends _dispatcher.Dispatcher {
constructor(scope, jsHandle) {
// Do not call this directly, use createHandle() instead.
super(scope, jsHandle, jsHandle.asElement() ? 'ElementHandle' : 'JSHandle', {
preview: jsHandle.toString()
});
this._type_JSHandle = true;
jsHandle._setPreviewCallback(preview => this._dispatchEvent('previewUpdated', {
preview
}));
}
async evaluateExpression(params) {
return {
value: serializeResult(await this._object.evaluateExpression(params.expression, {
isFunction: params.isFunction
}, parseArgument(params.arg)))
};
}
async evaluateExpressionHandle(params) {
const jsHandle = await this._object.evaluateExpressionHandle(params.expression, {
isFunction: params.isFunction
}, parseArgument(params.arg));
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this.parentScope(), jsHandle)
};
}
async getProperty(params) {
const jsHandle = await this._object.getProperty(params.name);
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this.parentScope(), jsHandle)
};
}
async getPropertyList() {
const map = await this._object.getProperties();
const properties = [];
for (const [name, value] of map) properties.push({
name,
value: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this.parentScope(), value)
});
return {
properties
};
}
async jsonValue() {
return {
value: serializeResult(await this._object.jsonValue())
};
}
async dispose(_, metadata) {
metadata.potentiallyClosesScope = true;
this._object.dispose();
this._dispose();
}
}
// Generic channel parser converts guids to JSHandleDispatchers,
// and this function takes care of converting them into underlying JSHandles.
exports.JSHandleDispatcher = JSHandleDispatcher;
function parseArgument(arg) {
return (0, _serializers.parseSerializedValue)(arg.value, arg.handles.map(a => a._object));
}
function parseValue(v) {
return (0, _serializers.parseSerializedValue)(v, []);
}
function serializeResult(arg) {
return (0, _serializers.serializeValue)(arg, value => ({
fallThrough: value
}));
}

View File

@@ -0,0 +1,59 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.JsonPipeDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _utils = require("../../utils");
/**
* 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.
*/
class JsonPipeDispatcher extends _dispatcher.Dispatcher {
constructor(scope) {
super(scope, {
guid: 'jsonPipe@' + (0, _utils.createGuid)()
}, 'JsonPipe', {});
this._type_JsonPipe = true;
}
async send(params) {
this.emit('message', params.message);
}
async close() {
this.emit('close');
if (!this._disposed) {
this._dispatchEvent('closed', {});
this._dispose();
}
}
dispatch(message) {
if (!this._disposed) this._dispatchEvent('message', {
message
});
}
wasClosed(reason) {
if (!this._disposed) {
this._dispatchEvent('closed', {
reason
});
this._dispose();
}
}
dispose() {
this._dispose();
}
}
exports.JsonPipeDispatcher = JsonPipeDispatcher;

View File

@@ -0,0 +1,413 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LocalUtilsDispatcher = void 0;
exports.urlToWSEndpoint = urlToWSEndpoint;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _os = _interopRequireDefault(require("os"));
var _manualPromise = require("../../utils/manualPromise");
var _utils = require("../../utils");
var _dispatcher = require("./dispatcher");
var _zipBundle = require("../../zipBundle");
var _zipFile = require("../../utils/zipFile");
var _jsonPipeDispatcher = require("../dispatchers/jsonPipeDispatcher");
var _transport = require("../transport");
var _socksInterceptor = require("../socksInterceptor");
var _userAgent = require("../../utils/userAgent");
var _progress = require("../progress");
var _network = require("../../utils/network");
var _instrumentation = require("../../server/instrumentation");
var _deviceDescriptors = require("../deviceDescriptors");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* 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.
*/
class LocalUtilsDispatcher extends _dispatcher.Dispatcher {
constructor(scope, playwright) {
const localUtils = new _instrumentation.SdkObject(playwright, 'localUtils', 'localUtils');
const deviceDescriptors = Object.entries(_deviceDescriptors.deviceDescriptors).map(([name, descriptor]) => ({
name,
descriptor
}));
super(scope, localUtils, 'LocalUtils', {
deviceDescriptors
});
this._type_LocalUtils = void 0;
this._harBackends = new Map();
this._stackSessions = new Map();
this._type_LocalUtils = true;
}
async zip(params) {
const promise = new _manualPromise.ManualPromise();
const zipFile = new _zipBundle.yazl.ZipFile();
zipFile.on('error', error => promise.reject(error));
const addFile = (file, name) => {
try {
if (_fs.default.statSync(file).isFile()) zipFile.addFile(file, name);
} catch (e) {}
};
for (const entry of params.entries) addFile(entry.value, entry.name);
// Add stacks and the sources.
const stackSession = params.stacksId ? this._stackSessions.get(params.stacksId) : undefined;
if (stackSession !== null && stackSession !== void 0 && stackSession.callStacks.length) {
await stackSession.writer;
if (process.env.PW_LIVE_TRACE_STACKS) {
zipFile.addFile(stackSession.file, 'trace.stacks');
} else {
const buffer = Buffer.from(JSON.stringify((0, _utils.serializeClientSideCallMetadata)(stackSession.callStacks)));
zipFile.addBuffer(buffer, 'trace.stacks');
}
}
// Collect sources from stacks.
if (params.includeSources) {
const sourceFiles = new Set();
for (const {
stack
} of (stackSession === null || stackSession === void 0 ? void 0 : stackSession.callStacks) || []) {
if (!stack) continue;
for (const {
file
} of stack) sourceFiles.add(file);
}
for (const sourceFile of sourceFiles) addFile(sourceFile, 'resources/src@' + (0, _utils.calculateSha1)(sourceFile) + '.txt');
}
if (params.mode === 'write') {
// New file, just compress the entries.
await _fs.default.promises.mkdir(_path.default.dirname(params.zipFile), {
recursive: true
});
zipFile.end(undefined, () => {
zipFile.outputStream.pipe(_fs.default.createWriteStream(params.zipFile)).on('close', () => promise.resolve()).on('error', error => promise.reject(error));
});
await promise;
await this._deleteStackSession(params.stacksId);
return;
}
// File already exists. Repack and add new entries.
const tempFile = params.zipFile + '.tmp';
await _fs.default.promises.rename(params.zipFile, tempFile);
_zipBundle.yauzl.open(tempFile, (err, inZipFile) => {
if (err) {
promise.reject(err);
return;
}
(0, _utils.assert)(inZipFile);
let pendingEntries = inZipFile.entryCount;
inZipFile.on('entry', entry => {
inZipFile.openReadStream(entry, (err, readStream) => {
if (err) {
promise.reject(err);
return;
}
zipFile.addReadStream(readStream, entry.fileName);
if (--pendingEntries === 0) {
zipFile.end(undefined, () => {
zipFile.outputStream.pipe(_fs.default.createWriteStream(params.zipFile)).on('close', () => {
_fs.default.promises.unlink(tempFile).then(() => {
promise.resolve();
}).catch(error => promise.reject(error));
});
});
}
});
});
});
await promise;
await this._deleteStackSession(params.stacksId);
}
async harOpen(params, metadata) {
let harBackend;
if (params.file.endsWith('.zip')) {
const zipFile = new _zipFile.ZipFile(params.file);
const entryNames = await zipFile.entries();
const harEntryName = entryNames.find(e => e.endsWith('.har'));
if (!harEntryName) return {
error: 'Specified archive does not have a .har file'
};
const har = await zipFile.read(harEntryName);
const harFile = JSON.parse(har.toString());
harBackend = new HarBackend(harFile, null, zipFile);
} else {
const harFile = JSON.parse(await _fs.default.promises.readFile(params.file, 'utf-8'));
harBackend = new HarBackend(harFile, _path.default.dirname(params.file), null);
}
this._harBackends.set(harBackend.id, harBackend);
return {
harId: harBackend.id
};
}
async harLookup(params, metadata) {
const harBackend = this._harBackends.get(params.harId);
if (!harBackend) return {
action: 'error',
message: `Internal error: har was not opened`
};
return await harBackend.lookup(params.url, params.method, params.headers, params.postData, params.isNavigationRequest);
}
async harClose(params, metadata) {
const harBackend = this._harBackends.get(params.harId);
if (harBackend) {
this._harBackends.delete(harBackend.id);
harBackend.dispose();
}
}
async harUnzip(params, metadata) {
const dir = _path.default.dirname(params.zipFile);
const zipFile = new _zipFile.ZipFile(params.zipFile);
for (const entry of await zipFile.entries()) {
const buffer = await zipFile.read(entry);
if (entry === 'har.har') await _fs.default.promises.writeFile(params.harFile, buffer);else await _fs.default.promises.writeFile(_path.default.join(dir, entry), buffer);
}
zipFile.close();
await _fs.default.promises.unlink(params.zipFile);
}
async connect(params, metadata) {
const controller = new _progress.ProgressController(metadata, this._object);
controller.setLogName('browser');
return await controller.run(async progress => {
var _params$exposeNetwork;
const wsHeaders = {
'User-Agent': (0, _userAgent.getUserAgent)(),
'x-playwright-proxy': (_params$exposeNetwork = params.exposeNetwork) !== null && _params$exposeNetwork !== void 0 ? _params$exposeNetwork : '',
...params.headers
};
const wsEndpoint = await urlToWSEndpoint(progress, params.wsEndpoint);
const transport = await _transport.WebSocketTransport.connect(progress, wsEndpoint, wsHeaders, true, 'x-playwright-debug-log');
const socksInterceptor = new _socksInterceptor.SocksInterceptor(transport, params.exposeNetwork, params.socksProxyRedirectPortForTest);
const pipe = new _jsonPipeDispatcher.JsonPipeDispatcher(this);
transport.onmessage = json => {
if (socksInterceptor.interceptMessage(json)) return;
const cb = () => {
try {
pipe.dispatch(json);
} catch (e) {
transport.close();
}
};
if (params.slowMo) setTimeout(cb, params.slowMo);else cb();
};
pipe.on('message', message => {
transport.send(message);
});
transport.onclose = reason => {
socksInterceptor === null || socksInterceptor === void 0 || socksInterceptor.cleanup();
pipe.wasClosed(reason);
};
pipe.on('close', () => transport.close());
return {
pipe,
headers: transport.headers
};
}, params.timeout || 0);
}
async tracingStarted(params, metadata) {
let tmpDir = undefined;
if (!params.tracesDir) tmpDir = await _fs.default.promises.mkdtemp(_path.default.join(_os.default.tmpdir(), 'playwright-tracing-'));
const traceStacksFile = _path.default.join(params.tracesDir || tmpDir, params.traceName + '.stacks');
this._stackSessions.set(traceStacksFile, {
callStacks: [],
file: traceStacksFile,
writer: Promise.resolve(),
tmpDir
});
return {
stacksId: traceStacksFile
};
}
async traceDiscarded(params, metadata) {
await this._deleteStackSession(params.stacksId);
}
async addStackToTracingNoReply(params, metadata) {
for (const session of this._stackSessions.values()) {
session.callStacks.push(params.callData);
if (process.env.PW_LIVE_TRACE_STACKS) {
session.writer = session.writer.then(() => {
const buffer = Buffer.from(JSON.stringify((0, _utils.serializeClientSideCallMetadata)(session.callStacks)));
return _fs.default.promises.writeFile(session.file, buffer);
});
}
}
}
async _deleteStackSession(stacksId) {
const session = stacksId ? this._stackSessions.get(stacksId) : undefined;
if (!session) return;
await session.writer;
if (session.tmpDir) await (0, _utils.removeFolders)([session.tmpDir]);
this._stackSessions.delete(stacksId);
}
}
exports.LocalUtilsDispatcher = LocalUtilsDispatcher;
const redirectStatus = [301, 302, 303, 307, 308];
class HarBackend {
constructor(harFile, baseDir, zipFile) {
this.id = (0, _utils.createGuid)();
this._harFile = void 0;
this._zipFile = void 0;
this._baseDir = void 0;
this._harFile = harFile;
this._baseDir = baseDir;
this._zipFile = zipFile;
}
async lookup(url, method, headers, postData, isNavigationRequest) {
let entry;
try {
entry = await this._harFindResponse(url, method, headers, postData);
} catch (e) {
return {
action: 'error',
message: 'HAR error: ' + e.message
};
}
if (!entry) return {
action: 'noentry'
};
// If navigation is being redirected, restart it with the final url to ensure the document's url changes.
if (entry.request.url !== url && isNavigationRequest) return {
action: 'redirect',
redirectURL: entry.request.url
};
const response = entry.response;
try {
const buffer = await this._loadContent(response.content);
return {
action: 'fulfill',
status: response.status,
headers: response.headers,
body: buffer
};
} catch (e) {
return {
action: 'error',
message: e.message
};
}
}
async _loadContent(content) {
const file = content._file;
let buffer;
if (file) {
if (this._zipFile) buffer = await this._zipFile.read(file);else buffer = await _fs.default.promises.readFile(_path.default.resolve(this._baseDir, file));
} else {
buffer = Buffer.from(content.text || '', content.encoding === 'base64' ? 'base64' : 'utf-8');
}
return buffer;
}
async _harFindResponse(url, method, headers, postData) {
const harLog = this._harFile.log;
const visited = new Set();
while (true) {
const entries = [];
for (const candidate of harLog.entries) {
if (candidate.request.url !== url || candidate.request.method !== method) continue;
if (method === 'POST' && postData && candidate.request.postData) {
const buffer = await this._loadContent(candidate.request.postData);
if (!buffer.equals(postData)) {
const boundary = multipartBoundary(headers);
if (!boundary) continue;
const candidataBoundary = multipartBoundary(candidate.request.headers);
if (!candidataBoundary) continue;
// Try to match multipart/form-data ignroing boundary as it changes between requests.
if (postData.toString().replaceAll(boundary, '') !== buffer.toString().replaceAll(candidataBoundary, '')) continue;
}
}
entries.push(candidate);
}
if (!entries.length) return;
let entry = entries[0];
// Disambiguate using headers - then one with most matching headers wins.
if (entries.length > 1) {
const list = [];
for (const candidate of entries) {
const matchingHeaders = countMatchingHeaders(candidate.request.headers, headers);
list.push({
candidate,
matchingHeaders
});
}
list.sort((a, b) => b.matchingHeaders - a.matchingHeaders);
entry = list[0].candidate;
}
if (visited.has(entry)) throw new Error(`Found redirect cycle for ${url}`);
visited.add(entry);
// Follow redirects.
const locationHeader = entry.response.headers.find(h => h.name.toLowerCase() === 'location');
if (redirectStatus.includes(entry.response.status) && locationHeader) {
const locationURL = new URL(locationHeader.value, url);
url = locationURL.toString();
if ((entry.response.status === 301 || entry.response.status === 302) && method === 'POST' || entry.response.status === 303 && !['GET', 'HEAD'].includes(method)) {
// HTTP-redirect fetch step 13 (https://fetch.spec.whatwg.org/#http-redirect-fetch)
method = 'GET';
}
continue;
}
return entry;
}
}
dispose() {
var _this$_zipFile;
(_this$_zipFile = this._zipFile) === null || _this$_zipFile === void 0 || _this$_zipFile.close();
}
}
function countMatchingHeaders(harHeaders, headers) {
const set = new Set(headers.map(h => h.name.toLowerCase() + ':' + h.value));
let matches = 0;
for (const h of harHeaders) {
if (set.has(h.name.toLowerCase() + ':' + h.value)) ++matches;
}
return matches;
}
async function urlToWSEndpoint(progress, endpointURL) {
var _progress$timeUntilDe;
if (endpointURL.startsWith('ws')) return endpointURL;
progress === null || progress === void 0 || progress.log(`<ws preparing> retrieving websocket url from ${endpointURL}`);
const fetchUrl = new URL(endpointURL);
if (!fetchUrl.pathname.endsWith('/')) fetchUrl.pathname += '/';
fetchUrl.pathname += 'json';
const json = await (0, _network.fetchData)({
url: fetchUrl.toString(),
method: 'GET',
timeout: (_progress$timeUntilDe = progress === null || progress === void 0 ? void 0 : progress.timeUntilDeadline()) !== null && _progress$timeUntilDe !== void 0 ? _progress$timeUntilDe : 30_000,
headers: {
'User-Agent': (0, _userAgent.getUserAgent)()
}
}, async (params, response) => {
return new Error(`Unexpected status ${response.statusCode} when connecting to ${fetchUrl.toString()}.\n` + `This does not look like a Playwright server, try connecting via ws://.`);
});
progress === null || progress === void 0 || progress.throwIfAborted();
const wsUrl = new URL(endpointURL);
let wsEndpointPath = JSON.parse(json).wsEndpointPath;
if (wsEndpointPath.startsWith('/')) wsEndpointPath = wsEndpointPath.substring(1);
if (!wsUrl.pathname.endsWith('/')) wsUrl.pathname += '/';
wsUrl.pathname += wsEndpointPath;
wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:';
return wsUrl.toString();
}
function multipartBoundary(headers) {
const contentType = headers.find(h => h.name.toLowerCase() === 'content-type');
if (!(contentType !== null && contentType !== void 0 && contentType.value.includes('multipart/form-data'))) return undefined;
const boundary = contentType.value.match(/boundary=(\S+)/);
if (boundary) return boundary[1];
return undefined;
}

View File

@@ -0,0 +1,221 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebSocketDispatcher = exports.RouteDispatcher = exports.ResponseDispatcher = exports.RequestDispatcher = exports.APIRequestContextDispatcher = void 0;
var _network = require("../network");
var _dispatcher = require("./dispatcher");
var _tracingDispatcher = require("./tracingDispatcher");
var _frameDispatcher = require("./frameDispatcher");
var _pageDispatcher = require("./pageDispatcher");
/**
* 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.
*/
class RequestDispatcher extends _dispatcher.Dispatcher {
static from(scope, request) {
const result = (0, _dispatcher.existingDispatcher)(request);
return result || new RequestDispatcher(scope, request);
}
static fromNullable(scope, request) {
return request ? RequestDispatcher.from(scope, request) : undefined;
}
constructor(scope, request) {
var _request$frame;
const postData = request.postDataBuffer();
// Always try to attach request to the page, if not, frame.
const frame = request.frame();
const page = (_request$frame = request.frame()) === null || _request$frame === void 0 ? void 0 : _request$frame._page;
const pageDispatcher = page ? (0, _dispatcher.existingDispatcher)(page) : null;
const frameDispatcher = frame ? _frameDispatcher.FrameDispatcher.from(scope, frame) : null;
super(pageDispatcher || frameDispatcher || scope, request, 'Request', {
frame: _frameDispatcher.FrameDispatcher.fromNullable(scope, request.frame()),
serviceWorker: _pageDispatcher.WorkerDispatcher.fromNullable(scope, request.serviceWorker()),
url: request.url(),
resourceType: request.resourceType(),
method: request.method(),
postData: postData === null ? undefined : postData,
headers: request.headers(),
isNavigationRequest: request.isNavigationRequest(),
redirectedFrom: RequestDispatcher.fromNullable(scope, request.redirectedFrom())
});
this._type_Request = void 0;
this._browserContextDispatcher = void 0;
this._type_Request = true;
this._browserContextDispatcher = scope;
}
async rawRequestHeaders(params) {
return {
headers: await this._object.rawRequestHeaders()
};
}
async response() {
return {
response: ResponseDispatcher.fromNullable(this._browserContextDispatcher, await this._object.response())
};
}
}
exports.RequestDispatcher = RequestDispatcher;
class ResponseDispatcher extends _dispatcher.Dispatcher {
static from(scope, response) {
const result = (0, _dispatcher.existingDispatcher)(response);
const requestDispatcher = RequestDispatcher.from(scope, response.request());
return result || new ResponseDispatcher(requestDispatcher, response);
}
static fromNullable(scope, response) {
return response ? ResponseDispatcher.from(scope, response) : undefined;
}
constructor(scope, response) {
super(scope, response, 'Response', {
// TODO: responses in popups can point to non-reported requests.
request: scope,
url: response.url(),
status: response.status(),
statusText: response.statusText(),
headers: response.headers(),
timing: response.timing(),
fromServiceWorker: response.fromServiceWorker()
});
this._type_Response = true;
}
async body() {
return {
binary: await this._object.body()
};
}
async securityDetails() {
return {
value: (await this._object.securityDetails()) || undefined
};
}
async serverAddr() {
return {
value: (await this._object.serverAddr()) || undefined
};
}
async rawResponseHeaders(params) {
return {
headers: await this._object.rawResponseHeaders()
};
}
async sizes(params) {
return {
sizes: await this._object.sizes()
};
}
}
exports.ResponseDispatcher = ResponseDispatcher;
class RouteDispatcher extends _dispatcher.Dispatcher {
static from(scope, route) {
const result = (0, _dispatcher.existingDispatcher)(route);
return result || new RouteDispatcher(scope, route);
}
constructor(scope, route) {
super(scope, route, 'Route', {
// Context route can point to a non-reported request, so we send the request in the initializer.
request: scope
});
this._type_Route = true;
}
async continue(params, metadata) {
await this._object.continue({
url: params.url,
method: params.method,
headers: params.headers,
postData: params.postData,
isFallback: params.isFallback
});
}
async fulfill(params, metadata) {
await this._object.fulfill(params);
}
async abort(params, metadata) {
await this._object.abort(params.errorCode || 'failed');
}
async redirectNavigationRequest(params) {
await this._object.redirectNavigationRequest(params.url);
}
}
exports.RouteDispatcher = RouteDispatcher;
class WebSocketDispatcher extends _dispatcher.Dispatcher {
constructor(scope, webSocket) {
super(scope, webSocket, 'WebSocket', {
url: webSocket.url()
});
this._type_EventTarget = true;
this._type_WebSocket = true;
this.addObjectListener(_network.WebSocket.Events.FrameSent, event => this._dispatchEvent('frameSent', event));
this.addObjectListener(_network.WebSocket.Events.FrameReceived, event => this._dispatchEvent('frameReceived', event));
this.addObjectListener(_network.WebSocket.Events.SocketError, error => this._dispatchEvent('socketError', {
error
}));
this.addObjectListener(_network.WebSocket.Events.Close, () => this._dispatchEvent('close', {}));
}
}
exports.WebSocketDispatcher = WebSocketDispatcher;
class APIRequestContextDispatcher extends _dispatcher.Dispatcher {
static from(scope, request) {
const result = (0, _dispatcher.existingDispatcher)(request);
return result || new APIRequestContextDispatcher(scope, request);
}
static fromNullable(scope, request) {
return request ? APIRequestContextDispatcher.from(scope, request) : undefined;
}
constructor(parentScope, request) {
// We will reparent these to the context below.
const tracing = _tracingDispatcher.TracingDispatcher.from(parentScope, request.tracing());
super(parentScope, request, 'APIRequestContext', {
tracing
});
this._type_APIRequestContext = true;
this.adopt(tracing);
}
async storageState() {
return this._object.storageState();
}
async dispose(params, metadata) {
metadata.potentiallyClosesScope = true;
await this._object.dispose(params);
this._dispose();
}
async fetch(params, metadata) {
const fetchResponse = await this._object.fetch(params, metadata);
return {
response: {
url: fetchResponse.url,
status: fetchResponse.status,
statusText: fetchResponse.statusText,
headers: fetchResponse.headers,
fetchUid: fetchResponse.fetchUid
}
};
}
async fetchResponseBody(params) {
return {
binary: this._object.fetchResponses.get(params.fetchUid)
};
}
async fetchLog(params) {
const log = this._object.fetchLog.get(params.fetchUid) || [];
return {
log
};
}
async disposeAPIResponse(params) {
this._object.disposeResponse(params.fetchUid);
}
}
exports.APIRequestContextDispatcher = APIRequestContextDispatcher;

View File

@@ -0,0 +1,367 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WorkerDispatcher = exports.PageDispatcher = exports.BindingCallDispatcher = void 0;
var _page = require("../page");
var _dispatcher = require("./dispatcher");
var _errors = require("../errors");
var _frameDispatcher = require("./frameDispatcher");
var _networkDispatchers = require("./networkDispatchers");
var _jsHandleDispatcher = require("./jsHandleDispatcher");
var _elementHandlerDispatcher = require("./elementHandlerDispatcher");
var _artifactDispatcher = require("./artifactDispatcher");
var _utils = require("../../utils");
var _webSocketRouteDispatcher = require("./webSocketRouteDispatcher");
/**
* 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.
*/
class PageDispatcher extends _dispatcher.Dispatcher {
static from(parentScope, page) {
return PageDispatcher.fromNullable(parentScope, page);
}
static fromNullable(parentScope, page) {
if (!page) return undefined;
const result = (0, _dispatcher.existingDispatcher)(page);
return result || new PageDispatcher(parentScope, page);
}
constructor(parentScope, page) {
// TODO: theoretically, there could be more than one frame already.
// If we split pageCreated and pageReady, there should be no main frame during pageCreated.
// We will reparent it to the page below using adopt.
const mainFrame = _frameDispatcher.FrameDispatcher.from(parentScope, page.mainFrame());
super(parentScope, page, 'Page', {
mainFrame,
viewportSize: page.viewportSize() || undefined,
isClosed: page.isClosed(),
opener: PageDispatcher.fromNullable(parentScope, page.opener())
});
this._type_EventTarget = true;
this._type_Page = true;
this._page = void 0;
this._subscriptions = new Set();
this._webSocketInterceptionPatterns = [];
this.adopt(mainFrame);
this._page = page;
this.addObjectListener(_page.Page.Events.Close, () => {
this._dispatchEvent('close');
this._dispose();
});
this.addObjectListener(_page.Page.Events.Crash, () => this._dispatchEvent('crash'));
this.addObjectListener(_page.Page.Events.Download, download => {
// Artifact can outlive the page, so bind to the context scope.
this._dispatchEvent('download', {
url: download.url,
suggestedFilename: download.suggestedFilename(),
artifact: _artifactDispatcher.ArtifactDispatcher.from(parentScope, download.artifact)
});
});
this.addObjectListener(_page.Page.Events.FileChooser, fileChooser => this._dispatchEvent('fileChooser', {
element: _elementHandlerDispatcher.ElementHandleDispatcher.from(mainFrame, fileChooser.element()),
isMultiple: fileChooser.isMultiple()
}));
this.addObjectListener(_page.Page.Events.FrameAttached, frame => this._onFrameAttached(frame));
this.addObjectListener(_page.Page.Events.FrameDetached, frame => this._onFrameDetached(frame));
this.addObjectListener(_page.Page.Events.LocatorHandlerTriggered, uid => this._dispatchEvent('locatorHandlerTriggered', {
uid
}));
this.addObjectListener(_page.Page.Events.WebSocket, webSocket => this._dispatchEvent('webSocket', {
webSocket: new _networkDispatchers.WebSocketDispatcher(this, webSocket)
}));
this.addObjectListener(_page.Page.Events.Worker, worker => this._dispatchEvent('worker', {
worker: new WorkerDispatcher(this, worker)
}));
this.addObjectListener(_page.Page.Events.Video, artifact => this._dispatchEvent('video', {
artifact: _artifactDispatcher.ArtifactDispatcher.from(parentScope, artifact)
}));
if (page._video) this._dispatchEvent('video', {
artifact: _artifactDispatcher.ArtifactDispatcher.from(this.parentScope(), page._video)
});
// Ensure client knows about all frames.
const frames = page._frameManager.frames();
for (let i = 1; i < frames.length; i++) this._onFrameAttached(frames[i]);
}
page() {
return this._page;
}
async setDefaultNavigationTimeoutNoReply(params, metadata) {
this._page.setDefaultNavigationTimeout(params.timeout);
}
async setDefaultTimeoutNoReply(params, metadata) {
this._page.setDefaultTimeout(params.timeout);
}
async exposeBinding(params, metadata) {
await this._page.exposeBinding(params.name, !!params.needsHandle, (source, ...args) => {
// When reusing the context, we might have some bindings called late enough,
// after context and page dispatchers have been disposed.
if (this._disposed) return;
const binding = new BindingCallDispatcher(this, params.name, !!params.needsHandle, source, args);
this._dispatchEvent('bindingCall', {
binding
});
return binding.promise();
});
}
async setExtraHTTPHeaders(params, metadata) {
await this._page.setExtraHTTPHeaders(params.headers);
}
async reload(params, metadata) {
return {
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.reload(metadata, params))
};
}
async goBack(params, metadata) {
return {
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goBack(metadata, params))
};
}
async goForward(params, metadata) {
return {
response: _networkDispatchers.ResponseDispatcher.fromNullable(this.parentScope(), await this._page.goForward(metadata, params))
};
}
async requestGC(params, metadata) {
await this._page.requestGC();
}
async registerLocatorHandler(params, metadata) {
const uid = this._page.registerLocatorHandler(params.selector, params.noWaitAfter);
return {
uid
};
}
async resolveLocatorHandlerNoReply(params, metadata) {
this._page.resolveLocatorHandler(params.uid, params.remove);
}
async unregisterLocatorHandler(params, metadata) {
this._page.unregisterLocatorHandler(params.uid);
}
async emulateMedia(params, metadata) {
await this._page.emulateMedia({
media: params.media,
colorScheme: params.colorScheme,
reducedMotion: params.reducedMotion,
forcedColors: params.forcedColors
});
}
async setViewportSize(params, metadata) {
await this._page.setViewportSize(params.viewportSize);
}
async addInitScript(params, metadata) {
await this._page.addInitScript(params.source);
}
async setNetworkInterceptionPatterns(params, metadata) {
if (!params.patterns.length) {
await this._page.setClientRequestInterceptor(undefined);
return;
}
const urlMatchers = params.patterns.map(pattern => pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob);
await this._page.setClientRequestInterceptor((route, request) => {
const matchesSome = urlMatchers.some(urlMatch => (0, _utils.urlMatches)(this._page._browserContext._options.baseURL, request.url(), urlMatch));
if (!matchesSome) return false;
this._dispatchEvent('route', {
route: _networkDispatchers.RouteDispatcher.from(_networkDispatchers.RequestDispatcher.from(this.parentScope(), request), route)
});
return true;
});
}
async setWebSocketInterceptionPatterns(params, metadata) {
this._webSocketInterceptionPatterns = params.patterns;
if (params.patterns.length) await _webSocketRouteDispatcher.WebSocketRouteDispatcher.installIfNeeded(this.parentScope(), this._page);
}
async expectScreenshot(params, metadata) {
const mask = (params.mask || []).map(({
frame,
selector
}) => ({
frame: frame._object,
selector
}));
const locator = params.locator ? {
frame: params.locator.frame._object,
selector: params.locator.selector
} : undefined;
return await this._page.expectScreenshot(metadata, {
...params,
locator,
mask
});
}
async screenshot(params, metadata) {
const mask = (params.mask || []).map(({
frame,
selector
}) => ({
frame: frame._object,
selector
}));
return {
binary: await this._page.screenshot(metadata, {
...params,
mask
})
};
}
async close(params, metadata) {
if (!params.runBeforeUnload) metadata.potentiallyClosesScope = true;
await this._page.close(metadata, params);
}
async updateSubscription(params) {
if (params.event === 'fileChooser') await this._page.setFileChooserIntercepted(params.enabled);
if (params.enabled) this._subscriptions.add(params.event);else this._subscriptions.delete(params.event);
}
async keyboardDown(params, metadata) {
await this._page.keyboard.down(params.key);
}
async keyboardUp(params, metadata) {
await this._page.keyboard.up(params.key);
}
async keyboardInsertText(params, metadata) {
await this._page.keyboard.insertText(params.text);
}
async keyboardType(params, metadata) {
await this._page.keyboard.type(params.text, params);
}
async keyboardPress(params, metadata) {
await this._page.keyboard.press(params.key, params);
}
async mouseMove(params, metadata) {
await this._page.mouse.move(params.x, params.y, params, metadata);
}
async mouseDown(params, metadata) {
await this._page.mouse.down(params, metadata);
}
async mouseUp(params, metadata) {
await this._page.mouse.up(params, metadata);
}
async mouseClick(params, metadata) {
await this._page.mouse.click(params.x, params.y, params, metadata);
}
async mouseWheel(params, metadata) {
await this._page.mouse.wheel(params.deltaX, params.deltaY);
}
async touchscreenTap(params, metadata) {
await this._page.touchscreen.tap(params.x, params.y, metadata);
}
async accessibilitySnapshot(params, metadata) {
const rootAXNode = await this._page.accessibility.snapshot({
interestingOnly: params.interestingOnly,
root: params.root ? params.root._elementHandle : undefined
});
return {
rootAXNode: rootAXNode || undefined
};
}
async pdf(params, metadata) {
if (!this._page.pdf) throw new Error('PDF generation is only supported for Headless Chromium');
const buffer = await this._page.pdf(params);
return {
pdf: buffer
};
}
async bringToFront(params, metadata) {
await this._page.bringToFront();
}
async startJSCoverage(params, metadata) {
const coverage = this._page.coverage;
await coverage.startJSCoverage(params);
}
async stopJSCoverage(params, metadata) {
const coverage = this._page.coverage;
return await coverage.stopJSCoverage();
}
async startCSSCoverage(params, metadata) {
const coverage = this._page.coverage;
await coverage.startCSSCoverage(params);
}
async stopCSSCoverage(params, metadata) {
const coverage = this._page.coverage;
return await coverage.stopCSSCoverage();
}
_onFrameAttached(frame) {
this._dispatchEvent('frameAttached', {
frame: _frameDispatcher.FrameDispatcher.from(this.parentScope(), frame)
});
}
_onFrameDetached(frame) {
this._dispatchEvent('frameDetached', {
frame: _frameDispatcher.FrameDispatcher.from(this.parentScope(), frame)
});
}
_onDispose() {
// Avoid protocol calls for the closed page.
if (!this._page.isClosedOrClosingOrCrashed()) this._page.setClientRequestInterceptor(undefined).catch(() => {});
}
}
exports.PageDispatcher = PageDispatcher;
class WorkerDispatcher extends _dispatcher.Dispatcher {
static fromNullable(scope, worker) {
if (!worker) return undefined;
const result = (0, _dispatcher.existingDispatcher)(worker);
return result || new WorkerDispatcher(scope, worker);
}
constructor(scope, worker) {
super(scope, worker, 'Worker', {
url: worker.url()
});
this._type_Worker = true;
this.addObjectListener(_page.Worker.Events.Close, () => this._dispatchEvent('close'));
}
async evaluateExpression(params, metadata) {
return {
value: (0, _jsHandleDispatcher.serializeResult)(await this._object.evaluateExpression(params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
async evaluateExpressionHandle(params, metadata) {
return {
handle: _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(this, await this._object.evaluateExpressionHandle(params.expression, params.isFunction, (0, _jsHandleDispatcher.parseArgument)(params.arg)))
};
}
}
exports.WorkerDispatcher = WorkerDispatcher;
class BindingCallDispatcher extends _dispatcher.Dispatcher {
constructor(scope, name, needsHandle, source, args) {
super(scope, {
guid: 'bindingCall@' + (0, _utils.createGuid)()
}, 'BindingCall', {
frame: _frameDispatcher.FrameDispatcher.from(scope.parentScope(), source.frame),
name,
args: needsHandle ? undefined : args.map(_jsHandleDispatcher.serializeResult),
handle: needsHandle ? _elementHandlerDispatcher.ElementHandleDispatcher.fromJSHandle(scope, args[0]) : undefined
});
this._type_BindingCall = true;
this._resolve = void 0;
this._reject = void 0;
this._promise = void 0;
this._promise = new Promise((resolve, reject) => {
this._resolve = resolve;
this._reject = reject;
});
}
promise() {
return this._promise;
}
async resolve(params, metadata) {
this._resolve((0, _jsHandleDispatcher.parseArgument)(params.result));
this._dispose();
}
async reject(params, metadata) {
this._reject((0, _errors.parseError)(params.error));
this._dispose();
}
}
exports.BindingCallDispatcher = BindingCallDispatcher;

View File

@@ -0,0 +1,107 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.PlaywrightDispatcher = void 0;
var _fetch = require("../fetch");
var _socksProxy = require("../../common/socksProxy");
var _androidDispatcher = require("./androidDispatcher");
var _browserTypeDispatcher = require("./browserTypeDispatcher");
var _dispatcher = require("./dispatcher");
var _electronDispatcher = require("./electronDispatcher");
var _localUtilsDispatcher = require("./localUtilsDispatcher");
var _networkDispatchers = require("./networkDispatchers");
var _selectorsDispatcher = require("./selectorsDispatcher");
var _browserDispatcher = require("./browserDispatcher");
var _utils = require("../../utils");
var _eventsHelper = require("../../utils/eventsHelper");
/**
* 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.
*/
class PlaywrightDispatcher extends _dispatcher.Dispatcher {
constructor(scope, playwright, socksProxy, preLaunchedBrowser, prelaunchedAndroidDevice) {
const browserDispatcher = preLaunchedBrowser ? new _browserDispatcher.ConnectedBrowserDispatcher(scope, preLaunchedBrowser) : undefined;
const android = new _androidDispatcher.AndroidDispatcher(scope, playwright.android);
const prelaunchedAndroidDeviceDispatcher = prelaunchedAndroidDevice ? new _androidDispatcher.AndroidDeviceDispatcher(android, prelaunchedAndroidDevice) : undefined;
super(scope, playwright, 'Playwright', {
chromium: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.chromium),
firefox: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.firefox),
webkit: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.webkit),
bidiChromium: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiChromium),
bidiFirefox: new _browserTypeDispatcher.BrowserTypeDispatcher(scope, playwright.bidiFirefox),
android,
electron: new _electronDispatcher.ElectronDispatcher(scope, playwright.electron),
utils: playwright.options.isServer ? undefined : new _localUtilsDispatcher.LocalUtilsDispatcher(scope, playwright),
selectors: new _selectorsDispatcher.SelectorsDispatcher(scope, (browserDispatcher === null || browserDispatcher === void 0 ? void 0 : browserDispatcher.selectors) || playwright.selectors),
preLaunchedBrowser: browserDispatcher,
preConnectedAndroidDevice: prelaunchedAndroidDeviceDispatcher,
socksSupport: socksProxy ? new SocksSupportDispatcher(scope, socksProxy) : undefined
});
this._type_Playwright = void 0;
this._browserDispatcher = void 0;
this._type_Playwright = true;
this._browserDispatcher = browserDispatcher;
}
async newRequest(params) {
const request = new _fetch.GlobalAPIRequestContext(this._object, params);
return {
request: _networkDispatchers.APIRequestContextDispatcher.from(this.parentScope(), request)
};
}
async cleanup() {
var _this$_browserDispatc;
// Cleanup contexts upon disconnect.
await ((_this$_browserDispatc = this._browserDispatcher) === null || _this$_browserDispatc === void 0 ? void 0 : _this$_browserDispatc.cleanupContexts());
}
}
exports.PlaywrightDispatcher = PlaywrightDispatcher;
class SocksSupportDispatcher extends _dispatcher.Dispatcher {
constructor(scope, socksProxy) {
super(scope, {
guid: 'socksSupport@' + (0, _utils.createGuid)()
}, 'SocksSupport', {});
this._type_SocksSupport = void 0;
this._socksProxy = void 0;
this._socksListeners = void 0;
this._type_SocksSupport = true;
this._socksProxy = socksProxy;
this._socksListeners = [_eventsHelper.eventsHelper.addEventListener(socksProxy, _socksProxy.SocksProxy.Events.SocksRequested, payload => this._dispatchEvent('socksRequested', payload)), _eventsHelper.eventsHelper.addEventListener(socksProxy, _socksProxy.SocksProxy.Events.SocksData, payload => this._dispatchEvent('socksData', payload)), _eventsHelper.eventsHelper.addEventListener(socksProxy, _socksProxy.SocksProxy.Events.SocksClosed, payload => this._dispatchEvent('socksClosed', payload))];
}
async socksConnected(params) {
var _this$_socksProxy;
(_this$_socksProxy = this._socksProxy) === null || _this$_socksProxy === void 0 || _this$_socksProxy.socketConnected(params);
}
async socksFailed(params) {
var _this$_socksProxy2;
(_this$_socksProxy2 = this._socksProxy) === null || _this$_socksProxy2 === void 0 || _this$_socksProxy2.socketFailed(params);
}
async socksData(params) {
var _this$_socksProxy3;
(_this$_socksProxy3 = this._socksProxy) === null || _this$_socksProxy3 === void 0 || _this$_socksProxy3.sendSocketData(params);
}
async socksError(params) {
var _this$_socksProxy4;
(_this$_socksProxy4 = this._socksProxy) === null || _this$_socksProxy4 === void 0 || _this$_socksProxy4.sendSocketError(params);
}
async socksEnd(params) {
var _this$_socksProxy5;
(_this$_socksProxy5 = this._socksProxy) === null || _this$_socksProxy5 === void 0 || _this$_socksProxy5.sendSocketEnd(params);
}
_onDispose() {
_eventsHelper.eventsHelper.removeEventListeners(this._socksListeners);
}
}

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SelectorsDispatcher = void 0;
var _dispatcher = require("./dispatcher");
/**
* 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.
*/
class SelectorsDispatcher extends _dispatcher.Dispatcher {
constructor(scope, selectors) {
super(scope, selectors, 'Selectors', {});
this._type_Selectors = true;
}
async register(params) {
await this._object.register(params.name, params.source, params.contentScript);
}
async setTestIdAttributeName(params) {
this._object.setTestIdAttributeName(params.testIdAttributeName);
}
}
exports.SelectorsDispatcher = SelectorsDispatcher;

View File

@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.StreamDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var _utils = require("../../utils");
/**
* 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.
*/
class StreamDispatcher extends _dispatcher.Dispatcher {
constructor(scope, stream) {
super(scope, {
guid: 'stream@' + (0, _utils.createGuid)(),
stream
}, 'Stream', {});
// In Node v12.9.0+ we can use readableEnded.
this._type_Stream = true;
this._ended = false;
stream.once('end', () => this._ended = true);
stream.once('error', () => this._ended = true);
}
async read(params) {
const stream = this._object.stream;
if (this._ended) return {
binary: Buffer.from('')
};
if (!stream.readableLength) {
const readyPromise = new _utils.ManualPromise();
const done = () => readyPromise.resolve();
stream.on('readable', done);
stream.on('end', done);
stream.on('error', done);
await readyPromise;
stream.off('readable', done);
stream.off('end', done);
stream.off('error', done);
}
const buffer = stream.read(Math.min(stream.readableLength, params.size || stream.readableLength));
return {
binary: buffer || Buffer.from('')
};
}
async close() {
this._object.stream.destroy();
}
}
exports.StreamDispatcher = StreamDispatcher;

View File

@@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.TracingDispatcher = void 0;
var _artifactDispatcher = require("./artifactDispatcher");
var _dispatcher = require("./dispatcher");
/**
* 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.
*/
class TracingDispatcher extends _dispatcher.Dispatcher {
static from(scope, tracing) {
const result = (0, _dispatcher.existingDispatcher)(tracing);
return result || new TracingDispatcher(scope, tracing);
}
constructor(scope, tracing) {
super(scope, tracing, 'Tracing', {});
this._type_Tracing = true;
}
async tracingStart(params) {
await this._object.start(params);
}
async tracingStartChunk(params) {
return await this._object.startChunk(params);
}
async tracingGroup(params, metadata) {
const {
name,
location
} = params;
await this._object.group(name, location, metadata);
}
async tracingGroupEnd(params) {
await this._object.groupEnd();
}
async tracingStopChunk(params) {
const {
artifact,
entries
} = await this._object.stopChunk(params);
return {
artifact: artifact ? _artifactDispatcher.ArtifactDispatcher.from(this, artifact) : undefined,
entries
};
}
async tracingStop(params) {
await this._object.stop();
}
}
exports.TracingDispatcher = TracingDispatcher;

View File

@@ -0,0 +1,189 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebSocketRouteDispatcher = void 0;
var _page = require("../page");
var _dispatcher = require("./dispatcher");
var _utils = require("../../utils");
var _pageDispatcher = require("./pageDispatcher");
var webSocketMockSource = _interopRequireWildcard(require("../../generated/webSocketMockSource"));
var _eventsHelper = require("../../utils/eventsHelper");
var _class;
/**
* 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.
*/
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
const kBindingInstalledSymbol = Symbol('webSocketRouteBindingInstalled');
const kInitScriptInstalledSymbol = Symbol('webSocketRouteInitScriptInstalled');
class WebSocketRouteDispatcher extends _dispatcher.Dispatcher {
constructor(scope, id, url, frame) {
super(scope, {
guid: 'webSocketRoute@' + (0, _utils.createGuid)()
}, 'WebSocketRoute', {
url
});
this._type_WebSocketRoute = true;
this._id = void 0;
this._frame = void 0;
this._id = id;
this._frame = frame;
this._eventListeners.push(
// When the frame navigates or detaches, there will be no more communication
// from the mock websocket, so pretend like it was closed.
_eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.InternalFrameNavigatedToNewDocument, frame => {
if (frame === this._frame) this._executionContextGone();
}), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.FrameDetached, frame => {
if (frame === this._frame) this._executionContextGone();
}), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.Close, () => this._executionContextGone()), _eventsHelper.eventsHelper.addEventListener(frame._page, _page.Page.Events.Crash, () => this._executionContextGone()));
WebSocketRouteDispatcher._idToDispatcher.set(this._id, this);
scope._dispatchEvent('webSocketRoute', {
webSocketRoute: this
});
}
static async installIfNeeded(contextDispatcher, target) {
const context = target instanceof _page.Page ? target.context() : target;
if (!context[kBindingInstalledSymbol]) {
context[kBindingInstalledSymbol] = true;
await context.exposeBinding('__pwWebSocketBinding', false, (source, payload) => {
if (payload.type === 'onCreate') {
const pageDispatcher = _pageDispatcher.PageDispatcher.fromNullable(contextDispatcher, source.page);
let scope;
if (pageDispatcher && matchesPattern(pageDispatcher, context._options.baseURL, payload.url)) scope = pageDispatcher;else if (matchesPattern(contextDispatcher, context._options.baseURL, payload.url)) scope = contextDispatcher;
if (scope) {
new WebSocketRouteDispatcher(scope, payload.id, payload.url, source.frame);
} else {
const request = {
id: payload.id,
type: 'passthrough'
};
source.frame.evaluateExpression(`globalThis.__pwWebSocketDispatch(${JSON.stringify(request)})`).catch(() => {});
}
return;
}
const dispatcher = WebSocketRouteDispatcher._idToDispatcher.get(payload.id);
if (payload.type === 'onMessageFromPage') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('messageFromPage', {
message: payload.data.data,
isBase64: payload.data.isBase64
});
if (payload.type === 'onMessageFromServer') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('messageFromServer', {
message: payload.data.data,
isBase64: payload.data.isBase64
});
if (payload.type === 'onClosePage') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('closePage', {
code: payload.code,
reason: payload.reason,
wasClean: payload.wasClean
});
if (payload.type === 'onCloseServer') dispatcher === null || dispatcher === void 0 || dispatcher._dispatchEvent('closeServer', {
code: payload.code,
reason: payload.reason,
wasClean: payload.wasClean
});
});
}
if (!target[kInitScriptInstalledSymbol]) {
target[kInitScriptInstalledSymbol] = true;
await target.addInitScript(`
(() => {
const module = {};
${webSocketMockSource.source}
(module.exports.inject())(globalThis);
})();
`);
}
}
async connect(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'connect'
});
}
async ensureOpened(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'ensureOpened'
});
}
async sendToPage(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'sendToPage',
data: {
data: params.message,
isBase64: params.isBase64
}
});
}
async sendToServer(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'sendToServer',
data: {
data: params.message,
isBase64: params.isBase64
}
});
}
async closePage(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'closePage',
code: params.code,
reason: params.reason,
wasClean: params.wasClean
});
}
async closeServer(params) {
await this._evaluateAPIRequest({
id: this._id,
type: 'closeServer',
code: params.code,
reason: params.reason,
wasClean: params.wasClean
});
}
async _evaluateAPIRequest(request) {
await this._frame.evaluateExpression(`globalThis.__pwWebSocketDispatch(${JSON.stringify(request)})`).catch(() => {});
}
_onDispose() {
WebSocketRouteDispatcher._idToDispatcher.delete(this._id);
}
_executionContextGone() {
// We could enter here after being disposed upon page closure:
// - first from the recursive dispose inintiated by PageDispatcher;
// - then from our own page.on('close') listener.
if (!this._disposed) {
this._dispatchEvent('closePage', {
wasClean: true
});
this._dispatchEvent('closeServer', {
wasClean: true
});
}
}
}
exports.WebSocketRouteDispatcher = WebSocketRouteDispatcher;
_class = WebSocketRouteDispatcher;
WebSocketRouteDispatcher._idToDispatcher = new Map();
function matchesPattern(dispatcher, baseURL, url) {
for (const pattern of dispatcher._webSocketInterceptionPatterns || []) {
const urlMatch = pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags) : pattern.glob;
if ((0, _utils.urlMatches)(baseURL, url, urlMatch)) return true;
}
return false;
}

View File

@@ -0,0 +1,58 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WritableStreamDispatcher = void 0;
var _dispatcher = require("./dispatcher");
var fs = _interopRequireWildcard(require("fs"));
var _utils = require("../../utils");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
/**
* 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.
*/
class WritableStreamDispatcher extends _dispatcher.Dispatcher {
constructor(scope, streamOrDirectory, lastModifiedMs) {
super(scope, {
guid: 'writableStream@' + (0, _utils.createGuid)(),
streamOrDirectory
}, 'WritableStream', {});
this._type_WritableStream = true;
this._lastModifiedMs = void 0;
this._lastModifiedMs = lastModifiedMs;
}
async write(params) {
if (typeof this._object.streamOrDirectory === 'string') throw new Error('Cannot write to a directory');
const stream = this._object.streamOrDirectory;
await new Promise((fulfill, reject) => {
stream.write(params.binary, error => {
if (error) reject(error);else fulfill();
});
});
}
async close() {
if (typeof this._object.streamOrDirectory === 'string') throw new Error('Cannot close a directory');
const stream = this._object.streamOrDirectory;
await new Promise(fulfill => stream.end(fulfill));
if (this._lastModifiedMs) await fs.promises.utimes(this.path(), new Date(this._lastModifiedMs), new Date(this._lastModifiedMs));
}
path() {
if (typeof this._object.streamOrDirectory === 'string') return this._object.streamOrDirectory;
return this._object.streamOrDirectory.path;
}
}
exports.WritableStreamDispatcher = WritableStreamDispatcher;