Skip to content

Commit

Permalink
fix(route): make sure Route.fetch works for popup main request (#26590)
Browse files Browse the repository at this point in the history
References #24603.
  • Loading branch information
dgozman committed Aug 21, 2023
1 parent c3c3c7f commit 72bdd43
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 11 deletions.
1 change: 1 addition & 0 deletions packages/playwright-core/src/client/browserContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
}

async _onRoute(route: network.Route) {
route._context = this;
const routeHandlers = this._routes.slice();
for (const routeHandler of routeHandlers) {
if (!routeHandler.matches(route.request().url()))
Expand Down
10 changes: 3 additions & 7 deletions packages/playwright-core/src/client/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -158,11 +159,6 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
return this._provisionalHeaders.headers();
}

_context() {
// TODO: make sure this works for service worker requests.
return this.frame().page().context();
}

_actualHeaders(): Promise<RawHeaders> {
if (this._fallbackOverrides.headers)
return Promise.resolve(RawHeaders._fromHeadersObjectLossy(this._fallbackOverrides.headers));
Expand Down Expand Up @@ -277,6 +273,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap

export class Route extends ChannelOwner<channels.RouteChannel> implements api.Route {
private _handlingPromise: ManualPromise<boolean> | null = null;
_context!: BrowserContext;

static from(route: channels.RouteChannel): Route {
return (route as any)._object;
Expand Down Expand Up @@ -322,8 +319,7 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro

async fetch(options: FallbackOverrides & { maxRedirects?: number, timeout?: number } = {}): Promise<APIResponse> {
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 });
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/playwright-core/src/client/page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ export class Page extends ChannelOwner<channels.PageChannel> 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()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,12 @@ export class RouteDispatcher extends Dispatcher<Route, channels.RouteChannel, Re

private constructor(scope: RequestDispatcher, route: Route) {
super(scope, route, 'Route', {
// Context route can point to a non-reported request.
// Context route can point to a non-reported request, so we send the request in the initializer.
request: scope
});
}

async continue(params: channels.RouteContinueParams, metadata: CallMetadata): Promise<channels.RouteContinueResult> {
// Used to discriminate between continue in tracing.
await this._object.continue({
url: params.url,
method: params.method,
Expand All @@ -145,12 +144,10 @@ export class RouteDispatcher extends Dispatcher<Route, channels.RouteChannel, Re
}

async fulfill(params: channels.RouteFulfillParams, metadata: CallMetadata): Promise<void> {
// Used to discriminate between fulfills in tracing.
await this._object.fulfill(params);
}

async abort(params: channels.RouteAbortParams, metadata: CallMetadata): Promise<void> {
// Used to discriminate between abort in tracing.
await this._object.abort(params.errorCode || 'failed');
}

Expand Down
1 change: 1 addition & 0 deletions tests/page/page-event-popup.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 }) => {
Expand Down
16 changes: 16 additions & 0 deletions tests/page/page-request-intercept.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(`<a target=_blank href="${server.EMPTY_PAGE}">click me</a>`);
const [popup] = await Promise.all([
page.waitForEvent('popup'),
page.getByText('click me').click(),
]);
await expect(popup.locator('body')).toHaveText('hello');
});

0 comments on commit 72bdd43

Please sign in to comment.