screenshot/test_1

This commit is contained in:
ramkumarp
2025-03-27 11:21:02 +00:00
commit 616d466383
470 changed files with 144705 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WebKit = void 0;
var _path = _interopRequireDefault(require("path"));
var _wkConnection = require("./wkConnection");
var _ascii = require("../utils/ascii");
var _browserType = require("../browserType");
var _wkBrowser = require("../webkit/wkBrowser");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
/**
* Copyright 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class WebKit extends _browserType.BrowserType {
constructor(parent) {
super(parent, 'webkit');
}
connectToTransport(transport, options) {
return _wkBrowser.WKBrowser.connect(this.attribution.playwright, transport, options);
}
amendEnvironment(env, userDataDir, executable, browserArguments) {
return {
...env,
CURL_COOKIE_JAR_PATH: _path.default.join(userDataDir, 'cookiejar.db')
};
}
doRewriteStartupLog(error) {
if (!error.logs) return error;
if (error.logs.includes('Failed to open display') || error.logs.includes('cannot open display')) error.logs = '\n' + (0, _ascii.wrapInASCIIBox)(_browserType.kNoXServerRunningError, 1);
return error;
}
attemptToGracefullyCloseBrowser(transport) {
transport.send({
method: 'Playwright.close',
params: {},
id: _wkConnection.kBrowserCloseMessageId
});
}
defaultArgs(options, isPersistent, userDataDir) {
const {
args = [],
headless
} = options;
const userDataDirArg = args.find(arg => arg.startsWith('--user-data-dir'));
if (userDataDirArg) throw this._createUserDataDirArgMisuseError('--user-data-dir');
if (args.find(arg => !arg.startsWith('-'))) throw new Error('Arguments can not specify page to be opened');
const webkitArguments = ['--inspector-pipe'];
if (process.platform === 'win32') webkitArguments.push('--disable-accelerated-compositing');
if (headless) webkitArguments.push('--headless');
if (isPersistent) webkitArguments.push(`--user-data-dir=${userDataDir}`);else webkitArguments.push(`--no-startup-window`);
const proxy = options.proxyOverride || options.proxy;
if (proxy) {
if (process.platform === 'darwin') {
webkitArguments.push(`--proxy=${proxy.server}`);
if (proxy.bypass) webkitArguments.push(`--proxy-bypass-list=${proxy.bypass}`);
} else if (process.platform === 'linux') {
webkitArguments.push(`--proxy=${proxy.server}`);
if (proxy.bypass) webkitArguments.push(...proxy.bypass.split(',').map(t => `--ignore-host=${t}`));
} else if (process.platform === 'win32') {
// Enable socks5 hostname resolution on Windows. Workaround can be removed once fixed upstream.
// See https://github.com/microsoft/playwright/issues/20451
webkitArguments.push(`--curl-proxy=${proxy.server.replace(/^socks5:\/\//, 'socks5h://')}`);
if (proxy.bypass) webkitArguments.push(`--curl-noproxy=${proxy.bypass}`);
}
}
webkitArguments.push(...args);
if (isPersistent) webkitArguments.push('about:blank');
return webkitArguments;
}
}
exports.WebKit = WebKit;

View File

@@ -0,0 +1,194 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getAccessibilityTree = getAccessibilityTree;
/**
* 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.
*/
async function getAccessibilityTree(session, needle) {
const objectId = needle ? needle._objectId : undefined;
const {
axNode
} = await session.send('Page.accessibilitySnapshot', {
objectId
});
const tree = new WKAXNode(axNode);
return {
tree,
needle: needle ? tree._findNeedle() : null
};
}
const WKRoleToARIARole = new Map(Object.entries({
'TextField': 'textbox'
}));
// WebKit localizes role descriptions on mac, but the english versions only add noise.
const WKUnhelpfulRoleDescriptions = new Map(Object.entries({
'WebArea': 'HTML content',
'Summary': 'summary',
'DescriptionList': 'description list',
'ImageMap': 'image map',
'ListMarker': 'list marker',
'Video': 'video playback',
'Mark': 'highlighted',
'contentinfo': 'content information',
'Details': 'details',
'DescriptionListDetail': 'description',
'DescriptionListTerm': 'term',
'alertdialog': 'web alert dialog',
'dialog': 'web dialog',
'status': 'application status',
'tabpanel': 'tab panel',
'application': 'web application'
}));
class WKAXNode {
constructor(payload) {
this._payload = void 0;
this._children = void 0;
this._payload = payload;
this._children = [];
for (const payload of this._payload.children || []) this._children.push(new WKAXNode(payload));
}
children() {
return this._children;
}
_findNeedle() {
if (this._payload.found) return this;
for (const child of this._children) {
const found = child._findNeedle();
if (found) return found;
}
return null;
}
isControl() {
switch (this._payload.role) {
case 'button':
case 'checkbox':
case 'ColorWell':
case 'combobox':
case 'DisclosureTriangle':
case 'listbox':
case 'menu':
case 'menubar':
case 'menuitem':
case 'menuitemcheckbox':
case 'menuitemradio':
case 'radio':
case 'scrollbar':
case 'searchbox':
case 'slider':
case 'spinbutton':
case 'switch':
case 'tab':
case 'textbox':
case 'TextField':
case 'tree':
return true;
default:
return false;
}
}
_isTextControl() {
switch (this._payload.role) {
case 'combobox':
case 'searchfield':
case 'textbox':
case 'TextField':
return true;
}
return false;
}
_name() {
if (this._payload.role === 'text') return this._payload.value || '';
return this._payload.name || '';
}
isInteresting(insideControl) {
const {
role,
focusable
} = this._payload;
const name = this._name();
if (role === 'ScrollArea') return false;
if (role === 'WebArea') return true;
if (focusable || role === 'MenuListOption') return true;
// If it's not focusable but has a control role, then it's interesting.
if (this.isControl()) return true;
// A non focusable child of a control is not interesting
if (insideControl) return false;
return this.isLeafNode() && !!name;
}
_hasRedundantTextChild() {
if (this._children.length !== 1) return false;
const child = this._children[0];
return child._payload.role === 'text' && this._payload.name === child._payload.value;
}
isLeafNode() {
if (!this._children.length) return true;
// WebKit on Linux ignores everything inside text controls, normalize this behavior
if (this._isTextControl()) return true;
// WebKit for mac has text nodes inside heading, li, menuitem, a, and p nodes
if (this._hasRedundantTextChild()) return true;
return false;
}
serialize() {
const node = {
role: WKRoleToARIARole.get(this._payload.role) || this._payload.role,
name: this._name()
};
if ('description' in this._payload && this._payload.description !== node.name) node.description = this._payload.description;
if ('roledescription' in this._payload) {
const roledescription = this._payload.roledescription;
if (roledescription !== this._payload.role && WKUnhelpfulRoleDescriptions.get(this._payload.role) !== roledescription) node.roledescription = roledescription;
}
if ('value' in this._payload && this._payload.role !== 'text') {
if (typeof this._payload.value === 'string') node.valueString = this._payload.value;else if (typeof this._payload.value === 'number') node.valueNumber = this._payload.value;
}
if ('checked' in this._payload) node.checked = this._payload.checked === 'true' ? 'checked' : this._payload.checked === 'false' ? 'unchecked' : 'mixed';
if ('pressed' in this._payload) node.pressed = this._payload.pressed === 'true' ? 'pressed' : this._payload.pressed === 'false' ? 'released' : 'mixed';
const userStringProperties = ['keyshortcuts', 'valuetext'];
for (const userStringProperty of userStringProperties) {
if (!(userStringProperty in this._payload)) continue;
node[userStringProperty] = this._payload[userStringProperty];
}
const booleanProperties = ['disabled', 'expanded', 'focused', 'modal', 'multiselectable', 'readonly', 'required', 'selected'];
for (const booleanProperty of booleanProperties) {
// WebArea and ScrollArea treat focus differently than other nodes. They report whether their frame has focus,
// not whether focus is specifically on the root node.
if (booleanProperty === 'focused' && (this._payload.role === 'WebArea' || this._payload.role === 'ScrollArea')) continue;
const value = this._payload[booleanProperty];
if (!value) continue;
node[booleanProperty] = value;
}
const numericalProperties = ['level', 'valuemax', 'valuemin'];
for (const numericalProperty of numericalProperties) {
if (!(numericalProperty in this._payload)) continue;
node[numericalProperty] = this._payload[numericalProperty];
}
const tokenProperties = ['autocomplete', 'haspopup', 'invalid'];
for (const tokenProperty of tokenProperties) {
const value = this._payload[tokenProperty];
if (!value || value === 'false') continue;
node[tokenProperty] = value;
}
const orientationIsApplicable = new Set(['ScrollArea', 'scrollbar', 'listbox', 'combobox', 'menu', 'tree', 'separator', 'slider', 'tablist', 'toolbar']);
if (this._payload.orientation && orientationIsApplicable.has(this._payload.role)) node.orientation = this._payload.orientation;
return node;
}
}

View File

@@ -0,0 +1,329 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WKBrowserContext = exports.WKBrowser = void 0;
var _utils = require("../../utils");
var _browser = require("../browser");
var _browserContext = require("../browserContext");
var network = _interopRequireWildcard(require("../network"));
var _wkConnection = require("./wkConnection");
var _wkPage = require("./wkPage");
var _errors = require("../errors");
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 && {}.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 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const DEFAULT_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15';
const BROWSER_VERSION = '18.4';
class WKBrowser extends _browser.Browser {
static async connect(parent, transport, options) {
const browser = new WKBrowser(parent, transport, options);
if (options.__testHookOnConnectToBrowser) await options.__testHookOnConnectToBrowser();
const promises = [browser._browserSession.send('Playwright.enable')];
if (options.persistent) {
var _options$persistent;
(_options$persistent = options.persistent).userAgent || (_options$persistent.userAgent = DEFAULT_USER_AGENT);
browser._defaultContext = new WKBrowserContext(browser, undefined, options.persistent);
promises.push(browser._defaultContext._initialize());
}
await Promise.all(promises);
return browser;
}
constructor(parent, transport, options) {
super(parent, options);
this._connection = void 0;
this._browserSession = void 0;
this._contexts = new Map();
this._wkPages = new Map();
this._connection = new _wkConnection.WKConnection(transport, this._onDisconnect.bind(this), options.protocolLogger, options.browserLogsCollector);
this._browserSession = this._connection.browserSession;
this._browserSession.on('Playwright.pageProxyCreated', this._onPageProxyCreated.bind(this));
this._browserSession.on('Playwright.pageProxyDestroyed', this._onPageProxyDestroyed.bind(this));
this._browserSession.on('Playwright.provisionalLoadFailed', event => this._onProvisionalLoadFailed(event));
this._browserSession.on('Playwright.windowOpen', event => this._onWindowOpen(event));
this._browserSession.on('Playwright.downloadCreated', this._onDownloadCreated.bind(this));
this._browserSession.on('Playwright.downloadFilenameSuggested', this._onDownloadFilenameSuggested.bind(this));
this._browserSession.on('Playwright.downloadFinished', this._onDownloadFinished.bind(this));
this._browserSession.on('Playwright.screencastFinished', this._onScreencastFinished.bind(this));
this._browserSession.on(_wkConnection.kPageProxyMessageReceived, this._onPageProxyMessageReceived.bind(this));
}
_onDisconnect() {
for (const wkPage of this._wkPages.values()) wkPage.didClose();
this._wkPages.clear();
for (const video of this._idToVideo.values()) video.artifact.reportFinished(new _errors.TargetClosedError());
this._idToVideo.clear();
this._didClose();
}
async doCreateNewContext(options) {
const proxy = options.proxyOverride || options.proxy;
const createOptions = proxy ? {
// Enable socks5 hostname resolution on Windows.
// See https://github.com/microsoft/playwright/issues/20451
proxyServer: process.platform === 'win32' ? proxy.server.replace(/^socks5:\/\//, 'socks5h://') : proxy.server,
proxyBypassList: proxy.bypass
} : undefined;
const {
browserContextId
} = await this._browserSession.send('Playwright.createContext', createOptions);
options.userAgent = options.userAgent || DEFAULT_USER_AGENT;
const context = new WKBrowserContext(this, browserContextId, options);
await context._initialize();
this._contexts.set(browserContextId, context);
return context;
}
contexts() {
return Array.from(this._contexts.values());
}
version() {
return BROWSER_VERSION;
}
userAgent() {
return DEFAULT_USER_AGENT;
}
_onDownloadCreated(payload) {
const page = this._wkPages.get(payload.pageProxyId);
if (!page) return;
// In some cases, e.g. blob url download, we receive only frameScheduledNavigation
// but no signals that the navigation was canceled and replaced by download. Fix it
// here by simulating cancelled provisional load which matches downloads from network.
//
// TODO: this is racy, because download might be unrelated any navigation, and we will
// abort navigation that is still running. We should be able to fix this by
// instrumenting policy decision start/proceed/cancel.
page._page._frameManager.frameAbortedNavigation(payload.frameId, 'Download is starting');
let originPage = page._page.initializedOrUndefined();
// If it's a new window download, report it on the opener page.
if (!originPage) {
// Resume the page creation with an error. The page will automatically close right
// after the download begins.
page._firstNonInitialNavigationCommittedReject(new Error('Starting new page download'));
if (page._opener) originPage = page._opener._page.initializedOrUndefined();
}
if (!originPage) return;
this._downloadCreated(originPage, payload.uuid, payload.url);
}
_onDownloadFilenameSuggested(payload) {
this._downloadFilenameSuggested(payload.uuid, payload.suggestedFilename);
}
_onDownloadFinished(payload) {
this._downloadFinished(payload.uuid, payload.error);
}
_onScreencastFinished(payload) {
var _this$_takeVideo;
(_this$_takeVideo = this._takeVideo(payload.screencastId)) === null || _this$_takeVideo === void 0 || _this$_takeVideo.reportFinished();
}
_onPageProxyCreated(event) {
const pageProxyId = event.pageProxyId;
let context = null;
if (event.browserContextId) {
// FIXME: we don't know about the default context id, so assume that all targets from
// unknown contexts are created in the 'default' context which can in practice be represented
// by multiple actual contexts in WebKit. Solving this properly will require adding context
// lifecycle events.
context = this._contexts.get(event.browserContextId) || null;
}
if (!context) context = this._defaultContext;
if (!context) return;
const pageProxySession = new _wkConnection.WKSession(this._connection, pageProxyId, message => {
this._connection.rawSend({
...message,
pageProxyId
});
});
const opener = event.openerId ? this._wkPages.get(event.openerId) : undefined;
const wkPage = new _wkPage.WKPage(context, pageProxySession, opener || null);
this._wkPages.set(pageProxyId, wkPage);
}
_onPageProxyDestroyed(event) {
const pageProxyId = event.pageProxyId;
const wkPage = this._wkPages.get(pageProxyId);
if (!wkPage) return;
wkPage.didClose();
this._wkPages.delete(pageProxyId);
}
_onPageProxyMessageReceived(event) {
const wkPage = this._wkPages.get(event.pageProxyId);
if (!wkPage) return;
wkPage.dispatchMessageToSession(event.message);
}
_onProvisionalLoadFailed(event) {
const wkPage = this._wkPages.get(event.pageProxyId);
if (!wkPage) return;
wkPage.handleProvisionalLoadFailed(event);
}
_onWindowOpen(event) {
const wkPage = this._wkPages.get(event.pageProxyId);
if (!wkPage) return;
wkPage.handleWindowOpen(event);
}
isConnected() {
return !this._connection.isClosed();
}
}
exports.WKBrowser = WKBrowser;
class WKBrowserContext extends _browserContext.BrowserContext {
constructor(browser, browserContextId, options) {
super(browser, options, browserContextId);
this._validateEmulatedViewport(options.viewport);
this._authenticateProxyViaHeader();
}
async _initialize() {
(0, _utils.assert)(!this._wkPages().length);
const browserContextId = this._browserContextId;
const promises = [super._initialize()];
promises.push(this._browser._browserSession.send('Playwright.setDownloadBehavior', {
behavior: this._options.acceptDownloads === 'accept' ? 'allow' : 'deny',
downloadPath: this._browser.options.downloadsPath,
browserContextId
}));
if (this._options.ignoreHTTPSErrors || this._options.internalIgnoreHTTPSErrors) promises.push(this._browser._browserSession.send('Playwright.setIgnoreCertificateErrors', {
browserContextId,
ignore: true
}));
if (this._options.locale) promises.push(this._browser._browserSession.send('Playwright.setLanguages', {
browserContextId,
languages: [this._options.locale]
}));
if (this._options.geolocation) promises.push(this.setGeolocation(this._options.geolocation));
if (this._options.offline) promises.push(this.setOffline(this._options.offline));
if (this._options.httpCredentials) promises.push(this.setHTTPCredentials(this._options.httpCredentials));
await Promise.all(promises);
}
_wkPages() {
return Array.from(this._browser._wkPages.values()).filter(wkPage => wkPage._browserContext === this);
}
possiblyUninitializedPages() {
return this._wkPages().map(wkPage => wkPage._page);
}
async doCreateNewPage() {
(0, _browserContext.assertBrowserContextIsNotOwned)(this);
const {
pageProxyId
} = await this._browser._browserSession.send('Playwright.createPage', {
browserContextId: this._browserContextId
});
return this._browser._wkPages.get(pageProxyId)._page;
}
async doGetCookies(urls) {
const {
cookies
} = await this._browser._browserSession.send('Playwright.getAllCookies', {
browserContextId: this._browserContextId
});
return network.filterCookies(cookies.map(c => {
const copy = {
...c
};
copy.expires = c.expires === -1 ? -1 : c.expires / 1000;
delete copy.session;
return copy;
}), urls);
}
async addCookies(cookies) {
const cc = network.rewriteCookies(cookies).map(c => ({
...c,
session: c.expires === -1 || c.expires === undefined,
expires: c.expires && c.expires !== -1 ? c.expires * 1000 : c.expires
}));
await this._browser._browserSession.send('Playwright.setCookies', {
cookies: cc,
browserContextId: this._browserContextId
});
}
async doClearCookies() {
await this._browser._browserSession.send('Playwright.deleteAllCookies', {
browserContextId: this._browserContextId
});
}
async doGrantPermissions(origin, permissions) {
await Promise.all(this.pages().map(page => page._delegate._grantPermissions(origin, permissions)));
}
async doClearPermissions() {
await Promise.all(this.pages().map(page => page._delegate._clearPermissions()));
}
async setGeolocation(geolocation) {
(0, _browserContext.verifyGeolocation)(geolocation);
this._options.geolocation = geolocation;
const payload = geolocation ? {
...geolocation,
timestamp: Date.now()
} : undefined;
await this._browser._browserSession.send('Playwright.setGeolocationOverride', {
browserContextId: this._browserContextId,
geolocation: payload
});
}
async setExtraHTTPHeaders(headers) {
this._options.extraHTTPHeaders = headers;
for (const page of this.pages()) await page._delegate.updateExtraHTTPHeaders();
}
async setUserAgent(userAgent) {
this._options.userAgent = userAgent;
for (const page of this.pages()) await page._delegate.updateUserAgent();
}
async setOffline(offline) {
this._options.offline = offline;
for (const page of this.pages()) await page._delegate.updateOffline();
}
async doSetHTTPCredentials(httpCredentials) {
this._options.httpCredentials = httpCredentials;
for (const page of this.pages()) await page._delegate.updateHttpCredentials();
}
async doAddInitScript(initScript) {
for (const page of this.pages()) await page._delegate._updateBootstrapScript();
}
async doRemoveNonInternalInitScripts() {
for (const page of this.pages()) await page._delegate._updateBootstrapScript();
}
async doUpdateRequestInterception() {
for (const page of this.pages()) await page._delegate.updateRequestInterception();
}
onClosePersistent() {}
async clearCache() {
// We use ephemeral contexts so there is no disk cache.
await this._browser._browserSession.send('Playwright.clearMemoryCache', {
browserContextId: this._browserContextId
});
}
async doClose(reason) {
if (!this._browserContextId) {
await Promise.all(this._wkPages().map(wkPage => wkPage._stopVideo()));
// Closing persistent context should close the browser.
await this._browser.close({
reason
});
} else {
await this._browser._browserSession.send('Playwright.deleteContext', {
browserContextId: this._browserContextId
});
this._browser._contexts.delete(this._browserContextId);
}
}
async cancelDownload(uuid) {
await this._browser._browserSession.send('Playwright.cancelDownload', {
uuid
});
}
_validateEmulatedViewport(viewportSize) {
if (!viewportSize) return;
if (process.platform === 'win32' && this._browser.options.headful && (viewportSize.width < 250 || viewportSize.height < 240)) throw new Error(`WebKit on Windows has a minimal viewport of 250x240.`);
}
}
exports.WKBrowserContext = WKBrowserContext;

View File

@@ -0,0 +1,173 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.kPageProxyMessageReceived = exports.kBrowserCloseMessageId = exports.WKSession = exports.WKConnection = void 0;
var _events = require("events");
var _utils = require("../../utils");
var _debugLogger = require("../utils/debugLogger");
var _helper = require("../helper");
var _protocolError = require("../protocolError");
/**
* Copyright 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// WKPlaywright uses this special id to issue Browser.close command which we
// should ignore.
const kBrowserCloseMessageId = exports.kBrowserCloseMessageId = -9999;
// We emulate kPageProxyMessageReceived message to unify it with Browser.pageProxyCreated
// and Browser.pageProxyDestroyed for easier management.
const kPageProxyMessageReceived = exports.kPageProxyMessageReceived = Symbol('kPageProxyMessageReceived');
class WKConnection {
constructor(transport, onDisconnect, protocolLogger, browserLogsCollector) {
this._transport = void 0;
this._onDisconnect = void 0;
this._protocolLogger = void 0;
this._browserLogsCollector = void 0;
this._browserDisconnectedLogs = void 0;
this._lastId = 0;
this._closed = false;
this.browserSession = void 0;
this._transport = transport;
this._onDisconnect = onDisconnect;
this._protocolLogger = protocolLogger;
this._browserLogsCollector = browserLogsCollector;
this.browserSession = new WKSession(this, '', message => {
this.rawSend(message);
});
this._transport.onmessage = this._dispatchMessage.bind(this);
// onclose should be set last, since it can be immediately called.
this._transport.onclose = this._onClose.bind(this);
}
nextMessageId() {
return ++this._lastId;
}
rawSend(message) {
this._protocolLogger('send', message);
this._transport.send(message);
}
_dispatchMessage(message) {
this._protocolLogger('receive', message);
if (message.id === kBrowserCloseMessageId) return;
if (message.pageProxyId) {
const payload = {
message: message,
pageProxyId: message.pageProxyId
};
this.browserSession.dispatchMessage({
method: kPageProxyMessageReceived,
params: payload
});
return;
}
this.browserSession.dispatchMessage(message);
}
_onClose(reason) {
this._closed = true;
this._transport.onmessage = undefined;
this._transport.onclose = undefined;
this._browserDisconnectedLogs = _helper.helper.formatBrowserLogs(this._browserLogsCollector.recentLogs(), reason);
this.browserSession.dispose();
this._onDisconnect();
}
isClosed() {
return this._closed;
}
close() {
if (!this._closed) this._transport.close();
}
}
exports.WKConnection = WKConnection;
class WKSession extends _events.EventEmitter {
constructor(connection, sessionId, rawSend) {
super();
this.connection = void 0;
this.sessionId = void 0;
this._disposed = false;
this._rawSend = void 0;
this._callbacks = new Map();
this._crashed = false;
this.on = void 0;
this.addListener = void 0;
this.off = void 0;
this.removeListener = void 0;
this.once = void 0;
this.setMaxListeners(0);
this.connection = connection;
this.sessionId = sessionId;
this._rawSend = rawSend;
this.on = super.on;
this.off = super.removeListener;
this.addListener = super.addListener;
this.removeListener = super.removeListener;
this.once = super.once;
}
async send(method, params) {
if (this._crashed || this._disposed || this.connection._browserDisconnectedLogs) throw new _protocolError.ProtocolError(this._crashed ? 'crashed' : 'closed', undefined, this.connection._browserDisconnectedLogs);
const id = this.connection.nextMessageId();
const messageObj = {
id,
method,
params
};
this._rawSend(messageObj);
return new Promise((resolve, reject) => {
this._callbacks.set(id, {
resolve,
reject,
error: new _protocolError.ProtocolError('error', method)
});
});
}
sendMayFail(method, params) {
return this.send(method, params).catch(error => _debugLogger.debugLogger.log('error', error));
}
markAsCrashed() {
this._crashed = true;
}
isDisposed() {
return this._disposed;
}
dispose() {
for (const callback of this._callbacks.values()) {
callback.error.type = this._crashed ? 'crashed' : 'closed';
callback.error.logs = this.connection._browserDisconnectedLogs;
callback.reject(callback.error);
}
this._callbacks.clear();
this._disposed = true;
}
dispatchMessage(object) {
if (object.id && this._callbacks.has(object.id)) {
const callback = this._callbacks.get(object.id);
this._callbacks.delete(object.id);
if (object.error) {
callback.error.setMessage(object.error.message);
callback.reject(callback.error);
} else {
callback.resolve(object.result);
}
} else if (object.id && !object.error) {
// Response might come after session has been disposed and rejected all callbacks.
(0, _utils.assert)(this.isDisposed());
} else {
Promise.resolve().then(() => this.emit(object.method, object.params));
}
}
}
exports.WKSession = WKSession;

View File

@@ -0,0 +1,139 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WKExecutionContext = void 0;
exports.createHandle = createHandle;
var _utilityScriptSerializers = require("../isomorphic/utilityScriptSerializers");
var js = _interopRequireWildcard(require("../javascript"));
var dom = _interopRequireWildcard(require("../dom"));
var _protocolError = require("../protocolError");
var _assert = require("../../utils/isomorphic/assert");
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 && {}.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 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class WKExecutionContext {
constructor(session, contextId) {
this._session = void 0;
this._contextId = void 0;
this._session = session;
this._contextId = contextId;
}
async rawEvaluateJSON(expression) {
try {
const response = await this._session.send('Runtime.evaluate', {
expression,
contextId: this._contextId,
returnByValue: true
});
if (response.wasThrown) throw new js.JavaScriptErrorInEvaluate(response.result.description);
return response.result.value;
} catch (error) {
throw rewriteError(error);
}
}
async rawEvaluateHandle(context, expression) {
try {
const response = await this._session.send('Runtime.evaluate', {
expression,
contextId: this._contextId,
returnByValue: false
});
if (response.wasThrown) throw new js.JavaScriptErrorInEvaluate(response.result.description);
return createHandle(context, response.result);
} catch (error) {
throw rewriteError(error);
}
}
async evaluateWithArguments(expression, returnByValue, utilityScript, values, handles) {
try {
const response = await this._session.send('Runtime.callFunctionOn', {
functionDeclaration: expression,
objectId: utilityScript._objectId,
arguments: [{
objectId: utilityScript._objectId
}, ...values.map(value => ({
value
})), ...handles.map(handle => ({
objectId: handle._objectId
}))],
returnByValue,
emulateUserGesture: true,
awaitPromise: true
});
if (response.wasThrown) throw new js.JavaScriptErrorInEvaluate(response.result.description);
if (returnByValue) return (0, _utilityScriptSerializers.parseEvaluationResultValue)(response.result.value);
return createHandle(utilityScript._context, response.result);
} catch (error) {
throw rewriteError(error);
}
}
async getProperties(object) {
const response = await this._session.send('Runtime.getProperties', {
objectId: object._objectId,
ownProperties: true
});
const result = new Map();
for (const property of response.properties) {
if (!property.enumerable || !property.value) continue;
result.set(property.name, createHandle(object._context, property.value));
}
return result;
}
async releaseHandle(handle) {
if (!handle._objectId) return;
await this._session.send('Runtime.releaseObject', {
objectId: handle._objectId
});
}
}
exports.WKExecutionContext = WKExecutionContext;
function potentiallyUnserializableValue(remoteObject) {
const value = remoteObject.value;
const isUnserializable = remoteObject.type === 'number' && ['NaN', '-Infinity', 'Infinity', '-0'].includes(remoteObject.description);
return isUnserializable ? js.parseUnserializableValue(remoteObject.description) : value;
}
function rewriteError(error) {
if (error.message.includes('Object has too long reference chain')) throw new Error('Cannot serialize result: object reference chain is too long.');
if (!js.isJavaScriptErrorInEvaluate(error) && !(0, _protocolError.isSessionClosedError)(error)) return new Error('Execution context was destroyed, most likely because of a navigation.');
return error;
}
function renderPreview(object) {
if (object.type === 'undefined') return 'undefined';
if ('value' in object) return String(object.value);
if (object.description === 'Object' && object.preview) {
const tokens = [];
for (const {
name,
value
} of object.preview.properties) tokens.push(`${name}: ${value}`);
return `{${tokens.join(', ')}}`;
}
if (object.subtype === 'array' && object.preview) return js.sparseArrayToString(object.preview.properties);
return object.description;
}
function createHandle(context, remoteObject) {
if (remoteObject.subtype === 'node') {
(0, _assert.assert)(context instanceof dom.FrameExecutionContext);
return new dom.ElementHandle(context, remoteObject.objectId);
}
const isPromise = remoteObject.className === 'Promise';
return new js.JSHandle(context, isPromise ? 'promise' : remoteObject.subtype || remoteObject.type, renderPreview(remoteObject), remoteObject.objectId, potentiallyUnserializableValue(remoteObject));
}

View File

@@ -0,0 +1,179 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.RawTouchscreenImpl = exports.RawMouseImpl = exports.RawKeyboardImpl = void 0;
var _utils = require("../../utils");
var input = _interopRequireWildcard(require("../input"));
var _macEditingCommands = require("../macEditingCommands");
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 && {}.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 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function toModifiersMask(modifiers) {
// From Source/WebKit/Shared/WebEvent.h
let mask = 0;
if (modifiers.has('Shift')) mask |= 1;
if (modifiers.has('Control')) mask |= 2;
if (modifiers.has('Alt')) mask |= 4;
if (modifiers.has('Meta')) mask |= 8;
return mask;
}
function toButtonsMask(buttons) {
let mask = 0;
if (buttons.has('left')) mask |= 1;
if (buttons.has('right')) mask |= 2;
if (buttons.has('middle')) mask |= 4;
return mask;
}
class RawKeyboardImpl {
constructor(session) {
this._pageProxySession = void 0;
this._session = void 0;
this._pageProxySession = session;
}
setSession(session) {
this._session = session;
}
async keydown(modifiers, keyName, description, autoRepeat) {
const parts = [];
for (const modifier of ['Shift', 'Control', 'Alt', 'Meta']) {
if (modifiers.has(modifier)) parts.push(modifier);
}
const {
code,
keyCode,
key,
text
} = description;
parts.push(code);
const shortcut = parts.join('+');
let commands = _macEditingCommands.macEditingCommands[shortcut];
if ((0, _utils.isString)(commands)) commands = [commands];
await this._pageProxySession.send('Input.dispatchKeyEvent', {
type: 'keyDown',
modifiers: toModifiersMask(modifiers),
windowsVirtualKeyCode: keyCode,
code,
key,
text,
unmodifiedText: text,
autoRepeat,
macCommands: commands,
isKeypad: description.location === input.keypadLocation
});
}
async keyup(modifiers, keyName, description) {
const {
code,
key
} = description;
await this._pageProxySession.send('Input.dispatchKeyEvent', {
type: 'keyUp',
modifiers: toModifiersMask(modifiers),
key,
windowsVirtualKeyCode: description.keyCode,
code,
isKeypad: description.location === input.keypadLocation
});
}
async sendText(text) {
await this._session.send('Page.insertText', {
text
});
}
}
exports.RawKeyboardImpl = RawKeyboardImpl;
class RawMouseImpl {
constructor(session) {
this._pageProxySession = void 0;
this._session = void 0;
this._page = void 0;
this._pageProxySession = session;
}
setSession(session) {
this._session = session;
}
async move(x, y, button, buttons, modifiers, forClick) {
await this._pageProxySession.send('Input.dispatchMouseEvent', {
type: 'move',
button,
buttons: toButtonsMask(buttons),
x,
y,
modifiers: toModifiersMask(modifiers)
});
}
async down(x, y, button, buttons, modifiers, clickCount) {
await this._pageProxySession.send('Input.dispatchMouseEvent', {
type: 'down',
button,
buttons: toButtonsMask(buttons),
x,
y,
modifiers: toModifiersMask(modifiers),
clickCount
});
}
async up(x, y, button, buttons, modifiers, clickCount) {
await this._pageProxySession.send('Input.dispatchMouseEvent', {
type: 'up',
button,
buttons: toButtonsMask(buttons),
x,
y,
modifiers: toModifiersMask(modifiers),
clickCount
});
}
async wheel(x, y, buttons, modifiers, deltaX, deltaY) {
var _this$_page;
if ((_this$_page = this._page) !== null && _this$_page !== void 0 && _this$_page._browserContext._options.isMobile) throw new Error('Mouse wheel is not supported in mobile WebKit');
await this._session.send('Page.updateScrollingState');
// Wheel events hit the compositor first, so wait one frame for it to be synced.
await this._page.mainFrame().evaluateExpression(`new Promise(requestAnimationFrame)`, {
world: 'utility'
});
await this._pageProxySession.send('Input.dispatchWheelEvent', {
x,
y,
deltaX,
deltaY,
modifiers: toModifiersMask(modifiers)
});
}
setPage(page) {
this._page = page;
}
}
exports.RawMouseImpl = RawMouseImpl;
class RawTouchscreenImpl {
constructor(session) {
this._pageProxySession = void 0;
this._pageProxySession = session;
}
async tap(x, y, modifiers) {
await this._pageProxySession.send('Input.dispatchTapEvent', {
x,
y,
modifiers: toModifiersMask(modifiers)
});
}
}
exports.RawTouchscreenImpl = RawTouchscreenImpl;

View File

@@ -0,0 +1,162 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WKRouteImpl = exports.WKInterceptableRequest = void 0;
var _utils = require("../../utils");
var network = _interopRequireWildcard(require("../network"));
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 && {}.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 2017 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const errorReasons = {
'aborted': 'Cancellation',
'accessdenied': 'AccessControl',
'addressunreachable': 'General',
'blockedbyclient': 'Cancellation',
'blockedbyresponse': 'General',
'connectionaborted': 'General',
'connectionclosed': 'General',
'connectionfailed': 'General',
'connectionrefused': 'General',
'connectionreset': 'General',
'internetdisconnected': 'General',
'namenotresolved': 'General',
'timedout': 'Timeout',
'failed': 'General'
};
class WKInterceptableRequest {
constructor(session, frame, event, redirectedFrom, documentId) {
this._session = void 0;
this._requestId = void 0;
this.request = void 0;
this._timestamp = void 0;
this._wallTime = void 0;
this._session = session;
this._requestId = event.requestId;
const resourceType = event.type ? event.type.toLowerCase() : redirectedFrom ? redirectedFrom.request.resourceType() : 'other';
let postDataBuffer = null;
this._timestamp = event.timestamp;
this._wallTime = event.walltime * 1000;
if (event.request.postData) postDataBuffer = Buffer.from(event.request.postData, 'base64');
this.request = new network.Request(frame._page._browserContext, frame, null, (redirectedFrom === null || redirectedFrom === void 0 ? void 0 : redirectedFrom.request) || null, documentId, event.request.url, resourceType, event.request.method, postDataBuffer, (0, _utils.headersObjectToArray)(event.request.headers));
}
adoptRequestFromNewProcess(newSession, requestId) {
this._session = newSession;
this._requestId = requestId;
}
createResponse(responsePayload) {
const getResponseBody = async () => {
const response = await this._session.send('Network.getResponseBody', {
requestId: this._requestId
});
return Buffer.from(response.body, response.base64Encoded ? 'base64' : 'utf8');
};
const timingPayload = responsePayload.timing;
const timing = {
startTime: this._wallTime,
domainLookupStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.domainLookupStart) : -1,
domainLookupEnd: timingPayload ? wkMillisToRoundishMillis(timingPayload.domainLookupEnd) : -1,
connectStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.connectStart) : -1,
secureConnectionStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.secureConnectionStart) : -1,
connectEnd: timingPayload ? wkMillisToRoundishMillis(timingPayload.connectEnd) : -1,
requestStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.requestStart) : -1,
responseStart: timingPayload ? wkMillisToRoundishMillis(timingPayload.responseStart) : -1
};
const setCookieSeparator = process.platform === 'darwin' ? ',' : 'playwright-set-cookie-separator';
const response = new network.Response(this.request, responsePayload.status, responsePayload.statusText, (0, _utils.headersObjectToArray)(responsePayload.headers, ',', setCookieSeparator), timing, getResponseBody, responsePayload.source === 'service-worker');
// No raw response headers in WebKit, use "provisional" ones.
response.setRawResponseHeaders(null);
// Transfer size is not available in WebKit.
response.setTransferSize(null);
if (responsePayload.requestHeaders && Object.keys(responsePayload.requestHeaders).length) {
const headers = {
...responsePayload.requestHeaders
};
if (!headers['host']) headers['Host'] = new URL(this.request.url()).host;
this.request.setRawRequestHeaders((0, _utils.headersObjectToArray)(headers));
} else {
// No raw headers available, use provisional ones.
this.request.setRawRequestHeaders(null);
}
return response;
}
}
exports.WKInterceptableRequest = WKInterceptableRequest;
class WKRouteImpl {
constructor(session, requestId) {
this._session = void 0;
this._requestId = void 0;
this._session = session;
this._requestId = requestId;
}
async abort(errorCode) {
const errorType = errorReasons[errorCode];
(0, _utils.assert)(errorType, 'Unknown error code: ' + errorCode);
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
await this._session.sendMayFail('Network.interceptRequestWithError', {
requestId: this._requestId,
errorType
});
}
async fulfill(response) {
if (300 <= response.status && response.status < 400) throw new Error('Cannot fulfill with redirect status: ' + response.status);
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
let mimeType = response.isBase64 ? 'application/octet-stream' : 'text/plain';
const headers = (0, _utils.headersArrayToObject)(response.headers, true /* lowerCase */);
const contentType = headers['content-type'];
if (contentType) mimeType = contentType.split(';')[0].trim();
await this._session.sendMayFail('Network.interceptRequestWithResponse', {
requestId: this._requestId,
status: response.status,
statusText: network.statusText(response.status),
mimeType,
headers,
base64Encoded: response.isBase64,
content: response.body
});
}
async continue(overrides) {
// In certain cases, protocol will return error if the request was already canceled
// or the page was closed. We should tolerate these errors.
await this._session.sendMayFail('Network.interceptWithRequest', {
requestId: this._requestId,
url: overrides.url,
method: overrides.method,
headers: overrides.headers ? (0, _utils.headersArrayToObject)(overrides.headers, false /* lowerCase */) : undefined,
postData: overrides.postData ? Buffer.from(overrides.postData).toString('base64') : undefined
});
}
}
exports.WKRouteImpl = WKRouteImpl;
function wkMillisToRoundishMillis(value) {
// WebKit uses -1000 for unavailable.
if (value === -1000) return -1;
// WebKit has a bug, instead of -1 it sends -1000 to be in ms.
if (value <= 0) {
// DNS can start before request start on Mac Network Stack
return -1;
}
return (value * 1000 | 0) / 1000;
}

