diff --git a/packages/playwright-core/src/client/browserContext.ts b/packages/playwright-core/src/client/browserContext.ts index a74996bbe2..8c6023a703 100644 --- a/packages/playwright-core/src/client/browserContext.ts +++ b/packages/playwright-core/src/client/browserContext.ts @@ -197,8 +197,11 @@ export class BrowserContext extends ChannelOwner for (const routeHandler of routeHandlers) { if (!routeHandler.matches(route.request().url())) continue; + const index = this._routes.indexOf(routeHandler); + if (index === -1) + continue; if (routeHandler.willExpire()) - this._routes.splice(this._routes.indexOf(routeHandler), 1); + this._routes.splice(index, 1); const handled = await routeHandler.handle(route); if (!this._routes.length) this._wrapApiCall(() => this._updateInterceptionPatterns(), true).catch(() => {}); diff --git a/packages/playwright-core/src/client/page.ts b/packages/playwright-core/src/client/page.ts index 0430e3c0bc..ac15fb4ffe 100644 --- a/packages/playwright-core/src/client/page.ts +++ b/packages/playwright-core/src/client/page.ts @@ -177,8 +177,11 @@ export class Page extends ChannelOwner implements api.Page for (const routeHandler of routeHandlers) { if (!routeHandler.matches(route.request().url())) continue; + const index = this._routes.indexOf(routeHandler); + if (index === -1) + continue; if (routeHandler.willExpire()) - this._routes.splice(this._routes.indexOf(routeHandler), 1); + this._routes.splice(index, 1); const handled = await routeHandler.handle(route); if (!this._routes.length) this._wrapApiCall(() => this._updateInterceptionPatterns(), true).catch(() => {}); diff --git a/tests/library/browsercontext-route.spec.ts b/tests/library/browsercontext-route.spec.ts index e600948216..a597cf1157 100644 --- a/tests/library/browsercontext-route.spec.ts +++ b/tests/library/browsercontext-route.spec.ts @@ -208,6 +208,25 @@ it('should support the times parameter with route matching', async ({ context, p expect(intercepted).toHaveLength(1); }); +it('should work if handler with times parameter was removed from another handler', async ({ context, page, server }) => { + const intercepted = []; + const handler = async route => { + intercepted.push('first'); + void route.continue(); + }; + await context.route('**/*', handler, { times: 1 }); + await context.route('**/*', async route => { + intercepted.push('second'); + await context.unroute('**/*', handler); + await route.fallback(); + }); + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual(['second']); + intercepted.length = 0; + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual(['second']); +}); + 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)); diff --git a/tests/page/page-route.spec.ts b/tests/page/page-route.spec.ts index 8c0a1bc80c..b33054b8bb 100644 --- a/tests/page/page-route.spec.ts +++ b/tests/page/page-route.spec.ts @@ -902,6 +902,25 @@ it('should support the times parameter with route matching', async ({ page, serv expect(intercepted).toHaveLength(1); }); +it('should work if handler with times parameter was removed from another handler', async ({ page, server }) => { + const intercepted = []; + const handler = async route => { + intercepted.push('first'); + void route.continue(); + }; + await page.route('**/*', handler, { times: 1 }); + await page.route('**/*', async route => { + intercepted.push('second'); + await page.unroute('**/*', handler); + await route.fallback(); + }); + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual(['second']); + intercepted.length = 0; + await page.goto(server.EMPTY_PAGE); + expect(intercepted).toEqual(['second']); +}); + it('should support async handler w/ times', async ({ page, server }) => { await page.route('**/empty.html', async route => { await new Promise(f => setTimeout(f, 100));