set frame from outside

This commit is contained in:
Simon Knott 2025-01-27 16:44:08 +01:00
parent 4a4d930de7
commit 8db16b2e6b
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
5 changed files with 22 additions and 13 deletions

View file

@ -228,9 +228,9 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
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);

View file

@ -96,6 +96,6 @@ export const Events = {
},
MockingProxy: {
Route: 'rooute',
Route: 'route',
},
};

View file

@ -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<channels.MockingProxyChannel> {
private _browserRequests = new Map<string, network.Request>();
@ -30,13 +31,14 @@ export class MockingProxy extends ChannelOwner<channels.MockingProxyChannel> {
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<channels.MockingProxyChannel> {
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) } });

View file

@ -86,6 +86,7 @@ export class Request extends ChannelOwner<channels.RequestChannel> implements ap
private _actualHeadersPromise: Promise<RawHeaders> | 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<channels.RequestChannel> 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<channels.RequestChannel> 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 {

View file

@ -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);