feedback
This commit is contained in:
parent
08afdc600c
commit
d80f3297aa
|
|
@ -144,7 +144,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
});
|
||||
this._channel.on('request', ({ request, page }) => this._onRequest(network.Request.from(request), Page.fromNullable(page)));
|
||||
this._channel.on('requestFailed', ({ request, failureText, responseEndTiming, page }) => this._onRequestFailed(network.Request.from(request), responseEndTiming, failureText, Page.fromNullable(page)));
|
||||
this._channel.on('requestFinished', params => this._onRequestFinished(params));
|
||||
this._channel.on('requestFinished', ({ request, response, page, responseEndTiming }) => this._onRequestFinished(network.Request.from(request), network.Response.fromNullable(response), Page.fromNullable(page), responseEndTiming));
|
||||
this._channel.on('response', ({ response, page }) => this._onResponse(network.Response.from(response), Page.fromNullable(page)));
|
||||
this._closedPromise = new Promise(f => this.once(Events.BrowserContext.Close, f));
|
||||
|
||||
|
|
@ -165,27 +165,27 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
this.tracing._tracesDir = browserOptions.tracesDir;
|
||||
}
|
||||
|
||||
private async _onPage(page: Page): Promise<void>{
|
||||
private _onPage(page: Page): void {
|
||||
this._pages.add(page);
|
||||
this.emit(Events.BrowserContext.Page, page);
|
||||
await this._mockingProxy?.instrumentPage(page);
|
||||
if (page._opener && !page._opener.isClosed())
|
||||
page._opener.emit(Events.Page.Popup, page);
|
||||
this._mockingProxy?.instrumentPage(page);
|
||||
}
|
||||
|
||||
private _onRequest(request: network.Request, page: Page | null) {
|
||||
_onRequest(request: network.Request, page: Page | null) {
|
||||
this.emit(Events.BrowserContext.Request, request);
|
||||
if (page)
|
||||
page.emit(Events.Page.Request, request);
|
||||
}
|
||||
|
||||
private _onResponse(response: network.Response, page: Page | null) {
|
||||
_onResponse(response: network.Response, page: Page | null) {
|
||||
this.emit(Events.BrowserContext.Response, response);
|
||||
if (page)
|
||||
page.emit(Events.Page.Response, response);
|
||||
}
|
||||
|
||||
private _onRequestFailed(request: network.Request, responseEndTiming: number, failureText: string | undefined, page: Page | null) {
|
||||
_onRequestFailed(request: network.Request, responseEndTiming: number, failureText: string | undefined, page: Page | null) {
|
||||
request._failureText = failureText || null;
|
||||
request._setResponseEndTiming(responseEndTiming);
|
||||
this.emit(Events.BrowserContext.RequestFailed, request);
|
||||
|
|
@ -193,11 +193,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
page.emit(Events.Page.RequestFailed, request);
|
||||
}
|
||||
|
||||
private _onRequestFinished(params: channels.BrowserContextRequestFinishedEvent) {
|
||||
const { responseEndTiming } = params;
|
||||
const request = network.Request.from(params.request);
|
||||
const response = network.Response.fromNullable(params.response);
|
||||
const page = Page.fromNullable(params.page);
|
||||
_onRequestFinished(request: network.Request, response: network.Response | null, page: Page | null, responseEndTiming: number) {
|
||||
request._setResponseEndTiming(responseEndTiming);
|
||||
this.emit(Events.BrowserContext.RequestFinished, request);
|
||||
if (page)
|
||||
|
|
@ -250,13 +246,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
if (this._mockingProxy)
|
||||
throw new Error('Multiple mocking proxies are not supported');
|
||||
this._mockingProxy = mockingProxy;
|
||||
this._registeredListeners.push(
|
||||
eventsHelper.addEventListener(this._mockingProxy, Events.MockingProxy.Route, (route: network.Route) => {
|
||||
const page = route.request()._safePage()!;
|
||||
page._onRoute(route);
|
||||
}),
|
||||
// TODO: should we also emit `request`, `response`, `requestFinished`, `requestFailed` events?
|
||||
);
|
||||
}
|
||||
|
||||
setDefaultNavigationTimeout(timeout: number | undefined) {
|
||||
|
|
@ -421,15 +410,6 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||
private async _updateInterceptionPatterns() {
|
||||
const patterns = network.RouteHandler.prepareInterceptionPatterns(this._routes);
|
||||
await this._channel.setNetworkInterceptionPatterns({ patterns });
|
||||
await this._updateMockingProxyInterceptionPatterns();
|
||||
}
|
||||
|
||||
async _updateMockingProxyInterceptionPatterns() {
|
||||
if (!this._mockingProxy)
|
||||
return;
|
||||
const pageRoutes = this.pages().flatMap(page => page._routes);
|
||||
const patterns = network.RouteHandler.prepareInterceptionPatterns(this._routes.concat(pageRoutes));
|
||||
await this._mockingProxy.setInterceptionPatterns({ patterns });
|
||||
}
|
||||
|
||||
private async _updateWebSocketInterceptionPatterns() {
|
||||
|
|
|
|||
|
|
@ -94,8 +94,4 @@ export const Events = {
|
|||
Console: 'console',
|
||||
Window: 'window',
|
||||
},
|
||||
|
||||
MockingProxy: {
|
||||
Route: 'route',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import * as network from './network';
|
|||
import type * as channels from '@protocol/channels';
|
||||
import { ChannelOwner } from './channelOwner';
|
||||
import { APIRequestContext } from './fetch';
|
||||
import { Events } from './events';
|
||||
import { assert } from '../utils';
|
||||
import type { Page } from './page';
|
||||
|
||||
|
|
@ -31,39 +30,39 @@ export class MockingProxy extends ChannelOwner<channels.MockingProxyChannel> {
|
|||
this._channel.on('route', async (params: channels.MockingProxyRouteEvent) => {
|
||||
const route = network.Route.from(params.route);
|
||||
route._context = requestContext;
|
||||
this.emit(Events.MockingProxy.Route, route);
|
||||
const page = route.request()._safePage()!;
|
||||
await page._onRoute(route);
|
||||
});
|
||||
|
||||
this._channel.on('request', async (params: channels.MockingProxyRequestEvent) => {
|
||||
const page = this._pages.get(params.correlation);
|
||||
assert(page);
|
||||
const request = network.Request.from(params.request);
|
||||
request._page = page;
|
||||
request._pageForMockingProxy = page;
|
||||
page.context()._onRequest(request, page);
|
||||
});
|
||||
|
||||
this._channel.on('requestFailed', async (params: channels.MockingProxyRequestFailedEvent) => {
|
||||
const request = network.Request.from(params.request);
|
||||
request._failureText = params.failureText ?? null;
|
||||
request._setResponseEndTiming(params.responseEndTiming);
|
||||
const page = request._safePage()!;
|
||||
page.context()._onRequestFailed(request, params.responseEndTiming, params.failureText, page);
|
||||
});
|
||||
|
||||
this._channel.on('requestFinished', async (params: channels.MockingProxyRequestFinishedEvent) => {
|
||||
const { responseEndTiming } = params;
|
||||
const request = network.Request.from(params.request);
|
||||
const response = network.Response.fromNullable(params.response);
|
||||
request._setResponseEndTiming(responseEndTiming);
|
||||
response?._finishedPromise.resolve(null);
|
||||
const page = request._safePage()!;
|
||||
page.context()._onRequestFinished(request, response, page, responseEndTiming);
|
||||
});
|
||||
|
||||
this._channel.on('response', async (params: channels.MockingProxyResponseEvent) => {
|
||||
// no-op
|
||||
const response = network.Response.from(params.response);
|
||||
const page = response.request()._safePage()!;
|
||||
page.context()._onResponse(response, page);
|
||||
});
|
||||
}
|
||||
|
||||
async setInterceptionPatterns(params: channels.MockingProxySetInterceptionPatternsParams) {
|
||||
await this._channel.setInterceptionPatterns(params);
|
||||
}
|
||||
|
||||
async instrumentPage(page: Page) {
|
||||
const correlation = page._guid.split('@')[1];
|
||||
this._pages.set(correlation, page);
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
|||
private _actualHeadersPromise: Promise<RawHeaders> | undefined;
|
||||
_timing: ResourceTiming;
|
||||
private _fallbackOverrides: SerializedFallbackOverrides = {};
|
||||
_page: Page | null = null;
|
||||
_pageForMockingProxy: Page | null = null;
|
||||
|
||||
static from(request: channels.RequestChannel): Request {
|
||||
return (request as any)._object;
|
||||
|
|
@ -217,7 +217,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
|
|||
}
|
||||
|
||||
_safePage(): Page | null {
|
||||
return this._page ?? Frame.fromNullable(this._initializer.frame)?._page ?? null;
|
||||
return this._pageForMockingProxy ?? Frame.fromNullable(this._initializer.frame)?._page ?? null;
|
||||
}
|
||||
|
||||
serviceWorker(): Worker | null {
|
||||
|
|
|
|||
|
|
@ -568,7 +568,6 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||
private async _updateInterceptionPatterns() {
|
||||
const patterns = RouteHandler.prepareInterceptionPatterns(this._routes);
|
||||
await this._channel.setNetworkInterceptionPatterns({ patterns });
|
||||
await this._browserContext._updateMockingProxyInterceptionPatterns();
|
||||
}
|
||||
|
||||
private async _updateWebSocketInterceptionPatterns() {
|
||||
|
|
|
|||
|
|
@ -73,4 +73,9 @@ export class Playwright extends ChannelOwner<channels.PlaywrightChannel> {
|
|||
static from(channel: channels.PlaywrightChannel): Playwright {
|
||||
return (channel as any)._object;
|
||||
}
|
||||
|
||||
async _startMockingProxy() {
|
||||
const { mockingProxy } = await this._connection.localUtils()._channel.newMockingProxy({});
|
||||
return (mockingProxy as any)._object;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -363,16 +363,7 @@ scheme.MockingProxyRequestFinishedEvent = tObject({
|
|||
});
|
||||
scheme.MockingProxyResponseEvent = tObject({
|
||||
response: tChannel(['Response']),
|
||||
page: tOptional(tChannel(['Page'])),
|
||||
});
|
||||
scheme.MockingProxySetInterceptionPatternsParams = tObject({
|
||||
patterns: tArray(tObject({
|
||||
glob: tOptional(tString),
|
||||
regexSource: tOptional(tString),
|
||||
regexFlags: tOptional(tString),
|
||||
})),
|
||||
});
|
||||
scheme.MockingProxySetInterceptionPatternsResult = tOptional(tObject({}));
|
||||
scheme.RootInitializer = tOptional(tObject({}));
|
||||
scheme.RootInitializeParams = tObject({
|
||||
sdkLanguage: tEnum(['javascript', 'python', 'java', 'csharp']),
|
||||
|
|
|
|||
|
|
@ -312,8 +312,7 @@ class HarBackend {
|
|||
redirectURL?: string,
|
||||
status?: number,
|
||||
headers?: HeadersArray,
|
||||
body?: Buffer
|
||||
}> {
|
||||
body?: Buffer }> {
|
||||
let entry;
|
||||
try {
|
||||
entry = await this._harFindResponse(url, method, headers, postData);
|
||||
|
|
|
|||
|
|
@ -13,14 +13,12 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import type { CallMetadata } from '@protocol/callMetadata';
|
||||
import { MockingProxy } from '../mockingProxy';
|
||||
import type { RootDispatcher } from './dispatcher';
|
||||
import { Dispatcher, existingDispatcher } from './dispatcher';
|
||||
import type * as channels from '@protocol/channels';
|
||||
import { APIRequestContextDispatcher, RequestDispatcher, ResponseDispatcher, RouteDispatcher } from './networkDispatchers';
|
||||
import type { Request, Route } from '../network';
|
||||
import { urlMatches } from '../../utils/isomorphic/urlMatch';
|
||||
|
||||
export class MockingProxyDispatcher extends Dispatcher<MockingProxy, channels.MockingProxyChannel, RootDispatcher> implements channels.MockingProxyChannel {
|
||||
_type_MockingProxy = true;
|
||||
|
|
@ -58,12 +56,4 @@ export class MockingProxyDispatcher extends Dispatcher<MockingProxy, channels.Mo
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
async setInterceptionPatterns(params: channels.MockingProxySetInterceptionPatternsParams, metadata?: CallMetadata): Promise<channels.MockingProxySetInterceptionPatternsResult> {
|
||||
if (params.patterns.length === 0)
|
||||
return this._object.setInterceptionPatterns(undefined);
|
||||
|
||||
const urlMatchers = params.patterns.map(pattern => pattern.regexSource ? new RegExp(pattern.regexSource, pattern.regexFlags!) : pattern.glob!);
|
||||
this._object.setInterceptionPatterns(url => urlMatchers.some(urlMatch => urlMatches(undefined, url, urlMatch)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,6 @@ export class MockingProxy extends SdkObject implements RequestContext {
|
|||
};
|
||||
|
||||
fetchRequest: APIRequestContext;
|
||||
private _matches?: (url: string) => boolean;
|
||||
private _httpServer = new WorkerHttpServer();
|
||||
|
||||
constructor(parent: SdkObject, requestContext: APIRequestContext) {
|
||||
|
|
@ -63,10 +62,6 @@ export class MockingProxy extends SdkObject implements RequestContext {
|
|||
return this._httpServer.port();
|
||||
}
|
||||
|
||||
setInterceptionPatterns(matches?: (url: string) => boolean) {
|
||||
this._matches = matches;
|
||||
}
|
||||
|
||||
private async _proxy(req: http.IncomingMessage, res: http.ServerResponse) {
|
||||
if (req.url?.startsWith('/'))
|
||||
req.url = req.url.substring(1);
|
||||
|
|
@ -212,14 +207,7 @@ export class MockingProxy extends SdkObject implements RequestContext {
|
|||
},
|
||||
});
|
||||
|
||||
if (!correlation)
|
||||
return await route.continue({ isFallback: false });
|
||||
|
||||
|
||||
if (this._matches?.(req.url!))
|
||||
this.emit(MockingProxy.Events.Route, route);
|
||||
else
|
||||
await route.continue({ isFallback: false });
|
||||
this.emit(MockingProxy.Events.Route, route);
|
||||
}
|
||||
|
||||
addRouteInFlight(route: Route): void {
|
||||
|
|
@ -258,7 +246,7 @@ async function collectBody(req: http.IncomingMessage) {
|
|||
}
|
||||
|
||||
export class WorkerHttpServer extends HttpServer {
|
||||
override _handleCORS(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
||||
override handleCORS(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -213,7 +213,7 @@ export class HttpServer {
|
|||
readable.pipe(response);
|
||||
}
|
||||
|
||||
_handleCORS(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
||||
handleCORS(request: http.IncomingMessage, response: http.ServerResponse): boolean {
|
||||
if (request.method === 'OPTIONS') {
|
||||
response.writeHead(200);
|
||||
response.end();
|
||||
|
|
@ -224,7 +224,7 @@ export class HttpServer {
|
|||
}
|
||||
|
||||
private _onRequest(request: http.IncomingMessage, response: http.ServerResponse) {
|
||||
if (this._handleCORS(request, response))
|
||||
if (this.handleCORS(request, response))
|
||||
return;
|
||||
|
||||
request.on('error', () => response.end());
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import type { ApiCallData, ClientInstrumentation, ClientInstrumentationListener
|
|||
import type { MockingProxy } from '../../playwright-core/src/client/mockingProxy';
|
||||
import type { BrowserContext as BrowserContextImpl } from '../../playwright-core/src/client/browserContext';
|
||||
import { currentTestInfo } from './common/globals';
|
||||
import type { LocalUtils } from 'playwright-core/lib/client/localUtils';
|
||||
import type { Playwright as PlaywrightImpl } from 'playwright-core/lib/client/playwright';
|
||||
export { expect } from './matchers/expect';
|
||||
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
||||
|
||||
|
|
@ -127,9 +127,8 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
_mockingProxy: [async ({ mockingProxy: mockingProxyOption, playwright }, use) => {
|
||||
if (!mockingProxyOption)
|
||||
return await use(undefined);
|
||||
const localUtils: LocalUtils = (playwright as any)._connection.localUtils();
|
||||
const { mockingProxy } = await localUtils._channel.newMockingProxy({});
|
||||
await use((mockingProxy as any)._object);
|
||||
const mockingProxy = await (playwright as PlaywrightImpl)._startMockingProxy();
|
||||
await use(mockingProxy);
|
||||
}, { scope: 'worker', box: true }],
|
||||
|
||||
acceptDownloads: [({ contextOptions }, use) => use(contextOptions.acceptDownloads ?? true), { option: true }],
|
||||
|
|
|
|||
13
packages/protocol/src/channels.d.ts
vendored
13
packages/protocol/src/channels.d.ts
vendored
|
|
@ -589,7 +589,6 @@ export interface MockingProxyEventTarget {
|
|||
}
|
||||
export interface MockingProxyChannel extends MockingProxyEventTarget, EventTargetChannel {
|
||||
_type_MockingProxy: boolean;
|
||||
setInterceptionPatterns(params: MockingProxySetInterceptionPatternsParams, metadata?: CallMetadata): Promise<MockingProxySetInterceptionPatternsResult>;
|
||||
}
|
||||
export type MockingProxyRouteEvent = {
|
||||
route: RouteChannel,
|
||||
|
|
@ -610,19 +609,7 @@ export type MockingProxyRequestFinishedEvent = {
|
|||
};
|
||||
export type MockingProxyResponseEvent = {
|
||||
response: ResponseChannel,
|
||||
page?: PageChannel,
|
||||
};
|
||||
export type MockingProxySetInterceptionPatternsParams = {
|
||||
patterns: {
|
||||
glob?: string,
|
||||
regexSource?: string,
|
||||
regexFlags?: string,
|
||||
}[],
|
||||
};
|
||||
export type MockingProxySetInterceptionPatternsOptions = {
|
||||
|
||||
};
|
||||
export type MockingProxySetInterceptionPatternsResult = void;
|
||||
|
||||
export interface MockingProxyEvents {
|
||||
'route': MockingProxyRouteEvent;
|
||||
|
|
|
|||
|
|
@ -682,18 +682,6 @@ MockingProxy:
|
|||
port: number
|
||||
requestContext: APIRequestContext
|
||||
|
||||
commands:
|
||||
setInterceptionPatterns:
|
||||
parameters:
|
||||
patterns:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
glob: string?
|
||||
regexSource: string?
|
||||
regexFlags: string?
|
||||
|
||||
events:
|
||||
route:
|
||||
parameters:
|
||||
|
|
@ -719,7 +707,6 @@ MockingProxy:
|
|||
response:
|
||||
parameters:
|
||||
response: Response
|
||||
page: Page?
|
||||
|
||||
Root:
|
||||
type: interface
|
||||
|
|
|
|||
Loading…
Reference in a new issue