# Copyright (c) Microsoft Corporation. # # 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 asyncio from typing import List, Optional from playwright.async_api import Browser, BrowserContext, Request, Route from tests.server import Server from tests.utils import must async def test_link_navigation_inherit_user_agent_from_browser_context( browser: Browser, server: Server ) -> None: context = await browser.new_context(user_agent="hey") page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('link') request_waitable = asyncio.create_task(server.wait_for_request("/popup/popup.html")) await asyncio.sleep(0) # execute scheduled tasks, but don't await them async with context.expect_page() as page_info: await page.click("a") popup = await page_info.value await popup.wait_for_load_state("domcontentloaded") user_agent = await popup.evaluate("window.initialUserAgent") request = await request_waitable assert user_agent == "hey" assert request.requestHeaders.getRawHeaders("user-agent") == ["hey"] await context.close() async def test_link_navigation_respect_routes_from_browser_context( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('link') intercepted: List[bool] = [] async def handle_request(route: Route) -> None: intercepted.append(True) await route.continue_() await context.route("**/empty.html", handle_request) async with context.expect_page(): await page.click("a") assert intercepted == [True] async def test_window_open_inherit_user_agent_from_browser_context( browser: Browser, server: Server ) -> None: context = await browser.new_context(user_agent="hey") page = await context.new_page() await page.goto(server.EMPTY_PAGE) request_promise = asyncio.create_task(server.wait_for_request("/dummy.html")) await asyncio.sleep(0) # execute scheduled tasks, but don't await them user_agent = await page.evaluate( """url => { win = window.open(url) return win.navigator.userAgent }""", server.PREFIX + "/dummy.html", ) request = await request_promise assert user_agent == "hey" assert request.requestHeaders.getRawHeaders("user-agent") == ["hey"] await context.close() async def test_should_inherit_extra_headers_from_browser_context( browser: Browser, server: Server ) -> None: context = await browser.new_context(extra_http_headers={"foo": "bar"}) page = await context.new_page() await page.goto(server.EMPTY_PAGE) request_promise = asyncio.create_task(server.wait_for_request("/dummy.html")) await asyncio.sleep(0) # execute scheduled tasks, but don't await them await page.evaluate("url => window._popup = window.open(url)", server.PREFIX + "/dummy.html") request = await request_promise assert request.requestHeaders.getRawHeaders("foo") == ["bar"] await context.close() async def test_should_inherit_offline_from_browser_context( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await context.set_offline(True) online = await page.evaluate( """url => { win = window.open(url) return win.navigator.onLine }""", server.PREFIX + "/dummy.html", ) assert online is False async def test_should_inherit_http_credentials_from_browser_context( browser: Browser, server: Server ) -> None: server.set_auth("/title.html", "user", "pass") context = await browser.new_context(http_credentials={"username": "user", "password": "pass"}) page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with page.expect_popup() as popup_info: await page.evaluate( "url => window._popup = window.open(url)", server.PREFIX + "/title.html" ) popup = await popup_info.value await popup.wait_for_load_state("domcontentloaded") assert await popup.title() == "Woof-Woof" await context.close() async def test_should_inherit_touch_support_from_browser_context( browser: Browser, server: Server ) -> None: context = await browser.new_context(viewport={"width": 400, "height": 500}, has_touch=True) page = await context.new_page() await page.goto(server.EMPTY_PAGE) has_touch = await page.evaluate( """() => { win = window.open('') return 'ontouchstart' in win }""" ) assert has_touch await context.close() async def test_should_inherit_viewport_size_from_browser_context( browser: Browser, server: Server ) -> None: context = await browser.new_context(viewport={"width": 400, "height": 500}) page = await context.new_page() await page.goto(server.EMPTY_PAGE) size = await page.evaluate( """() => { win = window.open('about:blank') return { width: win.innerWidth, height: win.innerHeight } }""" ) assert size == {"width": 400, "height": 500} await context.close() @pytest.mark.skip(reason="Not supported by Camoufox") async def test_should_use_viewport_size_from_window_features( browser: Browser, server: Server ) -> None: context = await browser.new_context(viewport={"width": 700, "height": 700}) page = await context.new_page() await page.goto(server.EMPTY_PAGE) size = None async with page.expect_popup() as popup_info: size = await page.evaluate( """async () => { const win = window.open(window.location.href, 'Title', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=300,top=0,left=0'); await new Promise(resolve => { const interval = setInterval(() => { if (win.innerWidth === 600 && win.innerHeight === 300) { clearInterval(interval); resolve(); } }, 10); }); return { width: win.innerWidth, height: win.innerHeight } }""" ) popup = await popup_info.value await popup.set_viewport_size({"width": 500, "height": 400}) await popup.wait_for_load_state() resized = await popup.evaluate( "() => ({ width: window.innerWidth, height: window.innerHeight })" ) await context.close() assert size == {"width": 600, "height": 300} assert resized == {"width": 500, "height": 400} async def test_should_respect_routes_from_browser_context( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) def handle_request(route: Route, request: Request, intercepted: List[bool]) -> None: asyncio.create_task(route.continue_()) intercepted.append(True) intercepted: List[bool] = [] await context.route( "**/empty.html", lambda route, request: handle_request(route, request, intercepted), ) async with page.expect_popup(): await page.evaluate("url => window.__popup = window.open(url)", server.EMPTY_PAGE) assert len(intercepted) == 1 async def test_browser_context_add_init_script_should_apply_to_an_in_process_popup( context: BrowserContext, server: Server ) -> None: await context.add_init_script("window.injected = 123") page = await context.new_page() await page.goto(server.EMPTY_PAGE) injected = await page.evaluate( """() => { const win = window.open('about:blank'); return win.injected; }""" ) assert injected == 123 async def test_browser_context_add_init_script_should_apply_to_a_cross_process_popup( context: BrowserContext, server: Server ) -> None: await context.add_init_script("window.injected = 123") page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with page.expect_popup() as popup_info: await page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html") popup = await popup_info.value assert await popup.evaluate("injected") == 123 await popup.reload() assert await popup.evaluate("injected") == 123 async def test_should_expose_function_from_browser_context( context: BrowserContext, server: Server ) -> None: await context.expose_function("add", lambda a, b: a + b) page = await context.new_page() await page.goto(server.EMPTY_PAGE) added = await page.evaluate( """async () => { win = window.open('about:blank') return win.add(9, 4) }""" ) assert added == 13 async def test_should_work(context: BrowserContext) -> None: page = await context.new_page() async with page.expect_popup() as popup_info: await page.evaluate('window.__popup = window.open("about:blank")') popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") async def test_should_work_with_window_features(context: BrowserContext, server: Server) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with page.expect_popup() as popup_info: await page.evaluate( 'window.__popup = window.open(window.location.href, "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top=0,left=0")' ) popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") async def test_window_open_emit_for_immediately_closed_popups( context: BrowserContext, ) -> None: page = await context.new_page() async with page.expect_popup() as popup_info: await page.evaluate( """() => { win = window.open('about:blank') win.close() }""" ) popup = await popup_info.value assert popup async def test_should_emit_for_immediately_closed_popups( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with page.expect_popup() as popup_info: await page.evaluate( """() => { win = window.open(window.location.href) win.close() }""" ) popup = await popup_info.value assert popup async def test_should_be_able_to_capture_alert(context: BrowserContext) -> None: page = await context.new_page() evaluate_task: Optional[asyncio.Future] = None async def evaluate() -> None: nonlocal evaluate_task evaluate_task = asyncio.create_task( page.evaluate( """() => { const win = window.open('') win.alert('hello') }""" ) ) [popup, dialog, _] = await asyncio.gather( page.wait_for_event("popup"), context.wait_for_event("dialog"), evaluate() ) assert dialog.message == "hello" assert dialog.page == popup await dialog.dismiss() await must(evaluate_task) async def test_should_work_with_empty_url(context: BrowserContext) -> None: page = await context.new_page() async with page.expect_popup() as popup_info: await page.evaluate("() => window.__popup = window.open('')") popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") async def test_should_work_with_noopener_and_no_url(context: BrowserContext) -> None: page = await context.new_page() async with page.expect_popup() as popup_info: await page.evaluate('() => window.__popup = window.open(undefined, null, "noopener")') popup = await popup_info.value # Chromium reports 'about:blank#blocked' here. assert popup.url.split("#")[0] == "about:blank" assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") is False async def test_should_work_with_noopener_and_about_blank( context: BrowserContext, ) -> None: page = await context.new_page() async with page.expect_popup() as popup_info: await page.evaluate('() => window.__popup = window.open("about:blank", null, "noopener")') popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") is False async def test_should_work_with_noopener_and_url(context: BrowserContext, server: Server) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with page.expect_popup() as popup_info: await page.evaluate( 'url => window.__popup = window.open(url, null, "noopener")', server.EMPTY_PAGE, ) popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") is False async def test_should_work_with_clicking_target__blank( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('yo') async with page.expect_popup() as popup_info: await page.click("a") popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") assert popup.main_frame.page == popup async def test_should_work_with_fake_clicking_target__blank_and_rel_noopener( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('yo') async with page.expect_popup() as popup_info: await page.eval_on_selector("a", "a => a.click()") popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") is False async def test_should_work_with_clicking_target__blank_and_rel_noopener( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('yo') async with page.expect_popup() as popup_info: await page.click("a") popup = await popup_info.value assert await page.evaluate("!!window.opener") is False assert await popup.evaluate("!!window.opener") is False async def test_should_not_treat_navigations_as_new_popups( context: BrowserContext, server: Server ) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) await page.set_content('yo') async with page.expect_popup() as popup_info: await page.click("a") popup = await popup_info.value handled_popups = [] page.on( "popup", lambda popup: handled_popups.append(True), ) await popup.goto(server.CROSS_PROCESS_PREFIX + "/empty.html") assert len(handled_popups) == 0