move to serverside
This commit is contained in:
parent
7a08cd6fa7
commit
5e49e08ba2
|
|
@ -81,7 +81,7 @@ export class Browser extends ChannelOwner<channels.BrowserChannel> implements ap
|
|||
|
||||
async _innerNewContext(options: BrowserContextOptions = {}, forReuse: boolean): Promise<BrowserContext> {
|
||||
options = { ...this._browserType._defaultContextOptions, ...options };
|
||||
const contextOptions = await prepareBrowserContextParams(options);
|
||||
const contextOptions = await prepareBrowserContextParams(options, this._browserType);
|
||||
const response = forReuse ? await this._channel.newContextForReuse(contextOptions) : await this._channel.newContext(contextOptions);
|
||||
const context = BrowserContext.from(response.context);
|
||||
await this._browserType._didCreateContext(context, contextOptions, this._options, options.logger || this._logger);
|
||||
|
|
|
|||
|
|
@ -29,8 +29,7 @@ import { Events } from './events';
|
|||
import { TimeoutSettings } from '../common/timeoutSettings';
|
||||
import { Waiter } from './waiter';
|
||||
import type { Headers, WaitForEventOptions, BrowserContextOptions, StorageState, LaunchOptions } from './types';
|
||||
import type { RegisteredListener } from '../utils';
|
||||
import { type URLMatch, headersObjectToArray, isRegExp, isString, urlMatchesEqual, mkdirIfNeeded, eventsHelper } from '../utils';
|
||||
import { type URLMatch, headersObjectToArray, isRegExp, isString, urlMatchesEqual, mkdirIfNeeded } from '../utils';
|
||||
import type * as api from '../../types/types';
|
||||
import type * as structs from '../../types/structs';
|
||||
import { CDPSession } from './cdpSession';
|
||||
|
|
@ -45,7 +44,6 @@ import { Dialog } from './dialog';
|
|||
import { WebError } from './webError';
|
||||
import { TargetClosedError, parseError } from './errors';
|
||||
import { Clock } from './clock';
|
||||
import type { MockingProxy } from './mockingProxy';
|
||||
|
||||
export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel> implements api.BrowserContext {
|
||||
_pages = new Set<Page>();
|
||||
|
|
@ -70,7 +68,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
_closeWasCalled = false;
|
||||
private _closeReason: string | undefined;
|
||||
private _harRouters: HarRouter[] = [];
|
||||
_mockingProxy?: MockingProxy;
|
||||
|
||||
static from(context: channels.BrowserContextChannel): BrowserContext {
|
||||
return (context as any)._object;
|
||||
|
|
@ -169,7 +166,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
this.emit(Events.BrowserContext.Page, page);
|
||||
if (page._opener && !page._opener.isClosed())
|
||||
page._opener.emit(Events.Page.Popup, page);
|
||||
this._mockingProxy?.instrumentPage(page);
|
||||
}
|
||||
|
||||
_onRequest(request: network.Request, page: Page | null) {
|
||||
|
|
@ -241,12 +237,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
await bindingCall.call(func);
|
||||
}
|
||||
|
||||
async _subscribeToMockingProxy(mockingProxy: MockingProxy) {
|
||||
if (this._mockingProxy)
|
||||
throw new Error('Multiple mocking proxies are not supported');
|
||||
this._mockingProxy = mockingProxy;
|
||||
}
|
||||
|
||||
setDefaultNavigationTimeout(timeout: number | undefined) {
|
||||
this._timeoutSettings.setDefaultNavigationTimeout(timeout);
|
||||
this._wrapApiCall(async () => {
|
||||
|
|
@ -530,7 +520,7 @@ function prepareRecordHarOptions(options: BrowserContextOptions['recordHar']): c
|
|||
};
|
||||
}
|
||||
|
||||
export async function prepareBrowserContextParams(options: BrowserContextOptions): Promise<channels.BrowserNewContextParams> {
|
||||
export async function prepareBrowserContextParams(options: BrowserContextOptions, type?: BrowserType): Promise<channels.BrowserNewContextParams> {
|
||||
if (options.videoSize && !options.videosPath)
|
||||
throw new Error(`"videoSize" option requires "videosPath" to be specified`);
|
||||
if (options.extraHTTPHeaders)
|
||||
|
|
@ -548,6 +538,7 @@ export async function prepareBrowserContextParams(options: BrowserContextOptions
|
|||
forcedColors: options.forcedColors === null ? 'no-override' : options.forcedColors,
|
||||
acceptDownloads: toAcceptDownloadsProtocol(options.acceptDownloads),
|
||||
clientCertificates: await toClientCertificatesProtocol(options.clientCertificates),
|
||||
mockingProxyBaseURL: type?._playwright._mockingProxy?.baseURL(),
|
||||
};
|
||||
if (!contextParams.recordVideo && options.videosPath) {
|
||||
contextParams.recordVideo = {
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import { assert, headersObjectToArray, monotonicTime } from '../utils';
|
|||
import type * as api from '../../types/types';
|
||||
import { raceAgainstDeadline } from '../utils/timeoutRunner';
|
||||
import type { Playwright } from './playwright';
|
||||
import type { Page } from './page';
|
||||
|
||||
export interface BrowserServerLauncher {
|
||||
launchServer(options?: LaunchServerOptions): Promise<api.BrowserServer>;
|
||||
|
|
@ -96,7 +95,7 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
|||
const logger = options.logger || this._defaultLaunchOptions?.logger;
|
||||
assert(!(options as any).port, 'Cannot specify a port without launching as a server.');
|
||||
options = { ...this._defaultLaunchOptions, ...this._defaultContextOptions, ...options };
|
||||
const contextParams = await prepareBrowserContextParams(options);
|
||||
const contextParams = await prepareBrowserContextParams(options, this);
|
||||
const persistentParams: channels.BrowserTypeLaunchPersistentContextParams = {
|
||||
...contextParams,
|
||||
ignoreDefaultArgs: Array.isArray(options.ignoreDefaultArgs) ? options.ignoreDefaultArgs : undefined,
|
||||
|
|
@ -243,13 +242,6 @@ export class BrowserType extends ChannelOwner<channels.BrowserTypeChannel> imple
|
|||
if (this._defaultContextNavigationTimeout !== undefined)
|
||||
context.setDefaultNavigationTimeout(this._defaultContextNavigationTimeout);
|
||||
|
||||
if (this._playwright._mockingProxy) {
|
||||
context.on(Events.BrowserContext.Page, (page: Page) => {
|
||||
// TODO: funnel through protocol, so these headers are known to the server browsercontext and can be applied earlier
|
||||
page.setExtraHTTPHeaders(this._playwright._mockingProxy!.instrumentationHeaders(page));
|
||||
});
|
||||
}
|
||||
|
||||
await this._instrumentation.runAfterCreateBrowserContext(context);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ export class MockingProxy extends ChannelOwner<channels.MockingProxyChannel> {
|
|||
}
|
||||
|
||||
findPage(correlation: string): Page | undefined {
|
||||
const guid = `Page@${correlation}`;
|
||||
const guid = `page@${correlation}`;
|
||||
// TODO: move this as list onto Playwright directly
|
||||
for (const browserType of [this._playwright.chromium, this._playwright.firefox, this._playwright.webkit]) {
|
||||
for (const context of browserType._contexts) {
|
||||
|
|
@ -81,10 +81,7 @@ export class MockingProxy extends ChannelOwner<channels.MockingProxyChannel> {
|
|||
}
|
||||
}
|
||||
|
||||
instrumentationHeaders(page: Page) {
|
||||
const correlation = page._guid.substring('Page@'.length);
|
||||
return {
|
||||
'x-playwright-proxy': `${this._initializer.baseURL}/pw_meta:${correlation}/`,
|
||||
};
|
||||
baseURL() {
|
||||
return this._initializer.baseURL;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -775,6 +775,7 @@ scheme.BrowserNewContextParams = tObject({
|
|||
cookies: tOptional(tArray(tType('SetNetworkCookie'))),
|
||||
origins: tOptional(tArray(tType('OriginStorage'))),
|
||||
})),
|
||||
mockingProxyBaseURL: tOptional(tString),
|
||||
});
|
||||
scheme.BrowserNewContextResult = tObject({
|
||||
context: tChannel(['BrowserContext']),
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ export class FFPage implements PageDelegate {
|
|||
}
|
||||
|
||||
async updateExtraHTTPHeaders(): Promise<void> {
|
||||
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page.extraHTTPHeaders() || [] });
|
||||
await this._session.send('Network.setExtraHTTPHeaders', { headers: this._page.extraHTTPHeaders() });
|
||||
}
|
||||
|
||||
async updateEmulatedViewportSize(): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -654,7 +654,7 @@ export class Frame extends SdkObject {
|
|||
private async _gotoAction(progress: Progress, url: string, options: types.GotoOptions): Promise<network.Response | null> {
|
||||
const waitUntil = verifyLifecycle('waitUntil', options.waitUntil === undefined ? 'load' : options.waitUntil);
|
||||
progress.log(`navigating to "${url}", waiting until "${waitUntil}"`);
|
||||
const headers = this._page.extraHTTPHeaders() || [];
|
||||
const headers = this._page.extraHTTPHeaders();
|
||||
const refererHeader = headers.find(h => h.name.toLowerCase() === 'referer');
|
||||
let referer = refererHeader ? refererHeader.value : undefined;
|
||||
if (options.referer !== undefined) {
|
||||
|
|
|
|||
|
|
@ -365,8 +365,20 @@ export class Page extends SdkObject {
|
|||
return this._delegate.updateExtraHTTPHeaders();
|
||||
}
|
||||
|
||||
extraHTTPHeaders(): types.HeadersArray | undefined {
|
||||
return this._extraHTTPHeaders;
|
||||
extraHTTPHeaders(): types.HeadersArray {
|
||||
return this.instrumentationHeaders().concat(this._extraHTTPHeaders ?? []);
|
||||
}
|
||||
|
||||
instrumentationHeaders() {
|
||||
const headers: channels.NameValue[] = [];
|
||||
|
||||
const mockingProxyBaseURL = this.context()._options.mockingProxyBaseURL;
|
||||
if (mockingProxyBaseURL) {
|
||||
const correlation = this.guid.substring('Page@'.length);
|
||||
headers.push({ name: 'x-playwright-proxy', value: encodeURIComponent(mockingProxyBaseURL + `pw_meta:${correlation}/`) });
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
async _onBindingCalled(payload: string, context: dom.FrameExecutionContext) {
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
|
|||
_optionContextReuseMode: ContextReuseMode,
|
||||
_optionConnectOptions: PlaywrightWorkerOptions['connectOptions'],
|
||||
_reuseContext: boolean,
|
||||
_mockingProxy?: MockingProxy,
|
||||
_mockingProxy?: void,
|
||||
};
|
||||
|
||||
const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||
|
|
@ -124,12 +124,11 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
}, true);
|
||||
}, { scope: 'worker', timeout: 0 }],
|
||||
|
||||
_mockingProxy: [async ({ mockingProxy: mockingProxyOption, playwright }, use) => {
|
||||
if (mockingProxyOption !== 'inject-via-header')
|
||||
return await use(undefined);
|
||||
const mockingProxy = await (playwright as PlaywrightImpl)._startMockingProxy();
|
||||
await use(mockingProxy);
|
||||
}, { scope: 'worker', box: true }],
|
||||
_mockingProxy: [async ({ mockingProxy, playwright }, use) => {
|
||||
if (mockingProxy === 'inject-via-header')
|
||||
await (playwright as PlaywrightImpl)._startMockingProxy();
|
||||
await use();
|
||||
}, { scope: 'worker', box: true, auto: true }],
|
||||
|
||||
acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true }],
|
||||
bypassCSP: [({ contextOptions }, use) => use(contextOptions.bypassCSP ?? false), { option: true }],
|
||||
|
|
@ -259,7 +258,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
}
|
||||
}, { auto: 'all-hooks-included', title: 'context configuration', box: true } as any],
|
||||
|
||||
_setupArtifacts: [async ({ playwright, screenshot, _mockingProxy }, use, testInfo) => {
|
||||
_setupArtifacts: [async ({ playwright, screenshot }, use, testInfo) => {
|
||||
// This fixture has a separate zero-timeout slot to ensure that artifact collection
|
||||
// happens even after some fixtures or hooks time out.
|
||||
// Now that default test timeout is known, we can replace zero with an actual value.
|
||||
|
|
@ -313,8 +312,6 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
currentTestInfo()?._setDebugMode();
|
||||
},
|
||||
runAfterCreateBrowserContext: async (context: BrowserContextImpl) => {
|
||||
if (_mockingProxy)
|
||||
await context._subscribeToMockingProxy(_mockingProxy);
|
||||
await artifactsRecorder?.didCreateBrowserContext(context);
|
||||
const testInfo = currentTestInfo();
|
||||
if (testInfo)
|
||||
|
|
|
|||
2
packages/protocol/src/channels.d.ts
vendored
2
packages/protocol/src/channels.d.ts
vendored
|
|
@ -1369,6 +1369,7 @@ export type BrowserNewContextParams = {
|
|||
cookies?: SetNetworkCookie[],
|
||||
origins?: OriginStorage[],
|
||||
},
|
||||
mockingProxyBaseURL?: string,
|
||||
};
|
||||
export type BrowserNewContextOptions = {
|
||||
noDefaultViewport?: boolean,
|
||||
|
|
@ -1435,6 +1436,7 @@ export type BrowserNewContextOptions = {
|
|||
cookies?: SetNetworkCookie[],
|
||||
origins?: OriginStorage[],
|
||||
},
|
||||
mockingProxyBaseURL?: string,
|
||||
};
|
||||
export type BrowserNewContextResult = {
|
||||
context: BrowserContextChannel,
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,7 @@ Browser:
|
|||
origins:
|
||||
type: array?
|
||||
items: OriginStorage
|
||||
mockingProxyBaseURL: string?
|
||||
returns:
|
||||
context: BrowserContext
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue