# 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 Optional import pytest from playwright.async_api import Error, Page from tests.server import Server from .utils import Utils async def test_evaluate_handle(page: Page, server: Server) -> None: await page.goto(server.EMPTY_PAGE) main_frame = page.main_frame assert main_frame.page == page window_handle = await main_frame.evaluate_handle("window") assert window_handle async def test_frame_element(page: Page, server: Server, utils: Utils) -> None: await page.goto(server.EMPTY_PAGE) frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) assert frame1 await utils.attach_frame(page, "frame2", server.EMPTY_PAGE) frame3 = await utils.attach_frame(page, "frame3", server.EMPTY_PAGE) assert frame3 frame1handle1 = await page.query_selector("#frame1") assert frame1handle1 frame1handle2 = await frame1.frame_element() frame3handle1 = await page.query_selector("#frame3") assert frame3handle1 frame3handle2 = await frame3.frame_element() assert await frame1handle1.evaluate("(a, b) => a === b", frame1handle2) assert await frame3handle1.evaluate("(a, b) => a === b", frame3handle2) assert await frame1handle1.evaluate("(a, b) => a === b", frame3handle1) is False async def test_frame_element_with_content_frame(page: Page, server: Server, utils: Utils) -> None: await page.goto(server.EMPTY_PAGE) frame = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) handle = await frame.frame_element() content_frame = await handle.content_frame() assert content_frame == frame async def test_frame_element_throw_when_detached(page: Page, server: Server, utils: Utils) -> None: await page.goto(server.EMPTY_PAGE) frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) await page.eval_on_selector("#frame1", "e => e.remove()") error: Optional[Error] = None try: await frame1.frame_element() except Error as e: error = e assert error assert error.message == "Frame.frame_element: Frame has been detached." async def test_evaluate_throw_for_detached_frames(page: Page, server: Server, utils: Utils) -> None: frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) assert frame1 await utils.detach_frame(page, "frame1") error: Optional[Error] = None try: await frame1.evaluate("7 * 8") except Error as e: error = e assert error assert "Frame was detached" in error.message async def test_evaluate_isolated_between_frames(page: Page, server: Server, utils: Utils) -> None: await page.goto(server.EMPTY_PAGE) await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) assert len(page.frames) == 2 [frame1, frame2] = page.frames assert frame1 != frame2 await asyncio.gather(frame1.evaluate("window.a = 1"), frame2.evaluate("window.a = 2")) [a1, a2] = await asyncio.gather(frame1.evaluate("window.a"), frame2.evaluate("window.a")) assert a1 == 1 assert a2 == 2 async def test_should_handle_nested_frames(page: Page, server: Server, utils: Utils) -> None: await page.goto(server.PREFIX + "/frames/nested-frames.html") assert utils.dump_frames(page.main_frame) == [ "http://localhost:/frames/nested-frames.html", " http://localhost:/frames/frame.html (aframe)", " http://localhost:/frames/two-frames.html (2frames)", " http://localhost:/frames/frame.html (dos)", " http://localhost:/frames/frame.html (uno)", ] async def test_should_send_events_when_frames_are_manipulated_dynamically( page: Page, server: Server, utils: Utils ) -> None: await page.goto(server.EMPTY_PAGE) # validate frameattached events attached_frames = [] page.on("frameattached", lambda frame: attached_frames.append(frame)) await utils.attach_frame(page, "frame1", "./assets/frame.html") assert len(attached_frames) == 1 assert "/assets/frame.html" in attached_frames[0].url # validate framenavigated events navigated_frames = [] page.on("framenavigated", lambda frame: navigated_frames.append(frame)) await page.evaluate( """() => { frame = document.getElementById('frame1') frame.src = './empty.html' return new Promise(x => frame.onload = x) }""" ) assert len(navigated_frames) == 1 assert navigated_frames[0].url == server.EMPTY_PAGE # validate framedetached events detached_frames = [] page.on("framedetached", lambda frame: detached_frames.append(frame)) await utils.detach_frame(page, "frame1") assert len(detached_frames) == 1 assert detached_frames[0].is_detached() async def test_framenavigated_when_navigating_on_anchor_urls(page: Page, server: Server) -> None: await page.goto(server.EMPTY_PAGE) async with page.expect_event("framenavigated"): await page.goto(server.EMPTY_PAGE + "#foo") assert page.url == server.EMPTY_PAGE + "#foo" async def test_persist_main_frame_on_cross_process_navigation(page: Page, server: Server) -> None: await page.goto(server.EMPTY_PAGE) main_frame = page.main_frame await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html") assert page.main_frame == main_frame async def test_should_not_send_attach_detach_events_for_main_frame( page: Page, server: Server ) -> None: has_events = [] page.on("frameattached", lambda frame: has_events.append(True)) page.on("framedetached", lambda frame: has_events.append(True)) await page.goto(server.EMPTY_PAGE) assert has_events == [] async def test_detach_child_frames_on_navigation(page: Page, server: Server) -> None: attached_frames = [] detached_frames = [] navigated_frames = [] page.on("frameattached", lambda frame: attached_frames.append(frame)) page.on("framedetached", lambda frame: detached_frames.append(frame)) page.on("framenavigated", lambda frame: navigated_frames.append(frame)) await page.goto(server.PREFIX + "/frames/nested-frames.html") assert len(attached_frames) == 4 assert len(detached_frames) == 0 assert len(navigated_frames) == 5 attached_frames = [] detached_frames = [] navigated_frames = [] await page.goto(server.EMPTY_PAGE) assert len(attached_frames) == 0 assert len(detached_frames) == 4 assert len(navigated_frames) == 1 async def test_framesets(page: Page, server: Server) -> None: attached_frames = [] detached_frames = [] navigated_frames = [] page.on("frameattached", lambda frame: attached_frames.append(frame)) page.on("framedetached", lambda frame: detached_frames.append(frame)) page.on("framenavigated", lambda frame: navigated_frames.append(frame)) await page.goto(server.PREFIX + "/frames/frameset.html") assert len(attached_frames) == 4 assert len(detached_frames) == 0 assert len(navigated_frames) == 5 attached_frames = [] detached_frames = [] navigated_frames = [] await page.goto(server.EMPTY_PAGE) assert len(attached_frames) == 0 assert len(detached_frames) == 4 assert len(navigated_frames) == 1 async def test_frame_from_inside_shadow_dom(page: Page, server: Server) -> None: await page.goto(server.PREFIX + "/shadow.html") await page.evaluate( """async url => { frame = document.createElement('iframe'); frame.src = url; document.body.shadowRoot.appendChild(frame); await new Promise(x => frame.onload = x); }""", server.EMPTY_PAGE, ) assert len(page.frames) == 2 assert page.frames[1].url == server.EMPTY_PAGE async def test_frame_name(page: Page, server: Server, utils: Utils) -> None: await utils.attach_frame(page, "theFrameId", server.EMPTY_PAGE) await page.evaluate( """url => { frame = document.createElement('iframe'); frame.name = 'theFrameName'; frame.src = url; document.body.appendChild(frame); return new Promise(x => frame.onload = x); }""", server.EMPTY_PAGE, ) assert page.frames[0].name == "" assert page.frames[1].name == "theFrameId" assert page.frames[2].name == "theFrameName" async def test_frame_parent(page: Page, server: Server, utils: Utils) -> None: await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) await utils.attach_frame(page, "frame2", server.EMPTY_PAGE) assert page.frames[0].parent_frame is None assert page.frames[1].parent_frame == page.main_frame assert page.frames[2].parent_frame == page.main_frame async def test_should_report_different_frame_instance_when_frame_re_attaches( page: Page, server: Server, utils: Utils ) -> None: frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE) await page.evaluate( """() => { window.frame = document.querySelector('#frame1') window.frame.remove() }""" ) assert frame1.is_detached() async with page.expect_event("frameattached") as frame2_info: await page.evaluate("() => document.body.appendChild(window.frame)") frame2 = await frame2_info.value assert frame2.is_detached() is False assert frame1 != frame2 async def test_strict_mode(page: Page, server: Server) -> None: await page.goto(server.EMPTY_PAGE) await page.set_content( """ """ ) with pytest.raises(Error): await page.text_content("button", strict=True) with pytest.raises(Error): await page.query_selector("button", strict=True)