diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index 5c45e564fd..be6de760a9 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -145,8 +145,10 @@ export class BrowserContext extends ChannelOwner } async _onRoute(route: network.Route, request: network.Request) { - const routeHandlers = this._routes.filter(r => r.matches(request.url())); + const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { + if (!routeHandler.matches(request.url())) + continue; if (routeHandler.willExpire()) this._routes.splice(this._routes.indexOf(routeHandler), 1); const handled = await routeHandler.handle(route, request); diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index 12688638cb..fd4283b18d 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -179,8 +179,10 @@ export class Page extends ChannelOwner implements api.Page } private async _onRoute(route: Route, request: Request) { - const routeHandlers = this._routes.filter(r => r.matches(request.url())); + const routeHandlers = this._routes.slice(); for (const routeHandler of routeHandlers) { + if (!routeHandler.matches(request.url())) + continue; if (routeHandler.willExpire()) this._routes.splice(this._routes.indexOf(routeHandler), 1); const handled = await routeHandler.handle(route, request); diff --git a/tests/library/browsercontext-route.spec.ts b/tests/library/browsercontext-route.spec.ts index 80e0f7a020..148289e622 100644 --- a/tests/library/browsercontext-route.spec.ts +++ b/tests/library/browsercontext-route.spec.ts @@ -268,6 +268,26 @@ it('should chain fallback', async ({ context, page, server }) => { expect(intercepted).toEqual([3, 2, 1]); }); +it('should chain fallback w/ dynamic URL', async ({ context, page, server }) => { + const intercepted = []; + await context.route('**/bar', route => { + intercepted.push(1); + route.fallback({ url: server.EMPTY_PAGE }); + }); + await context.route('**/foo', route => { + intercepted.push(2); + route.fallback({ url: 'http://localhost/bar' }); + }); + + await context.route('**/empty.html', route => { + intercepted.push(3); + route.fallback({ url: 'http://localhost/foo' }); + }); + + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual([3, 2, 1]); +}); + it('should not chain fulfill', async ({ context, page, server }) => { let failed = false; await context.route('**/empty.html', route => { diff --git a/tests/page/page-request-fallback.spec.ts b/tests/page/page-request-fallback.spec.ts index 2e4093c641..30d141fe6d 100644 --- a/tests/page/page-request-fallback.spec.ts +++ b/tests/page/page-request-fallback.spec.ts @@ -205,7 +205,7 @@ it('should override request url', async ({ page, server }) => { const request = server.waitForRequest('/global-var.html'); let url: string; - await page.route('**/foo', route => { + await page.route('**/global-var.html', route => { url = route.request().url(); route.continue(); }); diff --git a/tests/page/page-route.spec.ts b/tests/page/page-route.spec.ts index 4a481b4d21..95ada83008 100644 --- a/tests/page/page-route.spec.ts +++ b/tests/page/page-route.spec.ts @@ -321,6 +321,26 @@ it('should not work with redirects', async ({ page, server }) => { expect(chain[i].redirectedTo()).toBe(i ? chain[i - 1] : null); }); +it('should chain fallback w/ dynamic URL', async ({ page, server }) => { + const intercepted = []; + await page.route('**/bar', route => { + intercepted.push(1); + route.fallback({ url: server.EMPTY_PAGE }); + }); + await page.route('**/foo', route => { + intercepted.push(2); + route.fallback({ url: 'http://localhost/bar' }); + }); + + await page.route('**/empty.html', route => { + intercepted.push(3); + route.fallback({ url: 'http://localhost/foo' }); + }); + + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual([3, 2, 1]); +}); + it('should work with redirects for subresources', async ({ page, server }) => { const intercepted = []; await page.route('**/*', route => {