diff --git a/packages/playwright-core/src/protocol/debug.ts b/packages/playwright-core/src/protocol/debug.ts index e5b2dc2758..176864f4f5 100644 --- a/packages/playwright-core/src/protocol/debug.ts +++ b/packages/playwright-core/src/protocol/debug.ts @@ -67,6 +67,7 @@ export const slowMoActions = new Set([ export const commandsWithTracingSnapshots = new Set([ 'EventTarget.waitForEventInfo', 'LocalUtils.waitForEventInfo', + 'MockingProxy.waitForEventInfo', 'BrowserContext.waitForEventInfo', 'Page.waitForEventInfo', 'WebSocket.waitForEventInfo', diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index 3d2f551d06..661c4fc9d8 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -237,6 +237,7 @@ scheme.EventTargetWaitForEventInfoParams = tObject({ }), }); scheme.LocalUtilsWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); +scheme.MockingProxyWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); scheme.BrowserContextWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); scheme.PageWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); scheme.WebSocketWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); @@ -244,6 +245,7 @@ scheme.ElectronApplicationWaitForEventInfoParams = tType('EventTargetWaitForEven scheme.AndroidDeviceWaitForEventInfoParams = tType('EventTargetWaitForEventInfoParams'); scheme.EventTargetWaitForEventInfoResult = tOptional(tObject({})); scheme.LocalUtilsWaitForEventInfoResult = tType('EventTargetWaitForEventInfoResult'); +scheme.MockingProxyWaitForEventInfoResult = tType('EventTargetWaitForEventInfoResult'); scheme.BrowserContextWaitForEventInfoResult = tType('EventTargetWaitForEventInfoResult'); scheme.PageWaitForEventInfoResult = tType('EventTargetWaitForEventInfoResult'); scheme.WebSocketWaitForEventInfoResult = tType('EventTargetWaitForEventInfoResult'); @@ -268,27 +270,6 @@ scheme.LocalUtilsInitializer = tObject({ defaultBrowserType: tEnum(['chromium', 'firefox', 'webkit']), }), })), - requestContext: tChannel(['APIRequestContext']), -}); -scheme.LocalUtilsRouteEvent = tObject({ - route: tChannel(['Route']), -}); -scheme.LocalUtilsRequestEvent = tObject({ - request: tChannel(['Request']), -}); -scheme.LocalUtilsResponseEvent = tObject({ - request: tChannel(['Request']), - response: tChannel(['Response']), -}); -scheme.LocalUtilsRequestFailedEvent = tObject({ - request: tChannel(['Request']), - failureText: tOptional(tString), - responseEndTiming: tNumber, -}); -scheme.LocalUtilsRequestFinishedEvent = tObject({ - request: tChannel(['Request']), - response: tOptional(tChannel(['Response'])), - responseEndTiming: tNumber, }); scheme.LocalUtilsZipParams = tObject({ zipFile: tString, @@ -357,15 +338,44 @@ scheme.LocalUtilsTraceDiscardedParams = tObject({ stacksId: tString, }); scheme.LocalUtilsTraceDiscardedResult = tOptional(tObject({})); -scheme.LocalUtilsSetServerNetworkInterceptionPatternsParams = tObject({ +scheme.LocalUtilsNewMockingProxyParams = tObject({ + port: tOptional(tNumber), +}); +scheme.LocalUtilsNewMockingProxyResult = tObject({ + mockingProxy: tChannel(['MockingProxy']), +}); +scheme.MockingProxyInitializer = tObject({ port: tNumber, + requestContext: tChannel(['APIRequestContext']), +}); +scheme.MockingProxyRouteEvent = tObject({ + route: tChannel(['Route']), +}); +scheme.MockingProxyRequestEvent = tObject({ + request: tChannel(['Request']), +}); +scheme.MockingProxyResponseEvent = tObject({ + request: tChannel(['Request']), + response: tChannel(['Response']), +}); +scheme.MockingProxyRequestFailedEvent = tObject({ + request: tChannel(['Request']), + failureText: tOptional(tString), + responseEndTiming: tNumber, +}); +scheme.MockingProxyRequestFinishedEvent = tObject({ + request: tChannel(['Request']), + response: tOptional(tChannel(['Response'])), + responseEndTiming: tNumber, +}); +scheme.MockingProxySetInterceptionPatternsParams = tObject({ patterns: tArray(tObject({ glob: tOptional(tString), regexSource: tOptional(tString), regexFlags: tOptional(tString), })), }); -scheme.LocalUtilsSetServerNetworkInterceptionPatternsResult = tOptional(tObject({})); +scheme.MockingProxySetInterceptionPatternsResult = tOptional(tObject({})); scheme.RootInitializer = tOptional(tObject({})); scheme.RootInitializeParams = tObject({ sdkLanguage: tEnum(['javascript', 'python', 'java', 'csharp']), diff --git a/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts b/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts index 0ef2f3c0e4..8a4af139af 100644 --- a/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts +++ b/packages/playwright-core/src/server/dispatchers/localUtilsDispatcher.ts @@ -44,7 +44,7 @@ import { deviceDescriptors as descriptors } from '../deviceDescriptors'; import { APIRequestContextDispatcher, RequestDispatcher, ResponseDispatcher, RouteDispatcher } from './networkDispatchers'; import type { APIRequestContext } from '../fetch'; import { GlobalAPIRequestContext } from '../fetch'; -import { MockingProxy, ServerInterceptionRegistry } from './mockingProxy'; +import { MockingProxy, ServerInterceptionRegistry } from '../mockingProxy'; export class LocalUtilsDispatcher extends Dispatcher implements channels.LocalUtilsChannel { _type_LocalUtils: boolean; diff --git a/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts b/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts new file mode 100644 index 0000000000..6bcef53e84 --- /dev/null +++ b/packages/playwright-core/src/server/dispatchers/mockingProxyDispatcher.ts @@ -0,0 +1,40 @@ +/** + * 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 type { CallMetadata } from '@protocol/callMetadata'; +import type { MockingProxy, ServerInterceptionRegistry } from '../mockingProxy'; +import type { RootDispatcher } from './dispatcher'; +import { Dispatcher, existingDispatcher } from './dispatcher'; +import type * as channels from '@protocol/channels'; +import { SdkObject } from '../instrumentation'; + +export class MockingProxyDispatcher extends Dispatcher implements channels.MockingProxyChannel { + _type_MockingProxy = true; + _type_EventTarget = true; + + static from(scope: RootDispatcher, mockingProxy: ServerInterceptionRegistry): MockingProxyDispatcher { + return existingDispatcher(mockingProxy) || new MockingProxyDispatcher(scope, mockingProxy); + } + + private constructor(scope: RootDispatcher, mockingProxy: ServerInterceptionRegistry) { + super(scope, mockingProxy, 'MockingProxy', { + port: mockingProxy.port(), + }); + } + + setInterceptionPatterns(params: channels.MockingProxySetInterceptionPatternsParams, metadata?: CallMetadata): Promise { + throw new Error('Method not implemented.'); + } +} diff --git a/packages/playwright-core/src/server/dispatchers/mockingProxy.ts b/packages/playwright-core/src/server/mockingProxy.ts similarity index 97% rename from packages/playwright-core/src/server/dispatchers/mockingProxy.ts rename to packages/playwright-core/src/server/mockingProxy.ts index 0cd2f73a16..108b75c05f 100644 --- a/packages/playwright-core/src/server/dispatchers/mockingProxy.ts +++ b/packages/playwright-core/src/server/mockingProxy.ts @@ -17,13 +17,13 @@ import http from 'http'; import https from 'https'; import url from 'url'; -import type { APIRequestContext } from '../fetch'; -import { SdkObject } from '../instrumentation'; -import type { RemoteAddr, RequestContext, ResourceTiming, SecurityDetails } from '../network'; -import { Request, Response, Route } from '../network'; -import type { HeadersArray, NormalizedContinueOverrides, NormalizedFulfillResponse } from '../types'; +import type { APIRequestContext } from './fetch'; +import { SdkObject } from './instrumentation'; +import type { RemoteAddr, RequestContext, ResourceTiming, SecurityDetails } from './network'; +import { Request, Response, Route } from './network'; +import type { HeadersArray, NormalizedContinueOverrides, NormalizedFulfillResponse } from './types'; import { ManualPromise, monotonicTime } from 'playwright-core/lib/utils'; -import type { WorkerHttpServer } from './localUtilsDispatcher'; +import type { WorkerHttpServer } from './dispatchers/localUtilsDispatcher'; import { TLSSocket } from 'tls'; import type { AddressInfo } from 'net'; import { pipeline } from 'stream/promises'; diff --git a/packages/protocol/src/channels.d.ts b/packages/protocol/src/channels.d.ts index b28d3385b9..a7afad3639 100644 --- a/packages/protocol/src/channels.d.ts +++ b/packages/protocol/src/channels.d.ts @@ -56,6 +56,7 @@ export type InitializerTraits = T extends DebugControllerChannel ? DebugControllerInitializer : T extends PlaywrightChannel ? PlaywrightInitializer : T extends RootChannel ? RootInitializer : + T extends MockingProxyChannel ? MockingProxyInitializer : T extends LocalUtilsChannel ? LocalUtilsInitializer : T extends EventTargetChannel ? EventTargetInitializer : T extends APIRequestContextChannel ? APIRequestContextInitializer : @@ -94,6 +95,7 @@ export type EventsTraits = T extends DebugControllerChannel ? DebugControllerEvents : T extends PlaywrightChannel ? PlaywrightEvents : T extends RootChannel ? RootEvents : + T extends MockingProxyChannel ? MockingProxyEvents : T extends LocalUtilsChannel ? LocalUtilsEvents : T extends EventTargetChannel ? EventTargetEvents : T extends APIRequestContextChannel ? APIRequestContextEvents : @@ -132,6 +134,7 @@ export type EventTargetTraits = T extends DebugControllerChannel ? DebugControllerEventTarget : T extends PlaywrightChannel ? PlaywrightEventTarget : T extends RootChannel ? RootEventTarget : + T extends MockingProxyChannel ? MockingProxyEventTarget : T extends LocalUtilsChannel ? LocalUtilsEventTarget : T extends EventTargetChannel ? EventTargetEventTarget : T extends APIRequestContextChannel ? APIRequestContextEventTarget : @@ -449,14 +452,8 @@ export type LocalUtilsInitializer = { defaultBrowserType: 'chromium' | 'firefox' | 'webkit', }, }[], - requestContext: APIRequestContextChannel, }; export interface LocalUtilsEventTarget { - on(event: 'route', callback: (params: LocalUtilsRouteEvent) => void): this; - on(event: 'request', callback: (params: LocalUtilsRequestEvent) => void): this; - on(event: 'response', callback: (params: LocalUtilsResponseEvent) => void): this; - on(event: 'requestFailed', callback: (params: LocalUtilsRequestFailedEvent) => void): this; - on(event: 'requestFinished', callback: (params: LocalUtilsRequestFinishedEvent) => void): this; } export interface LocalUtilsChannel extends LocalUtilsEventTarget, EventTargetChannel { _type_LocalUtils: boolean; @@ -469,28 +466,8 @@ export interface LocalUtilsChannel extends LocalUtilsEventTarget, EventTargetCha tracingStarted(params: LocalUtilsTracingStartedParams, metadata?: CallMetadata): Promise; addStackToTracingNoReply(params: LocalUtilsAddStackToTracingNoReplyParams, metadata?: CallMetadata): Promise; traceDiscarded(params: LocalUtilsTraceDiscardedParams, metadata?: CallMetadata): Promise; - setServerNetworkInterceptionPatterns(params: LocalUtilsSetServerNetworkInterceptionPatternsParams, metadata?: CallMetadata): Promise; + newMockingProxy(params: LocalUtilsNewMockingProxyParams, metadata?: CallMetadata): Promise; } -export type LocalUtilsRouteEvent = { - route: RouteChannel, -}; -export type LocalUtilsRequestEvent = { - request: RequestChannel, -}; -export type LocalUtilsResponseEvent = { - request: RequestChannel, - response: ResponseChannel, -}; -export type LocalUtilsRequestFailedEvent = { - request: RequestChannel, - failureText?: string, - responseEndTiming: number, -}; -export type LocalUtilsRequestFinishedEvent = { - request: RequestChannel, - response?: ResponseChannel, - responseEndTiming: number, -}; export type LocalUtilsZipParams = { zipFile: string, entries: NameValue[], @@ -589,25 +566,73 @@ export type LocalUtilsTraceDiscardedOptions = { }; export type LocalUtilsTraceDiscardedResult = void; -export type LocalUtilsSetServerNetworkInterceptionPatternsParams = { +export type LocalUtilsNewMockingProxyParams = { + port?: number, +}; +export type LocalUtilsNewMockingProxyOptions = { + port?: number, +}; +export type LocalUtilsNewMockingProxyResult = { + mockingProxy: MockingProxyChannel, +}; + +export interface LocalUtilsEvents { +} + +// ----------- MockingProxy ----------- +export type MockingProxyInitializer = { port: number, + requestContext: APIRequestContextChannel, +}; +export interface MockingProxyEventTarget { + on(event: 'route', callback: (params: MockingProxyRouteEvent) => void): this; + on(event: 'request', callback: (params: MockingProxyRequestEvent) => void): this; + on(event: 'response', callback: (params: MockingProxyResponseEvent) => void): this; + on(event: 'requestFailed', callback: (params: MockingProxyRequestFailedEvent) => void): this; + on(event: 'requestFinished', callback: (params: MockingProxyRequestFinishedEvent) => void): this; +} +export interface MockingProxyChannel extends MockingProxyEventTarget, EventTargetChannel { + _type_MockingProxy: boolean; + setInterceptionPatterns(params: MockingProxySetInterceptionPatternsParams, metadata?: CallMetadata): Promise; +} +export type MockingProxyRouteEvent = { + route: RouteChannel, +}; +export type MockingProxyRequestEvent = { + request: RequestChannel, +}; +export type MockingProxyResponseEvent = { + request: RequestChannel, + response: ResponseChannel, +}; +export type MockingProxyRequestFailedEvent = { + request: RequestChannel, + failureText?: string, + responseEndTiming: number, +}; +export type MockingProxyRequestFinishedEvent = { + request: RequestChannel, + response?: ResponseChannel, + responseEndTiming: number, +}; +export type MockingProxySetInterceptionPatternsParams = { patterns: { glob?: string, regexSource?: string, regexFlags?: string, }[], }; -export type LocalUtilsSetServerNetworkInterceptionPatternsOptions = { +export type MockingProxySetInterceptionPatternsOptions = { }; -export type LocalUtilsSetServerNetworkInterceptionPatternsResult = void; +export type MockingProxySetInterceptionPatternsResult = void; -export interface LocalUtilsEvents { - 'route': LocalUtilsRouteEvent; - 'request': LocalUtilsRequestEvent; - 'response': LocalUtilsResponseEvent; - 'requestFailed': LocalUtilsRequestFailedEvent; - 'requestFinished': LocalUtilsRequestFinishedEvent; +export interface MockingProxyEvents { + 'route': MockingProxyRouteEvent; + 'request': MockingProxyRequestEvent; + 'response': MockingProxyResponseEvent; + 'requestFailed': MockingProxyRequestFailedEvent; + 'requestFinished': MockingProxyRequestFinishedEvent; } // ----------- Root ----------- diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index b0a0439420..629c5ce4f5 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -583,7 +583,6 @@ LocalUtils: - chromium - firefox - webkit - requestContext: APIRequestContext commands: @@ -671,10 +670,25 @@ LocalUtils: traceDiscarded: parameters: stacksId: string - - setServerNetworkInterceptionPatterns: + + newMockingProxy: + parameters: + port: number? + returns: + mockingProxy: MockingProxy + +MockingProxy: + type: interface + + extends: EventTarget + + initializer: + port: number + requestContext: APIRequestContext + + commands: + setInterceptionPatterns: parameters: - port: number patterns: type: array items: @@ -683,7 +697,7 @@ LocalUtils: glob: string? regexSource: string? regexFlags: string? - + events: route: parameters: