From 75a8ace20ebd6ddc11025680c63e52f2eaf43712 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 27 Jan 2025 16:53:48 +0100 Subject: [PATCH] add more events --- .../src/client/mockingProxy.ts | 24 ++++++++++++++++-- .../playwright-core/src/protocol/validator.ts | 17 +++++++++++++ .../dispatchers/mockingProxyDispatcher.ts | 9 ++++--- .../src/server/mockingProxy.ts | 4 +-- packages/protocol/src/channels.d.ts | 25 +++++++++++++++++++ packages/protocol/src/protocol.yml | 21 ++++++++++++++++ 6 files changed, 93 insertions(+), 7 deletions(-) diff --git a/packages/playwright-core/src/client/mockingProxy.ts b/packages/playwright-core/src/client/mockingProxy.ts index 19c639d625..5d21be65ee 100644 --- a/packages/playwright-core/src/client/mockingProxy.ts +++ b/packages/playwright-core/src/client/mockingProxy.ts @@ -30,15 +30,35 @@ export class MockingProxy extends ChannelOwner { this._channel.on('route', async (params: channels.MockingProxyRouteEvent) => { const route = network.Route.from(params.route); route._context = requestContext; + this.emit(Events.MockingProxy.Route, route); + }); + this._channel.on('request', async (params: channels.MockingProxyRequestEvent) => { + const request = network.Request.from(params.request); if (params.correlation) { const browserRequest = this._browserRequests.get(params.correlation); this._browserRequests.delete(params.correlation); assert(browserRequest); - route.request()._frame = browserRequest._frame; + request._frame = browserRequest._frame; } + }); - this.emit(Events.MockingProxy.Route, route); + this._channel.on('requestFailed', async (params: channels.MockingProxyRequestFailedEvent) => { + const request = network.Request.from(params.request); + request._failureText = params.failureText ?? null; + request._setResponseEndTiming(params.responseEndTiming); + }); + + 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); + }); + + this._channel.on('response', async (params: channels.MockingProxyResponseEvent) => { + // no-op }); } diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 950e2c0ac8..604b8ea50f 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -348,8 +348,25 @@ scheme.MockingProxyInitializer = tObject({ }); scheme.MockingProxyRouteEvent = tObject({ route: tChannel(['Route']), +}); +scheme.MockingProxyRequestEvent = tObject({ + request: tChannel(['Request']), correlation: tOptional(tString), }); +scheme.MockingProxyRequestFailedEvent = tObject({ + request: tChannel(['Request']), + failureText: tOptional(tString), + responseEndTiming: tNumber, +}); +scheme.MockingProxyRequestFinishedEvent = tObject({ + request: tChannel(['Request']), + response: tOptional(tChannel(['Response'])), + responseEndTiming: tNumber, +}); +scheme.MockingProxyResponseEvent = tObject({ + response: tChannel(['Response']), + page: tOptional(tChannel(['Page'])), +}); scheme.MockingProxySetInterceptionPatternsParams = tObject({ patterns: tArray(tObject({ glob: tOptional(tString), diff --git a/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts b/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts index b755605436..b9895459dc 100644 --- a/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts @@ -19,7 +19,7 @@ import type { RootDispatcher } from './dispatcher'; import { Dispatcher, existingDispatcher } from './dispatcher'; import type * as channels from '@protocol/channels'; import { APIRequestContextDispatcher, RequestDispatcher, RouteDispatcher } from './networkDispatchers'; -import type { Route } from '../network'; +import type { Request, Route } from '../network'; import { urlMatches } from '../../utils/isomorphic/urlMatch'; export class MockingProxyDispatcher extends Dispatcher implements channels.MockingProxyChannel { @@ -36,9 +36,12 @@ export class MockingProxyDispatcher extends Dispatcher { + this.addObjectListener(MockingProxy.Events.Route, (route: Route) => { const requestDispatcher = RequestDispatcher.from(this as any, route.request()); - this._dispatchEvent('route', { route: RouteDispatcher.from(requestDispatcher, route), correlation }); + this._dispatchEvent('route', { route: RouteDispatcher.from(requestDispatcher, route) }); + }); + this.addObjectListener(MockingProxy.Events.Request, ({ request, correlation }: { request: Request, correlation?: string }) => { + this._dispatchEvent('request', { request: RequestDispatcher.from(this as any, request), correlation }); }); } diff --git a/packages/playwright-core/src/server/mockingProxy.ts b/packages/playwright-core/src/server/mockingProxy.ts index be033a4e41..6a59f2bff5 100644 --- a/packages/playwright-core/src/server/mockingProxy.ts +++ b/packages/playwright-core/src/server/mockingProxy.ts @@ -87,7 +87,7 @@ export class MockingProxy extends SdkObject implements RequestContext { const body = await collectBody(req); const request = new Request(this, null, null, null, undefined, req.url!, '', req.method!, body, headers); request.setRawRequestHeaders(headers); - this.emit(MockingProxy.Events.Request, request); + this.emit(MockingProxy.Events.Request, { request, correlation }); const route = new Route(request, { abort: async errorCode => { @@ -209,7 +209,7 @@ export class MockingProxy extends SdkObject implements RequestContext { }); if (this._matches?.(req.url!)) - this.emit(MockingProxy.Events.Route, { route, correlation }); + this.emit(MockingProxy.Events.Route, route); else await route.continue({ isFallback: false }); } diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index 90385c1651..a6ae5d8cd5 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -586,6 +586,10 @@ export type MockingProxyInitializer = { }; export interface MockingProxyEventTarget { on(event: 'route', callback: (params: MockingProxyRouteEvent) => void): this; + on(event: 'request', callback: (params: MockingProxyRequestEvent) => void): this; + on(event: 'requestFailed', callback: (params: MockingProxyRequestFailedEvent) => void): this; + on(event: 'requestFinished', callback: (params: MockingProxyRequestFinishedEvent) => void): this; + on(event: 'response', callback: (params: MockingProxyResponseEvent) => void): this; } export interface MockingProxyChannel extends MockingProxyEventTarget, EventTargetChannel { _type_MockingProxy: boolean; @@ -593,8 +597,25 @@ export interface MockingProxyChannel extends MockingProxyEventTarget, EventTarge } export type MockingProxyRouteEvent = { route: RouteChannel, +}; +export type MockingProxyRequestEvent = { + request: RequestChannel, correlation?: string, }; +export type MockingProxyRequestFailedEvent = { + request: RequestChannel, + failureText?: string, + responseEndTiming: number, +}; +export type MockingProxyRequestFinishedEvent = { + request: RequestChannel, + response?: ResponseChannel, + responseEndTiming: number, +}; +export type MockingProxyResponseEvent = { + response: ResponseChannel, + page?: PageChannel, +}; export type MockingProxySetInterceptionPatternsParams = { patterns: { glob?: string, @@ -609,6 +630,10 @@ export type MockingProxySetInterceptionPatternsResult = void; export interface MockingProxyEvents { 'route': MockingProxyRouteEvent; + 'request': MockingProxyRequestEvent; + 'requestFailed': MockingProxyRequestFailedEvent; + 'requestFinished': MockingProxyRequestFinishedEvent; + 'response': MockingProxyResponseEvent; } // ----------- Root ----------- diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index 1b53096c96..f908389428 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -700,8 +700,29 @@ MockingProxy: route: parameters: route: Route + + request: + parameters: + request: Request correlation: string? + requestFailed: + parameters: + request: Request + failureText: string? + responseEndTiming: number + + requestFinished: + parameters: + request: Request + response: Response? + responseEndTiming: number + + response: + parameters: + response: Response + page: Page? + Root: type: interface