diff --git a/tests/library/browsercontext-route.spec.ts b/tests/library/browsercontext-route.spec.ts index 74c40f76778a5..a597cf1157e2a 100644 --- a/tests/library/browsercontext-route.spec.ts +++ b/tests/library/browsercontext-route.spec.ts @@ -79,102 +79,6 @@ it('should unroute', async ({ browser, server }) => { await context.close(); }); -it('unroute should not wait for pending handlers to complete', async ({ page, context, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await context.route(/.*/, async route => { - secondHandlerCalled = true; - await route.continue(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - await route.fallback(); - }; - await context.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - await context.unroute(/.*/, handler); - continueRouteCallback(); - await navigationPromise; - expect(secondHandlerCalled).toBe(true); -}); - -it('unrouteAll removes all handlers', async ({ page, context, server }) => { - await context.route('**/*', route => { - void route.abort(); - }); - await context.route('**/empty.html', route => { - void route.abort(); - }); - await context.unrouteAll(); - await page.goto(server.EMPTY_PAGE); -}); - -it('unrouteAll should wait for pending handlers to complete', async ({ page, context, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await context.route(/.*/, async route => { - secondHandlerCalled = true; - await route.abort(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - await route.fallback(); - }; - await context.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - let didUnroute = false; - const unroutePromise = context.unrouteAll({ behavior: 'wait' }).then(() => didUnroute = true); - await new Promise(f => setTimeout(f, 500)); - expect(didUnroute).toBe(false); - continueRouteCallback(); - await unroutePromise; - expect(didUnroute).toBe(true); - await navigationPromise; - expect(secondHandlerCalled).toBe(false); -}); - -it('unrouteAll should not wait for pending handlers to complete if behavior is ignoreErrors', async ({ page, context, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await context.route(/.*/, async route => { - secondHandlerCalled = true; - await route.abort(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - throw new Error('Handler error'); - }; - await context.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - let didUnroute = false; - const unroutePromise = context.unrouteAll({ behavior: 'ignoreErrors' }).then(() => didUnroute = true); - await new Promise(f => setTimeout(f, 500)); - await unroutePromise; - expect(didUnroute).toBe(true); - continueRouteCallback(); - await navigationPromise.catch(e => void e); - // The error in the unrouted handler should be silently caught and remaining handler called. - expect(secondHandlerCalled).toBe(false); -}); - it('should yield to page.route', async ({ browser, server }) => { const context = await browser.newContext(); await context.route('**/empty.html', route => { @@ -483,33 +387,3 @@ it('should fall back async', async ({ page, context, server }) => { await page.goto(server.EMPTY_PAGE); expect(intercepted).toEqual([3, 2, 1]); }); - -it('page.close should not wait for active route handlers on the owning context', async ({ page, context, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await context.route(/.*/, async route => { - routeCallback(); - }); - await page.route(/.*/, async route => { - await route.fallback(); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - await routePromise; - await page.close(); -}); - -it('context.close should not wait for active route handlers on the owned pages', async ({ page, context, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await page.route(/.*/, async route => { - routeCallback(); - }); - await page.route(/.*/, async route => { - await route.fallback(); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - await routePromise; - await context.close(); -}); diff --git a/tests/library/unroute-behavior.spec.ts b/tests/library/unroute-behavior.spec.ts new file mode 100644 index 0000000000000..b12390b79b03a --- /dev/null +++ b/tests/library/unroute-behavior.spec.ts @@ -0,0 +1,302 @@ +/** + * Copyright (c) Microsoft Corporation. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { browserTest as it, expect } from '../config/browserTest'; +import type { Route } from '@playwright/test'; + +it('context.unroute should not wait for pending handlers to complete', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await context.route(/.*/, async route => { + secondHandlerCalled = true; + await route.continue(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + await route.fallback(); + }; + await context.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + await context.unroute(/.*/, handler); + continueRouteCallback(); + await navigationPromise; + expect(secondHandlerCalled).toBe(true); +}); + +it('context.unrouteAll removes all handlers', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + await context.route('**/*', route => { + void route.abort(); + }); + await context.route('**/empty.html', route => { + void route.abort(); + }); + await context.unrouteAll(); + await page.goto(server.EMPTY_PAGE); +}); + +it('context.unrouteAll should wait for pending handlers to complete', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await context.route(/.*/, async route => { + secondHandlerCalled = true; + await route.abort(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + await route.fallback(); + }; + await context.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + let didUnroute = false; + const unroutePromise = context.unrouteAll({ behavior: 'wait' }).then(() => didUnroute = true); + await new Promise(f => setTimeout(f, 500)); + expect(didUnroute).toBe(false); + continueRouteCallback(); + await unroutePromise; + expect(didUnroute).toBe(true); + await navigationPromise; + expect(secondHandlerCalled).toBe(false); +}); + +it('context.unrouteAll should not wait for pending handlers to complete if behavior is ignoreErrors', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await context.route(/.*/, async route => { + secondHandlerCalled = true; + await route.abort(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + throw new Error('Handler error'); + }; + await context.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + let didUnroute = false; + const unroutePromise = context.unrouteAll({ behavior: 'ignoreErrors' }).then(() => didUnroute = true); + await new Promise(f => setTimeout(f, 500)); + await unroutePromise; + expect(didUnroute).toBe(true); + continueRouteCallback(); + await navigationPromise.catch(e => void e); + // The error in the unrouted handler should be silently caught and remaining handler called. + expect(secondHandlerCalled).toBe(false); +}); + +it('page.close should not wait for active route handlers on the owning context', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await context.route(/.*/, async route => { + routeCallback(); + }); + await page.route(/.*/, async route => { + await route.fallback(); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + await routePromise; + await page.close(); +}); + +it('context.close should not wait for active route handlers on the owned pages', async ({ page, context, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await page.route(/.*/, async route => { + routeCallback(); + }); + await page.route(/.*/, async route => { + await route.fallback(); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + await routePromise; + await context.close(); +}); + +it('page.unroute should not wait for pending handlers to complete', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await page.route(/.*/, async route => { + secondHandlerCalled = true; + await route.continue(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + await route.fallback(); + }; + await page.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + await page.unroute(/.*/, handler); + continueRouteCallback(); + await navigationPromise; + expect(secondHandlerCalled).toBe(true); +}); + +it('page.unrouteAll removes all routes', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + await page.route('**/*', route => { + void route.abort(); + }); + await page.route('**/empty.html', route => { + void route.abort(); + }); + await page.unrouteAll(); + const response = await page.goto(server.EMPTY_PAGE); + expect(response.ok()).toBe(true); +}); + +it('page.unrouteAll should wait for pending handlers to complete', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await page.route(/.*/, async route => { + secondHandlerCalled = true; + await route.abort(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + await route.fallback(); + }; + await page.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + let didUnroute = false; + const unroutePromise = page.unrouteAll({ behavior: 'wait' }).then(() => didUnroute = true); + await new Promise(f => setTimeout(f, 500)); + expect(didUnroute).toBe(false); + continueRouteCallback(); + await unroutePromise; + expect(didUnroute).toBe(true); + await navigationPromise; + expect(secondHandlerCalled).toBe(false); +}); + +it('page.unrouteAll should not wait for pending handlers to complete if behavior is ignoreErrors', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await page.route(/.*/, async route => { + secondHandlerCalled = true; + await route.abort(); + }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + let continueRouteCallback; + const routeBarrier = new Promise(f => continueRouteCallback = f); + const handler = async route => { + routeCallback(); + await routeBarrier; + throw new Error('Handler error'); + }; + await page.route(/.*/, handler); + const navigationPromise = page.goto(server.EMPTY_PAGE); + await routePromise; + let didUnroute = false; + const unroutePromise = page.unrouteAll({ behavior: 'ignoreErrors' }).then(() => didUnroute = true); + await new Promise(f => setTimeout(f, 500)); + await unroutePromise; + expect(didUnroute).toBe(true); + continueRouteCallback(); + await navigationPromise.catch(e => void e); + // The error in the unrouted handler should be silently caught. + expect(secondHandlerCalled).toBe(false); +}); + +it('page.close does not wait for active route handlers', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let secondHandlerCalled = false; + await page.route(/.*/, () => secondHandlerCalled = true); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await page.route(/.*/, async route => { + routeCallback(); + await new Promise(() => {}); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + await routePromise; + await page.close(); + await new Promise(f => setTimeout(f, 500)); + expect(secondHandlerCalled).toBe(false); +}); + +it('route.continue should not throw if page has been closed', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await page.route(/.*/, async route => { + routeCallback(route); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + const route = await routePromise; + await page.close(); + // Should not throw. + await route.continue(); +}); + +it('route.fallback should not throw if page has been closed', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await page.route(/.*/, async route => { + routeCallback(route); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + const route = await routePromise; + await page.close(); + // Should not throw. + await route.fallback(); +}); + +it('route.fulfill should not throw if page has been closed', async ({ page, server }) => { + it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); + let routeCallback; + const routePromise = new Promise(f => routeCallback = f); + await page.route(/.*/, async route => { + routeCallback(route); + }); + page.goto(server.EMPTY_PAGE).catch(() => {}); + const route = await routePromise; + await page.close(); + // Should not throw. + await route.fulfill(); +}); diff --git a/tests/page/page-route.spec.ts b/tests/page/page-route.spec.ts index 5b21a41abee34..828bd4a9e2325 100644 --- a/tests/page/page-route.spec.ts +++ b/tests/page/page-route.spec.ts @@ -72,103 +72,6 @@ it('should unroute', async ({ page, server }) => { expect(intercepted).toEqual([1]); }); -it('unroute should not wait for pending handlers to complete', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await page.route(/.*/, async route => { - secondHandlerCalled = true; - await route.continue(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - await route.fallback(); - }; - await page.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - await page.unroute(/.*/, handler); - continueRouteCallback(); - await navigationPromise; - expect(secondHandlerCalled).toBe(true); -}); - -it('unrouteAll removes all routes', async ({ page, server }) => { - await page.route('**/*', route => { - void route.abort(); - }); - await page.route('**/empty.html', route => { - void route.abort(); - }); - await page.unrouteAll(); - const response = await page.goto(server.EMPTY_PAGE); - expect(response.ok()).toBe(true); -}); - -it('unrouteAll should wait for pending handlers to complete', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await page.route(/.*/, async route => { - secondHandlerCalled = true; - await route.abort(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - await route.fallback(); - }; - await page.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - let didUnroute = false; - const unroutePromise = page.unrouteAll({ behavior: 'wait' }).then(() => didUnroute = true); - await new Promise(f => setTimeout(f, 500)); - expect(didUnroute).toBe(false); - continueRouteCallback(); - await unroutePromise; - expect(didUnroute).toBe(true); - await navigationPromise; - expect(secondHandlerCalled).toBe(false); -}); - -it('unrouteAll should not wait for pending handlers to complete if behavior is ignoreErrors', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await page.route(/.*/, async route => { - secondHandlerCalled = true; - await route.abort(); - }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - let continueRouteCallback; - const routeBarrier = new Promise(f => continueRouteCallback = f); - const handler = async route => { - routeCallback(); - await routeBarrier; - throw new Error('Handler error'); - }; - await page.route(/.*/, handler); - const navigationPromise = page.goto(server.EMPTY_PAGE); - await routePromise; - let didUnroute = false; - const unroutePromise = page.unrouteAll({ behavior: 'ignoreErrors' }).then(() => didUnroute = true); - await new Promise(f => setTimeout(f, 500)); - await unroutePromise; - expect(didUnroute).toBe(true); - continueRouteCallback(); - await navigationPromise.catch(e => void e); - // The error in the unrouted handler should be silently caught. - expect(secondHandlerCalled).toBe(false); -}); - it('should support ? in glob pattern', async ({ page, server }) => { server.setRoute('/index', (req, res) => res.end('index-no-hello')); server.setRoute('/index123hello', (req, res) => res.end('index123hello')); @@ -1124,62 +1027,3 @@ it('should intercept when postData is more than 1MB', async ({ page, server }) = }).catch(e => {}), POST_BODY); expect(await interceptionPromise).toBe(POST_BODY); }); - -it('page.close does not wait for active route handlers', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let secondHandlerCalled = false; - await page.route(/.*/, () => secondHandlerCalled = true); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await page.route(/.*/, async route => { - routeCallback(); - await new Promise(() => {}); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - await routePromise; - await page.close(); - await new Promise(f => setTimeout(f, 500)); - expect(secondHandlerCalled).toBe(false); -}); - -it('route.continue should not throw if page has been closed', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await page.route(/.*/, async route => { - routeCallback(route); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - const route = await routePromise; - await page.close(); - // Should not throw. - await route.continue(); -}); - -it('route.fallback should not throw if page has been closed', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await page.route(/.*/, async route => { - routeCallback(route); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - const route = await routePromise; - await page.close(); - // Should not throw. - await route.fallback(); -}); - -it('route.fulfill should not throw if page has been closed', async ({ page, server }) => { - it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/23781' }); - let routeCallback; - const routePromise = new Promise(f => routeCallback = f); - await page.route(/.*/, async route => { - routeCallback(route); - }); - page.goto(server.EMPTY_PAGE).catch(() => {}); - const route = await routePromise; - await page.close(); - // Should not throw. - await route.fulfill(); -});