mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(route): support route w/ async handler & times (#14317)
This commit is contained in:
parent
abed166dd4
commit
a1324bd935
@ -145,19 +145,26 @@ export class BrowserContext extends ChannelOwner<channels.BrowserContextChannel>
|
|||||||
|
|
||||||
_onRoute(route: network.Route, request: network.Request) {
|
_onRoute(route: network.Route, request: network.Request) {
|
||||||
for (const routeHandler of this._routes) {
|
for (const routeHandler of this._routes) {
|
||||||
if (routeHandler.matches(request.url())) {
|
if (!routeHandler.matches(request.url()))
|
||||||
|
continue;
|
||||||
|
// Immediately deactivate based on |times|.
|
||||||
|
if (routeHandler.willExpire())
|
||||||
|
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
try {
|
try {
|
||||||
routeHandler.handle(route, request);
|
// Let async callback work prior to disabling interception.
|
||||||
|
await routeHandler.handle(route, request);
|
||||||
} finally {
|
} finally {
|
||||||
if (!routeHandler.isActive()) {
|
if (!this._routes.length)
|
||||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
await this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
||||||
if (!this._routes.length)
|
|
||||||
this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
})();
|
||||||
}
|
|
||||||
|
// There is no chaining, first handler wins.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// it can race with BrowserContext.close() which then throws since its closed
|
// it can race with BrowserContext.close() which then throws since its closed
|
||||||
route._internalContinue();
|
route._internalContinue();
|
||||||
}
|
}
|
||||||
|
@ -309,7 +309,7 @@ export class Route extends ChannelOwner<channels.RouteChannel> implements api.Ro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RouteHandlerCallback = (route: Route, request: Request) => void;
|
export type RouteHandlerCallback = (route: Route, request: Request) => void | Promise<void>;
|
||||||
|
|
||||||
export type ResourceTiming = {
|
export type ResourceTiming = {
|
||||||
startTime: number;
|
startTime: number;
|
||||||
@ -518,13 +518,13 @@ export class RouteHandler {
|
|||||||
return urlMatches(this._baseURL, requestURL, this.url);
|
return urlMatches(this._baseURL, requestURL, this.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
public handle(route: Route, request: Request): void {
|
public handle(route: Route, request: Request): Promise<void> | void {
|
||||||
++this.handledCount;
|
++this.handledCount;
|
||||||
this.handler(route, request);
|
return this.handler(route, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
public isActive(): boolean {
|
public willExpire(): boolean {
|
||||||
return this.handledCount < this._times;
|
return this.handledCount + 1 >= this._times;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,18 +180,24 @@ export class Page extends ChannelOwner<channels.PageChannel> implements api.Page
|
|||||||
|
|
||||||
private _onRoute(route: Route, request: Request) {
|
private _onRoute(route: Route, request: Request) {
|
||||||
for (const routeHandler of this._routes) {
|
for (const routeHandler of this._routes) {
|
||||||
if (routeHandler.matches(request.url())) {
|
if (!routeHandler.matches(request.url()))
|
||||||
|
continue;
|
||||||
|
// Immediately deactivate based on |times|.
|
||||||
|
if (routeHandler.willExpire())
|
||||||
|
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
||||||
|
|
||||||
|
(async () => {
|
||||||
try {
|
try {
|
||||||
routeHandler.handle(route, request);
|
// Let async callback work prior to disabling interception.
|
||||||
|
await routeHandler.handle(route, request);
|
||||||
} finally {
|
} finally {
|
||||||
if (!routeHandler.isActive()) {
|
if (!this._routes.length)
|
||||||
this._routes.splice(this._routes.indexOf(routeHandler), 1);
|
this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
||||||
if (!this._routes.length)
|
|
||||||
this._wrapApiCall(() => this._disableInterception(), true).catch(() => {});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
})();
|
||||||
}
|
|
||||||
|
// There is no chaining, first handler wins.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this._browserContext._onRoute(route, request);
|
this._browserContext._onRoute(route, request);
|
||||||
}
|
}
|
||||||
|
@ -211,6 +211,20 @@ it('should support the times parameter with route matching', async ({ context, p
|
|||||||
expect(intercepted).toHaveLength(1);
|
expect(intercepted).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support async handler w/ times', async ({ context, page, server }) => {
|
||||||
|
await context.route('**/empty.html', async route => {
|
||||||
|
await new Promise(f => setTimeout(f, 100));
|
||||||
|
route.fulfill({
|
||||||
|
body: '<html>intercepted</html>',
|
||||||
|
contentType: 'text/html'
|
||||||
|
});
|
||||||
|
}, { times: 1 });
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await expect(page.locator('body')).toHaveText('intercepted');
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await expect(page.locator('body')).not.toHaveText('intercepted');
|
||||||
|
});
|
||||||
|
|
||||||
it('should overwrite post body with empty string', async ({ context, server, page, browserName }) => {
|
it('should overwrite post body with empty string', async ({ context, server, page, browserName }) => {
|
||||||
await context.route('**/empty.html', route => {
|
await context.route('**/empty.html', route => {
|
||||||
route.continue({
|
route.continue({
|
||||||
|
@ -772,6 +772,20 @@ it('should support the times parameter with route matching', async ({ page, serv
|
|||||||
expect(intercepted).toHaveLength(1);
|
expect(intercepted).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support async handler w/ times', async ({ page, server }) => {
|
||||||
|
await page.route('**/empty.html', async route => {
|
||||||
|
await new Promise(f => setTimeout(f, 100));
|
||||||
|
route.fulfill({
|
||||||
|
body: '<html>intercepted</html>',
|
||||||
|
contentType: 'text/html'
|
||||||
|
});
|
||||||
|
}, { times: 1 });
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await expect(page.locator('body')).toHaveText('intercepted');
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await expect(page.locator('body')).not.toHaveText('intercepted');
|
||||||
|
});
|
||||||
|
|
||||||
it('should contain raw request header', async ({ page, server }) => {
|
it('should contain raw request header', async ({ page, server }) => {
|
||||||
let headers: any;
|
let headers: any;
|
||||||
await page.route('**/*', async route => {
|
await page.route('**/*', async route => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user