mirror of
https://github.com/microsoft/playwright.git
synced 2024-11-30 23:45:33 +03:00
fix(route): make sure Route.fetch works for popup main request (#26590)
References #24603.
This commit is contained in:
parent
c3c3c7f53c
commit
72bdd43e69
@ -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()))
|
||||
|
@ -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<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));
|
||||
@ -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;
|
||||
@ -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 });
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -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()))
|
||||
|
@ -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,
|
||||
@ -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');
|
||||
}
|
||||
|
||||
|
@ -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 }) => {
|
||||
|
@ -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');
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user