From 72bdd43e699cb2228e0a4195c9a31ede68da6b0b Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Mon, 21 Aug 2023 16:48:51 -0700 Subject: [PATCH] fix(route): make sure Route.fetch works for popup main request (#26590) References #24603. --- .../playwright-core/src/client/browserContext.ts | 1 + packages/playwright-core/src/client/network.ts | 10 +++------- packages/playwright-core/src/client/page.ts | 1 + .../src/server/dispatchers/networkDispatchers.ts | 5 +---- tests/page/page-event-popup.spec.ts | 1 + tests/page/page-request-intercept.spec.ts | 16 ++++++++++++++++ 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 3fee5a1dc2..036f6a70e2 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -190,6 +190,7 @@ export class BrowserContext extends ChannelOwner } async _onRoute(route: network.Route) { + route._context = this; const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { if (!routeHandler.matches(route.request().url())) diff --git a/packages/playwright-core/src/client/network.ts b/packages/playwright-core/src/client/network.ts index 376d4bec4b..83e87f4cb3 100644 --- a/packages/playwright-core/src/client/network.ts +++ b/packages/playwright-core/src/client/network.ts @@ -33,6 +33,7 @@ import { urlMatches } from '../utils/network'; import { MultiMap } from '../utils/multimap'; import { APIResponse } from './fetch'; import type { Serializable } from '../../types/structs'; +import type { BrowserContext } from './browserContext'; export type NetworkCookie = { name: string, @@ -158,11 +159,6 @@ export class Request extends ChannelOwner implements ap return this._provisionalHeaders.headers(); } - _context() { - // TODO: make sure this works for service worker requests. - return this.frame().page().context(); - } - _actualHeaders(): Promise { if (this._fallbackOverrides.headers) return Promise.resolve(RawHeaders._fromHeadersObjectLossy(this._fallbackOverrides.headers)); @@ -277,6 +273,7 @@ export class Request extends ChannelOwner implements ap export class Route extends ChannelOwner implements api.Route { private _handlingPromise: ManualPromise | null = null; + _context!: BrowserContext; static from(route: channels.RouteChannel): Route { return (route as any)._object; @@ -322,8 +319,7 @@ export class Route extends ChannelOwner implements api.Ro async fetch(options: FallbackOverrides & { maxRedirects?: number, timeout?: number } = {}): Promise { return await this._wrapApiCall(async () => { - const context = this.request()._context(); - return context.request._innerFetch({ request: this.request(), data: options.postData, ...options }); + return this._context.request._innerFetch({ request: this.request(), data: options.postData, ...options }); }); } diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index 0d2a0e98e5..b963ab484d 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -171,6 +171,7 @@ export class Page extends ChannelOwner implements api.Page } private async _onRoute(route: Route) { + route._context = this.context(); const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { if (!routeHandler.matches(route.request().url())) diff --git a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts index 428782b883..78d862bc8d 100644 --- a/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts +++ b/packages/playwright-core/src/server/dispatchers/networkDispatchers.ts @@ -128,13 +128,12 @@ export class RouteDispatcher extends Dispatcher { - // Used to discriminate between continue in tracing. await this._object.continue({ url: params.url, method: params.method, @@ -145,12 +144,10 @@ export class RouteDispatcher extends Dispatcher { - // Used to discriminate between fulfills in tracing. await this._object.fulfill(params); } async abort(params: channels.RouteAbortParams, metadata: CallMetadata): Promise { - // Used to discriminate between abort in tracing. await this._object.abort(params.errorCode || 'failed'); } diff --git a/tests/page/page-event-popup.spec.ts b/tests/page/page-event-popup.spec.ts index c8330f2254..07b203709a 100644 --- a/tests/page/page-event-popup.spec.ts +++ b/tests/page/page-event-popup.spec.ts @@ -121,6 +121,7 @@ it('should work with clicking target=_blank', async ({ page, server }) => { ]); expect(await page.evaluate(() => !!window.opener)).toBe(false); expect(await popup.evaluate(() => !!window.opener)).toBe(true); + expect(popup.mainFrame().page()).toBe(popup); }); it('should work with fake-clicking target=_blank and rel=noopener', async ({ page, server }) => { diff --git a/tests/page/page-request-intercept.spec.ts b/tests/page/page-request-intercept.spec.ts index 5b3a7a6b8d..024919c898 100644 --- a/tests/page/page-request-intercept.spec.ts +++ b/tests/page/page-request-intercept.spec.ts @@ -265,3 +265,19 @@ it('should intercept with post data override', async ({ page, server, isElectron const request = await requestPromise; expect((await request.postBody).toString()).toBe(JSON.stringify({ 'foo': 'bar' })); }); + +it('should fulfill popup main request using alias', async ({ page, server, isElectron, isAndroid }) => { + it.fixme(isElectron, 'error: Browser context management is not supported.'); + it.skip(isAndroid, 'The internal Android localhost (10.0.0.2) != the localhost on the host'); + + await page.context().route('**/*', async route => { + const response = await route.fetch(); + await route.fulfill({ response, body: 'hello' }); + }); + await page.setContent(`click me`); + const [popup] = await Promise.all([ + page.waitForEvent('popup'), + page.getByText('click me').click(), + ]); + await expect(popup.locator('body')).toHaveText('hello'); +});