1208
node_modules/playwright-core/lib/server/webkit/wkPage.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,94 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WKProvisionalPage = void 0;
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 WKProvisionalPage {
constructor(session, page) {
var _page$_page$mainFrame;
this._session = void 0;
this._wkPage = void 0;
this._coopNavigationRequest = void 0;
this._sessionListeners = [];
this._mainFrameId = null;
this.initializationPromise = void 0;
this._session = session;
this._wkPage = page;
// Cross-Origin-Opener-Policy (COOP) request starts in one process and once response headers
// have been received, continues in another.
//
// Network.requestWillBeSent and requestIntercepted (if intercepting) from the original web process
// will always come before a provisional page is created based on the response COOP headers.
// Thereafter we'll receive targetCreated (provisional) and later on in some order loadingFailed from the
// original process and requestWillBeSent from the provisional one. We should ignore loadingFailed
// as the original request continues in the provisional process. But if the provisional load is later
// canceled we should dispatch loadingFailed to the client.
this._coopNavigationRequest = (_page$_page$mainFrame = page._page.mainFrame().pendingDocument()) === null || _page$_page$mainFrame === void 0 ? void 0 : _page$_page$mainFrame.request;
const overrideFrameId = handler => {
return payload => {
// Pretend that the events happened in the same process.
if (payload.frameId) payload.frameId = this._wkPage._page._frameManager.mainFrame()._id;
handler(payload);
};
};
const wkPage = this._wkPage;
this._sessionListeners = [_eventsHelper.eventsHelper.addEventListener(session, 'Network.requestWillBeSent', overrideFrameId(e => this._onRequestWillBeSent(e))), _eventsHelper.eventsHelper.addEventListener(session, 'Network.requestIntercepted', overrideFrameId(e => wkPage._onRequestIntercepted(session, e))), _eventsHelper.eventsHelper.addEventListener(session, 'Network.responseReceived', overrideFrameId(e => wkPage._onResponseReceived(session, e))), _eventsHelper.eventsHelper.addEventListener(session, 'Network.loadingFinished', overrideFrameId(e => this._onLoadingFinished(e))), _eventsHelper.eventsHelper.addEventListener(session, 'Network.loadingFailed', overrideFrameId(e => this._onLoadingFailed(e)))];
this.initializationPromise = this._wkPage._initializeSession(session, true, ({
frameTree
}) => this._handleFrameTree(frameTree));
}
coopNavigationRequest() {
return this._coopNavigationRequest;
}
dispose() {
_eventsHelper.eventsHelper.removeEventListeners(this._sessionListeners);
}
commit() {
(0, _utils.assert)(this._mainFrameId);
this._wkPage._onFrameAttached(this._mainFrameId, null);
}
_onRequestWillBeSent(event) {
if (this._coopNavigationRequest && this._coopNavigationRequest.url() === event.request.url) {
// If it's a continuation of the main frame navigation request after COOP headers were received,
// take over original request, and replace its request id with the new one.
this._wkPage._adoptRequestFromNewProcess(this._coopNavigationRequest, this._session, event.requestId);
// Simply ignore this event as it has already been dispatched from the original process
// and there will ne no requestIntercepted event from the provisional process as it resumes
// existing network load (that has already received reponse headers).
return;
}
this._wkPage._onRequestWillBeSent(this._session, event);
}
_onLoadingFinished(event) {
this._coopNavigationRequest = undefined;
this._wkPage._onLoadingFinished(event);
}
_onLoadingFailed(event) {
this._coopNavigationRequest = undefined;
this._wkPage._onLoadingFailed(this._session, event);
}
_handleFrameTree(frameTree) {
(0, _utils.assert)(!frameTree.frame.parentId);
this._mainFrameId = frameTree.frame.id;
}
}
exports.WKProvisionalPage = WKProvisionalPage;

View File

@@ -0,0 +1,104 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.WKWorkers = void 0;
var _eventsHelper = require("../utils/eventsHelper");
var _page = require("../page");
var _wkConnection = require("./wkConnection");
var _wkExecutionContext = require("./wkExecutionContext");
/**
* Copyright 2019 Microsoft Corporation All rights reserved.
*
* 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 WKWorkers {
constructor(page) {
this._sessionListeners = [];
this._page = void 0;
this._workerSessions = new Map();
this._page = page;
}
setSession(session) {
_eventsHelper.eventsHelper.removeEventListeners(this._sessionListeners);
this.clear();
this._sessionListeners = [_eventsHelper.eventsHelper.addEventListener(session, 'Worker.workerCreated', event => {
const worker = new _page.Worker(this._page, event.url);
const workerSession = new _wkConnection.WKSession(session.connection, event.workerId, message => {
session.send('Worker.sendMessageToWorker', {
workerId: event.workerId,
message: JSON.stringify(message)
}).catch(e => {
workerSession.dispatchMessage({
id: message.id,
error: {
message: e.message
}
});
});
});
this._workerSessions.set(event.workerId, workerSession);
worker._createExecutionContext(new _wkExecutionContext.WKExecutionContext(workerSession, undefined));
this._page._addWorker(event.workerId, worker);
workerSession.on('Console.messageAdded', event => this._onConsoleMessage(worker, event));
Promise.all([workerSession.send('Runtime.enable'), workerSession.send('Console.enable'), session.send('Worker.initialized', {
workerId: event.workerId
})]).catch(e => {
// Worker can go as we are initializing it.
this._page._removeWorker(event.workerId);
});
}), _eventsHelper.eventsHelper.addEventListener(session, 'Worker.dispatchMessageFromWorker', event => {
const workerSession = this._workerSessions.get(event.workerId);
if (!workerSession) return;
workerSession.dispatchMessage(JSON.parse(event.message));
}), _eventsHelper.eventsHelper.addEventListener(session, 'Worker.workerTerminated', event => {
const workerSession = this._workerSessions.get(event.workerId);
if (!workerSession) return;
workerSession.dispose();
this._workerSessions.delete(event.workerId);
this._page._removeWorker(event.workerId);
})];
}
clear() {
this._page._clearWorkers();
this._workerSessions.clear();
}
async initializeSession(session) {
await session.send('Worker.enable');
}
async _onConsoleMessage(worker, event) {
const {
type,
level,
text,
parameters,
url,
line: lineNumber,
column: columnNumber
} = event.message;
let derivedType = type || '';
if (type === 'log') derivedType = level;else if (type === 'timing') derivedType = 'timeEnd';
const handles = (parameters || []).map(p => {
return (0, _wkExecutionContext.createHandle)(worker._existingExecutionContext, p);
});
const location = {
url: url || '',
lineNumber: (lineNumber || 1) - 1,
columnNumber: (columnNumber || 1) - 1
};
this._page._addConsoleMessage(derivedType, handles, location, handles.length ? undefined : text);
}
}
exports.WKWorkers = WKWorkers;