From 8db16b2e6b2a2f1f9839d1367249c8dd5c9d2390 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Mon, 27 Jan 2025 16:44:08 +0100 Subject: [PATCH] set frame from outside --- .../playwright-core/src/client/browserContext.ts | 4 ++-- packages/playwright-core/src/client/events.ts | 2 +- .../playwright-core/src/client/mockingProxy.ts | 14 +++++++++++--- packages/playwright-core/src/client/network.ts | 11 ++++++----- .../playwright.mockingproxy.spec.ts | 4 ++-- 5 files changed, 22 insertions(+), 13 deletions(-) diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index f11096217b..73743ea21d 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -228,9 +228,9 @@ export class BrowserContext extends ChannelOwner await route._innerContinue(true /* isFallback */).catch(() => {}); } - private _onRouteListener = ({ route, browserRequest }: { route: network.Route, browserRequest?: network.Request }) => { + private _onRouteListener = (route: network.Route) => { const subject = - browserRequest?._safePage() + route.request()._safePage() ?? this.pages()[0] // Fallback to the first page if no page is associated with the request. This should be the `page` fixture. ?? this; subject._onRoute(route); diff --git a/packages/playwright-core/src/client/events.ts b/packages/playwright-core/src/client/events.ts index 2154e85e2c..3bf4040ad3 100644 --- a/packages/playwright-core/src/client/events.ts +++ b/packages/playwright-core/src/client/events.ts @@ -96,6 +96,6 @@ export const Events = { }, MockingProxy: { - Route: 'rooute', + Route: 'route', }, }; diff --git a/packages/playwright-core/src/client/mockingProxy.ts b/packages/playwright-core/src/client/mockingProxy.ts index 44240a7c6b..19c639d625 100644 --- a/packages/playwright-core/src/client/mockingProxy.ts +++ b/packages/playwright-core/src/client/mockingProxy.ts @@ -18,6 +18,7 @@ import type * as channels from '@protocol/channels'; import { ChannelOwner } from './channelOwner'; import { APIRequestContext } from './fetch'; import { Events } from './events'; +import { assert } from '../utils'; export class MockingProxy extends ChannelOwner { private _browserRequests = new Map(); @@ -30,13 +31,14 @@ export class MockingProxy extends ChannelOwner { const route = network.Route.from(params.route); route._context = requestContext; - let browserRequest: network.Request | undefined; if (params.correlation) { - browserRequest = this._browserRequests.get(params.correlation); + const browserRequest = this._browserRequests.get(params.correlation); this._browserRequests.delete(params.correlation); + assert(browserRequest); + route.request()._frame = browserRequest._frame; } - this.emit(Events.MockingProxy.Route, { route, browserRequest }); + this.emit(Events.MockingProxy.Route, route); }); } @@ -52,6 +54,12 @@ export class MockingProxy extends ChannelOwner { const request = route.request(); const correlation = request._guid.split('@')[1]; this._browserRequests.set(correlation, request); + + void request.response() + .then(response => response?.finished()) + .catch(() => {}) + .finally(() => this._browserRequests.delete(correlation)); + const proxyUrl = `http://localhost:${this.port()}/pw_meta:${correlation}/`; await route.fallback({ headers: { 'x-playwright-proxy': encodeURIComponent(proxyUrl) } }); diff --git a/packages/playwright-core/src/client/network.ts b/packages/playwright-core/src/client/network.ts index a349d5711b..831dcadc60 100644 --- a/packages/playwright-core/src/client/network.ts +++ b/packages/playwright-core/src/client/network.ts @@ -86,6 +86,7 @@ export class Request extends ChannelOwner implements ap private _actualHeadersPromise: Promise | undefined; _timing: ResourceTiming; private _fallbackOverrides: SerializedFallbackOverrides = {}; + _frame: Frame | null = null; static from(request: channels.RequestChannel): Request { return (request as any)._object; @@ -102,6 +103,7 @@ export class Request extends ChannelOwner implements ap if (this._redirectedFrom) this._redirectedFrom._redirectedTo = this; this._provisionalHeaders = new RawHeaders(initializer.headers); + this._frame = Frame.fromNullable(initializer.frame); this._timing = { startTime: 0, domainLookupStart: -1, @@ -200,23 +202,22 @@ export class Request extends ChannelOwner implements ap } frame(): Frame { - if (!this._initializer.frame) { + if (!this._frame) { assert(this.serviceWorker()); throw new Error('Service Worker requests do not have an associated frame.'); } - const frame = Frame.from(this._initializer.frame); - if (!frame._page) { + if (!this._frame._page) { throw new Error([ 'Frame for this navigation request is not available, because the request', 'was issued before the frame is created. You can check whether the request', 'is a navigation request by calling isNavigationRequest() method.', ].join('\n')); } - return frame; + return this._frame; } _safePage(): Page | null { - return Frame.fromNullable(this._initializer.frame)?._page || null; + return this._frame?._page || null; } serviceWorker(): Worker | null { diff --git a/tests/playwright-test/playwright.mockingproxy.spec.ts b/tests/playwright-test/playwright.mockingproxy.spec.ts index 0449772708..7ec80d672a 100644 --- a/tests/playwright-test/playwright.mockingproxy.spec.ts +++ b/tests/playwright-test/playwright.mockingproxy.spec.ts @@ -137,8 +137,8 @@ test('all properties are populated', async ({ runInlineTest, server, request }) // TODO: implement, this currently blocks because requestFinished isn't emitted // expect(await response.finished()).toBe(null); expect(request.serviceWorker()).toBe(null); - expect(() => request.frame()).toThrowError('Assertion error'); // TODO: improve error message - expect(() => response.frame()).toThrowError('Assertion error'); + expect(request.frame()).not.toBe(null); + expect(response.frame()).not.toBe(null); expect(request.failure()).toBe(null); expect(request.isNavigationRequest()).toBe(false);