playwright/src/webkit/Target.ts

96 lines
3.1 KiB
TypeScript

/**
* Copyright 2019 Google Inc. All rights reserved.
* Modifications copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BrowserContext } from './Browser';
import { Page } from './Page';
import { Protocol } from './protocol';
import { isSwappedOutError, TargetSession, TargetSessionEvents } from './Connection';
const targetSymbol = Symbol('target');
export class Target {
readonly _browserContext: BrowserContext;
readonly _targetId: string;
readonly _type: 'page' | 'service-worker' | 'worker';
private readonly _session: TargetSession;
private _pagePromise: Promise<Page> | null = null;
private _page: Page | null = null;
static fromPage(page: Page): Target {
return (page as any)[targetSymbol];
}
constructor(session: TargetSession, targetInfo: Protocol.Target.TargetInfo, browserContext: BrowserContext) {
const {targetId, type} = targetInfo;
this._session = session;
this._browserContext = browserContext;
this._targetId = targetId;
this._type = type;
/** @type {?Promise<!Page>} */
this._pagePromise = null;
}
_didClose() {
if (this._page)
this._page._didClose();
}
async _swappedIn(oldTarget: Target) {
if (!oldTarget._pagePromise)
return;
this._pagePromise = oldTarget._pagePromise;
this._page = oldTarget._page;
// Swapped out target should not be accessed by anyone. Reset page promise so that
// old target does not close the page on connection reset.
oldTarget._pagePromise = null;
oldTarget._page = null;
await this._adoptPage();
}
private async _adoptPage() {
(this._page as any)[targetSymbol] = this;
this._session.once(TargetSessionEvents.Disconnected, () => {
// Once swapped out, we reset _page and won't call _didDisconnect for old session.
if (this._page)
this._page._didDisconnect();
});
await this._page._initialize(this._session).catch(e => {
// Swallow initialization errors due to newer target swap in,
// since we will reinitialize again.
if (!isSwappedOutError(e))
throw e;
});
}
async page(): Promise<Page> {
if (this._type === 'page' && !this._pagePromise) {
const browser = this._browserContext.browser();
// Reference local page variable as _page may be
// cleared on swap.
const page = new Page(this._browserContext);
this._page = page;
this._pagePromise = new Promise(async f => {
await this._adoptPage();
if (browser._defaultViewport)
await page.setViewport(browser._defaultViewport);
f(page);
});
}
return this._pagePromise;
}
}