diff --git a/tests/async/conftest.py b/tests/async/conftest.py index ba141fcd55..490f4440a8 100644 --- a/tests/async/conftest.py +++ b/tests/async/conftest.py @@ -12,45 +12,60 @@ # See the License for the specific language governing permissions and # limitations under the License. -import pytest +import asyncio +from typing import Any, AsyncGenerator, Awaitable, Callable, Dict, Generator, List -from playwright.async_api import async_playwright +import pytest +from playwright.async_api import ( + Browser, + BrowserContext, + BrowserType, + Page, + Playwright, + Selectors, + async_playwright, +) + +from .utils import Utils from .utils import utils as utils_object @pytest.fixture -def utils(): +def utils() -> Generator[Utils, None, None]: yield utils_object # Will mark all the tests as async -def pytest_collection_modifyitems(items): +def pytest_collection_modifyitems(items: List[pytest.Item]) -> None: for item in items: item.add_marker(pytest.mark.asyncio) @pytest.fixture(scope="session") -async def playwright(): +async def playwright() -> AsyncGenerator[Playwright, None]: async with async_playwright() as playwright_object: yield playwright_object @pytest.fixture(scope="session") -def browser_type(playwright, browser_name: str): +def browser_type(playwright: Playwright, browser_name: str) -> BrowserType: if browser_name == "chromium": return playwright.chromium if browser_name == "firefox": return playwright.firefox if browser_name == "webkit": return playwright.webkit + raise Exception(f"Invalid browser_name: {browser_name}") @pytest.fixture(scope="session") -async def browser_factory(launch_arguments, browser_type): +async def browser_factory( + launch_arguments: Dict, browser_type: BrowserType +) -> AsyncGenerator[Callable[..., Awaitable[Browser]], None]: browsers = [] - async def launch(**kwargs): + async def launch(**kwargs: Any) -> Browser: browser = await browser_type.launch(**launch_arguments, **kwargs) browsers.append(browser) return browser @@ -61,17 +76,21 @@ async def launch(**kwargs): @pytest.fixture(scope="session") -async def browser(browser_factory): +async def browser( + browser_factory: "Callable[..., asyncio.Future[Browser]]", +) -> AsyncGenerator[Browser, None]: browser = await browser_factory() yield browser await browser.close() @pytest.fixture -async def context_factory(browser): +async def context_factory( + browser: Browser, +) -> AsyncGenerator["Callable[..., Awaitable[BrowserContext]]", None]: contexts = [] - async def launch(**kwargs): + async def launch(**kwargs: Any) -> BrowserContext: context = await browser.new_context(**kwargs) contexts.append(context) return context @@ -82,19 +101,21 @@ async def launch(**kwargs): @pytest.fixture -async def context(context_factory): +async def context( + context_factory: "Callable[..., asyncio.Future[BrowserContext]]", +) -> AsyncGenerator[BrowserContext, None]: context = await context_factory() yield context await context.close() @pytest.fixture -async def page(context): +async def page(context: BrowserContext) -> AsyncGenerator[Page, None]: page = await context.new_page() yield page await page.close() @pytest.fixture(scope="session") -def selectors(playwright): +def selectors(playwright: Playwright) -> Selectors: return playwright.selectors diff --git a/tests/async/test_accessibility.py b/tests/async/test_accessibility.py index fa9a54b978..201ba84834 100644 --- a/tests/async/test_accessibility.py +++ b/tests/async/test_accessibility.py @@ -17,8 +17,12 @@ import pytest +from playwright.async_api import Page -async def test_accessibility_should_work(page, is_firefox, is_chromium): + +async def test_accessibility_should_work( + page: Page, is_firefox: bool, is_chromium: bool +) -> None: await page.set_content( """ Accessibility Test @@ -109,54 +113,62 @@ async def test_accessibility_should_work(page, is_firefox, is_chromium): assert await page.accessibility.snapshot() == golden -async def test_accessibility_should_work_with_regular_text(page, is_firefox): +async def test_accessibility_should_work_with_regular_text( + page: Page, is_firefox: bool +) -> None: await page.set_content("
Hello World
") snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == { "role": "text leaf" if is_firefox else "text", "name": "Hello World", } -async def test_accessibility_roledescription(page): +async def test_accessibility_roledescription(page: Page) -> None: await page.set_content('

Hi

') snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0]["roledescription"] == "foo" -async def test_accessibility_orientation(page): +async def test_accessibility_orientation(page: Page) -> None: await page.set_content( '11' ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0]["orientation"] == "vertical" -async def test_accessibility_autocomplete(page): +async def test_accessibility_autocomplete(page: Page) -> None: await page.set_content('
hi
') snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0]["autocomplete"] == "list" -async def test_accessibility_multiselectable(page): +async def test_accessibility_multiselectable(page: Page) -> None: await page.set_content( '
hey
' ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0]["multiselectable"] -async def test_accessibility_keyshortcuts(page): +async def test_accessibility_keyshortcuts(page: Page) -> None: await page.set_content( '
hey
' ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0]["keyshortcuts"] == "foo" async def test_accessibility_filtering_children_of_leaf_nodes_should_not_report_text_nodes_inside_controls( - page, is_firefox -): + page: Page, is_firefox: bool +) -> None: await page.set_content( """
@@ -179,13 +191,14 @@ async def test_accessibility_filtering_children_of_leaf_nodes_should_not_report_ # WebKit rich text accessibility is iffy @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_with_role_should_not_have_children( - page, browser_channel -): + page: Page, +) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == { "multiline": True, "name": "", @@ -196,13 +209,14 @@ async def test_accessibility_plain_text_field_with_role_should_not_have_children @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_without_role_should_not_have_content( - page, browser_channel -): + page: Page, +) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == { "name": "", "role": "generic", @@ -212,13 +226,14 @@ async def test_accessibility_plain_text_field_without_role_should_not_have_conte @pytest.mark.only_browser("chromium") async def test_accessibility_plain_text_field_with_tabindex_and_without_role_should_not_have_content( - page, browser_channel -): + page: Page, +) -> None: await page.set_content( """
Edit this image:my fake image
""" ) snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == { "name": "", "role": "generic", @@ -227,8 +242,8 @@ async def test_accessibility_plain_text_field_with_tabindex_and_without_role_sho async def test_accessibility_non_editable_textbox_with_role_and_tabIndex_and_label_should_not_have_children( - page, is_chromium, is_firefox -): + page: Page, is_chromium: bool, is_firefox: bool +) -> None: await page.set_content( """
@@ -255,12 +270,13 @@ async def test_accessibility_non_editable_textbox_with_role_and_tabIndex_and_lab "value": "this is the inner content ", } snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == golden async def test_accessibility_checkbox_with_and_tabIndex_and_label_should_not_have_children( - page, -): + page: Page, +) -> None: await page.set_content( """
@@ -270,12 +286,13 @@ async def test_accessibility_checkbox_with_and_tabIndex_and_label_should_not_hav ) golden = {"role": "checkbox", "name": "my favorite checkbox", "checked": True} snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == golden async def test_accessibility_checkbox_without_label_should_not_have_children( - page, is_firefox -): + page: Page, is_firefox: bool +) -> None: await page.set_content( """
@@ -289,10 +306,11 @@ async def test_accessibility_checkbox_without_label_should_not_have_children( "checked": True, } snapshot = await page.accessibility.snapshot() + assert snapshot assert snapshot["children"][0] == golden -async def test_accessibility_should_work_a_button(page): +async def test_accessibility_should_work_a_button(page: Page) -> None: await page.set_content("") button = await page.query_selector("button") @@ -302,7 +320,7 @@ async def test_accessibility_should_work_a_button(page): } -async def test_accessibility_should_work_an_input(page): +async def test_accessibility_should_work_an_input(page: Page) -> None: await page.set_content('') input = await page.query_selector("input") @@ -313,9 +331,7 @@ async def test_accessibility_should_work_an_input(page): } -async def test_accessibility_should_work_on_a_menu( - page, is_webkit, is_chromium, browser_channel -): +async def test_accessibility_should_work_on_a_menu(page: Page) -> None: await page.set_content( """
@@ -345,15 +361,15 @@ async def test_accessibility_should_work_on_a_menu( async def test_accessibility_should_return_null_when_the_element_is_no_longer_in_DOM( - page, -): + page: Page, +) -> None: await page.set_content("") button = await page.query_selector("button") await page.eval_on_selector("button", "button => button.remove()") assert await page.accessibility.snapshot(root=button) is None -async def test_accessibility_should_show_uninteresting_nodes(page): +async def test_accessibility_should_show_uninteresting_nodes(page: Page) -> None: await page.set_content( """
@@ -369,6 +385,7 @@ async def test_accessibility_should_show_uninteresting_nodes(page): root = await page.query_selector("#root") snapshot = await page.accessibility.snapshot(root=root, interesting_only=False) + assert snapshot assert snapshot["role"] == "textbox" assert "hello" in snapshot["value"] assert "world" in snapshot["value"] diff --git a/tests/async/test_add_init_script.py b/tests/async/test_add_init_script.py index 07279f5a14..33853780a8 100644 --- a/tests/async/test_add_init_script.py +++ b/tests/async/test_add_init_script.py @@ -12,37 +12,45 @@ # See the License for the specific language governing permissions and # limitations under the License. -from playwright.async_api import Error +from pathlib import Path +from typing import Optional +from playwright.async_api import BrowserContext, Error, Page -async def test_add_init_script_evaluate_before_anything_else_on_the_page(page): + +async def test_add_init_script_evaluate_before_anything_else_on_the_page( + page: Page, +) -> None: await page.add_init_script("window.injected = 123") await page.goto("data:text/html,") assert await page.evaluate("window.result") == 123 -async def test_add_init_script_work_with_a_path(page, assetdir): +async def test_add_init_script_work_with_a_path(page: Page, assetdir: Path) -> None: await page.add_init_script(path=assetdir / "injectedfile.js") await page.goto("data:text/html,") assert await page.evaluate("window.result") == 123 -async def test_add_init_script_work_with_content(page): +async def test_add_init_script_work_with_content(page: Page) -> None: await page.add_init_script("window.injected = 123") await page.goto("data:text/html,") assert await page.evaluate("window.result") == 123 -async def test_add_init_script_throw_without_path_and_content(page): - error = None +async def test_add_init_script_throw_without_path_and_content(page: Page) -> None: + error: Optional[Error] = None try: - await page.add_init_script({"foo": "bar"}) + await page.add_init_script({"foo": "bar"}) # type: ignore except Error as e: error = e + assert error assert error.message == "Either path or script parameter must be specified" -async def test_add_init_script_work_with_browser_context_scripts(page, context): +async def test_add_init_script_work_with_browser_context_scripts( + page: Page, context: BrowserContext +) -> None: await context.add_init_script("window.temp = 123") page = await context.new_page() await page.add_init_script("window.injected = window.temp") @@ -51,8 +59,8 @@ async def test_add_init_script_work_with_browser_context_scripts(page, context): async def test_add_init_script_work_with_browser_context_scripts_with_a_path( - page, context, assetdir -): + page: Page, context: BrowserContext, assetdir: Path +) -> None: await context.add_init_script(path=assetdir / "injectedfile.js") page = await context.new_page() await page.goto("data:text/html,") @@ -60,15 +68,15 @@ async def test_add_init_script_work_with_browser_context_scripts_with_a_path( async def test_add_init_script_work_with_browser_context_scripts_for_already_created_pages( - page, context -): + page: Page, context: BrowserContext +) -> None: await context.add_init_script("window.temp = 123") await page.add_init_script("window.injected = window.temp") await page.goto("data:text/html,") assert await page.evaluate("window.result") == 123 -async def test_add_init_script_support_multiple_scripts(page): +async def test_add_init_script_support_multiple_scripts(page: Page) -> None: await page.add_init_script("window.script1 = 1") await page.add_init_script("window.script2 = 2") await page.goto("data:text/html,") @@ -76,7 +84,7 @@ async def test_add_init_script_support_multiple_scripts(page): assert await page.evaluate("window.script2") == 2 -async def test_should_work_with_trailing_comments(page): +async def test_should_work_with_trailing_comments(page: Page) -> None: await page.add_init_script("// comment") await page.add_init_script("window.secret = 42;") await page.goto("data:text/html,") diff --git a/tests/async/test_asyncio.py b/tests/async/test_asyncio.py index f1def84d38..084d9eb413 100644 --- a/tests/async/test_asyncio.py +++ b/tests/async/test_asyncio.py @@ -24,10 +24,10 @@ async def test_should_cancel_underlying_protocol_calls( browser_name: str, launch_arguments: Dict -): +) -> None: handler_exception = None - def exception_handlerdler(loop, context) -> None: + def exception_handlerdler(loop: asyncio.AbstractEventLoop, context: Dict) -> None: nonlocal handler_exception handler_exception = context["exception"] @@ -70,8 +70,9 @@ async def test_cancel_pending_protocol_call_on_playwright_stop(server: Server) - async def test_should_collect_stale_handles(page: Page, server: Server) -> None: - page.on("request", lambda: None) + page.on("request", lambda _: None) response = await page.goto(server.PREFIX + "/title.html") + assert response for i in range(1000): await page.evaluate( """async () => { diff --git a/tests/async/test_browser.py b/tests/async/test_browser.py index 17bfb5b2f7..e23b3439bd 100644 --- a/tests/async/test_browser.py +++ b/tests/async/test_browser.py @@ -16,10 +16,10 @@ import pytest -from playwright.async_api import Browser, Error +from playwright.async_api import Browser, BrowserType, Error -async def test_should_create_new_page(browser): +async def test_should_create_new_page(browser: Browser) -> None: page1 = await browser.new_page() assert len(browser.contexts) == 1 @@ -33,7 +33,7 @@ async def test_should_create_new_page(browser): assert len(browser.contexts) == 0 -async def test_should_throw_upon_second_create_new_page(browser): +async def test_should_throw_upon_second_create_new_page(browser: Browser) -> None: page = await browser.new_page() with pytest.raises(Error) as exc: await page.context.new_page() @@ -41,7 +41,7 @@ async def test_should_throw_upon_second_create_new_page(browser): assert "Please use browser.new_context()" in exc.value.message -async def test_version_should_work(browser: Browser, is_chromium): +async def test_version_should_work(browser: Browser, is_chromium: bool) -> None: version = browser.version if is_chromium: assert re.match(r"^\d+\.\d+\.\d+\.\d+$", version) @@ -49,5 +49,7 @@ async def test_version_should_work(browser: Browser, is_chromium): assert re.match(r"^\d+\.\d+", version) -async def test_should_return_browser_type(browser, browser_type): +async def test_should_return_browser_type( + browser: Browser, browser_type: BrowserType +) -> None: assert browser.browser_type is browser_type diff --git a/tests/async/test_browsercontext.py b/tests/async/test_browsercontext.py index 59670340a7..23fbd27dee 100644 --- a/tests/async/test_browsercontext.py +++ b/tests/async/test_browsercontext.py @@ -14,16 +14,28 @@ import asyncio import re +from typing import Any, List from urllib.parse import urlparse import pytest -from playwright.async_api import Browser, Error +from playwright.async_api import ( + Browser, + BrowserContext, + Error, + JSHandle, + Page, + Playwright, + Request, + Route, +) from tests.server import Server from tests.utils import TARGET_CLOSED_ERROR_MESSAGE +from .utils import Utils -async def test_page_event_should_create_new_context(browser): + +async def test_page_event_should_create_new_context(browser: Browser) -> None: assert len(browser.contexts) == 0 context = await browser.new_context() assert len(browser.contexts) == 1 @@ -33,7 +45,9 @@ async def test_page_event_should_create_new_context(browser): assert context.browser == browser -async def test_window_open_should_use_parent_tab_context(browser, server): +async def test_window_open_should_use_parent_tab_context( + browser: Browser, server: Server +) -> None: context = await browser.new_context() page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -44,7 +58,9 @@ async def test_window_open_should_use_parent_tab_context(browser, server): await context.close() -async def test_page_event_should_isolate_localStorage_and_cookies(browser, server): +async def test_page_event_should_isolate_localStorage_and_cookies( + browser: Browser, server: Server +) -> None: # Create two incognito contexts. context1 = await browser.new_context() context2 = await browser.new_context() @@ -90,14 +106,16 @@ async def test_page_event_should_isolate_localStorage_and_cookies(browser, serve assert browser.contexts == [] -async def test_page_event_should_propagate_default_viewport_to_the_page(browser, utils): +async def test_page_event_should_propagate_default_viewport_to_the_page( + browser: Browser, utils: Utils +) -> None: context = await browser.new_context(viewport={"width": 456, "height": 789}) page = await context.new_page() await utils.verify_viewport(page, 456, 789) await context.close() -async def test_page_event_should_respect_device_scale_factor(browser): +async def test_page_event_should_respect_device_scale_factor(browser: Browser) -> None: context = await browser.new_context(device_scale_factor=3) page = await context.new_page() assert await page.evaluate("window.devicePixelRatio") == 3 @@ -105,8 +123,8 @@ async def test_page_event_should_respect_device_scale_factor(browser): async def test_page_event_should_not_allow_device_scale_factor_with_null_viewport( - browser, -): + browser: Browser, +) -> None: with pytest.raises(Error) as exc_info: await browser.new_context(no_viewport=True, device_scale_factor=1) assert ( @@ -115,7 +133,9 @@ async def test_page_event_should_not_allow_device_scale_factor_with_null_viewpor ) -async def test_page_event_should_not_allow_is_mobile_with_null_viewport(browser): +async def test_page_event_should_not_allow_is_mobile_with_null_viewport( + browser: Browser, +) -> None: with pytest.raises(Error) as exc_info: await browser.new_context(no_viewport=True, is_mobile=True) assert ( @@ -124,12 +144,12 @@ async def test_page_event_should_not_allow_is_mobile_with_null_viewport(browser) ) -async def test_close_should_work_for_empty_context(browser): +async def test_close_should_work_for_empty_context(browser: Browser) -> None: context = await browser.new_context() await context.close() -async def test_close_should_abort_wait_for_event(browser): +async def test_close_should_abort_wait_for_event(browser: Browser) -> None: context = await browser.new_context() with pytest.raises(Error) as exc_info: async with context.expect_page(): @@ -137,7 +157,7 @@ async def test_close_should_abort_wait_for_event(browser): assert TARGET_CLOSED_ERROR_MESSAGE in exc_info.value.message -async def test_close_should_be_callable_twice(browser): +async def test_close_should_be_callable_twice(browser: Browser) -> None: context = await browser.new_context() await asyncio.gather( context.close(), @@ -146,8 +166,8 @@ async def test_close_should_be_callable_twice(browser): await context.close() -async def test_user_agent_should_work(browser, server): - async def baseline(): +async def test_user_agent_should_work(browser: Browser, server: Server) -> None: + async def baseline() -> None: context = await browser.new_context() page = await context.new_page() assert "Mozilla" in await page.evaluate("navigator.userAgent") @@ -155,7 +175,7 @@ async def baseline(): await baseline() - async def override(): + async def override() -> None: context = await browser.new_context(user_agent="foobar") page = await context.new_page() [request, _] = await asyncio.gather( @@ -168,7 +188,9 @@ async def override(): await override() -async def test_user_agent_should_work_for_subframes(browser, server, utils): +async def test_user_agent_should_work_for_subframes( + browser: Browser, server: Server, utils: Utils +) -> None: context = await browser.new_context(user_agent="foobar") page = await context.new_page() [request, _] = await asyncio.gather( @@ -179,7 +201,9 @@ async def test_user_agent_should_work_for_subframes(browser, server, utils): await context.close() -async def test_user_agent_should_emulate_device_user_agent(playwright, browser, server): +async def test_user_agent_should_emulate_device_user_agent( + playwright: Playwright, browser: Browser, server: Server +) -> None: context = await browser.new_context( user_agent=playwright.devices["iPhone 6"]["user_agent"] ) @@ -189,8 +213,10 @@ async def test_user_agent_should_emulate_device_user_agent(playwright, browser, await context.close() -async def test_user_agent_should_make_a_copy_of_default_options(browser, server): - options = {"user_agent": "foobar"} +async def test_user_agent_should_make_a_copy_of_default_options( + browser: Browser, server: Server +) -> None: + options: Any = {"user_agent": "foobar"} context = await browser.new_context(**options) options["user_agent"] = "wrong" page = await context.new_page() @@ -202,8 +228,10 @@ async def test_user_agent_should_make_a_copy_of_default_options(browser, server) await context.close() -async def test_page_event_should_bypass_csp_meta_tag(browser, server): - async def baseline(): +async def test_page_event_should_bypass_csp_meta_tag( + browser: Browser, server: Server +) -> None: + async def baseline() -> None: context = await browser.new_context() page = await context.new_page() await page.goto(server.PREFIX + "/csp.html") @@ -217,7 +245,7 @@ async def baseline(): await baseline() # By-pass CSP and try one more time. - async def override(): + async def override() -> None: context = await browser.new_context(bypass_csp=True) page = await context.new_page() await page.goto(server.PREFIX + "/csp.html") @@ -228,11 +256,13 @@ async def override(): await override() -async def test_page_event_should_bypass_csp_header(browser, server): +async def test_page_event_should_bypass_csp_header( + browser: Browser, server: Server +) -> None: # Make sure CSP prohibits add_script_tag. server.set_csp("/empty.html", 'default-src "self"') - async def baseline(): + async def baseline() -> None: context = await browser.new_context() page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -246,7 +276,7 @@ async def baseline(): await baseline() # By-pass CSP and try one more time. - async def override(): + async def override() -> None: context = await browser.new_context(bypass_csp=True) page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -257,7 +287,9 @@ async def override(): await override() -async def test_page_event_should_bypass_after_cross_process_navigation(browser, server): +async def test_page_event_should_bypass_after_cross_process_navigation( + browser: Browser, server: Server +) -> None: context = await browser.new_context(bypass_csp=True) page = await context.new_page() await page.goto(server.PREFIX + "/csp.html") @@ -270,8 +302,10 @@ async def test_page_event_should_bypass_after_cross_process_navigation(browser, await context.close() -async def test_page_event_should_bypass_csp_in_iframes_as_well(browser, server, utils): - async def baseline(): +async def test_page_event_should_bypass_csp_in_iframes_as_well( + browser: Browser, server: Server, utils: Utils +) -> None: + async def baseline() -> None: # Make sure CSP prohibits add_script_tag in an iframe. context = await browser.new_context() page = await context.new_page() @@ -287,7 +321,7 @@ async def baseline(): await baseline() # By-pass CSP and try one more time. - async def override(): + async def override() -> None: context = await browser.new_context(bypass_csp=True) page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -302,8 +336,8 @@ async def override(): await override() -async def test_csp_should_work(browser, is_webkit): - async def baseline(): +async def test_csp_should_work(browser: Browser, is_webkit: bool) -> None: + async def baseline() -> None: context = await browser.new_context(java_script_enabled=False) page = await context.new_page() await page.goto('data:text/html, ') @@ -317,7 +351,7 @@ async def baseline(): await baseline() - async def override(): + async def override() -> None: context = await browser.new_context() page = await context.new_page() await page.goto('data:text/html, ') @@ -328,15 +362,17 @@ async def override(): async def test_csp_should_be_able_to_navigate_after_disabling_javascript( - browser, server -): + browser: Browser, server: Server +) -> None: context = await browser.new_context(java_script_enabled=False) page = await context.new_page() await page.goto(server.EMPTY_PAGE) await context.close() -async def test_pages_should_return_all_of_the_pages(context, server): +async def test_pages_should_return_all_of_the_pages( + context: BrowserContext, server: Server +) -> None: page = await context.new_page() second = await context.new_page() all_pages = context.pages @@ -345,17 +381,19 @@ async def test_pages_should_return_all_of_the_pages(context, server): assert second in all_pages -async def test_pages_should_close_all_belonging_pages_once_closing_context(context): +async def test_pages_should_close_all_belonging_pages_once_closing_context( + context: BrowserContext, +) -> None: await context.new_page() assert len(context.pages) == 1 await context.close() assert context.pages == [] -async def test_expose_binding_should_work(context): +async def test_expose_binding_should_work(context: BrowserContext) -> None: binding_source = [] - def binding(source, a, b): + def binding(source: Any, a: int, b: int) -> int: binding_source.append(source) return a + b @@ -369,7 +407,7 @@ def binding(source, a, b): assert result == 11 -async def test_expose_function_should_work(context): +async def test_expose_function_should_work(context: BrowserContext) -> None: await context.expose_function("add", lambda a, b: a + b) page = await context.new_page() await page.expose_function("mul", lambda a, b: a * b) @@ -384,8 +422,8 @@ async def test_expose_function_should_work(context): async def test_expose_function_should_throw_for_duplicate_registrations( - context, server -): + context: BrowserContext, server: Server +) -> None: await context.expose_function("foo", lambda: None) await context.expose_function("bar", lambda: None) with pytest.raises(Error) as exc_info: @@ -408,8 +446,8 @@ async def test_expose_function_should_throw_for_duplicate_registrations( async def test_expose_function_should_be_callable_from_inside_add_init_script( - context, server -): + context: BrowserContext, server: Server +) -> None: args = [] await context.expose_function("woof", lambda arg: args.append(arg)) await context.add_init_script("woof('context')") @@ -422,10 +460,10 @@ async def test_expose_function_should_be_callable_from_inside_add_init_script( assert args == ["context", "page"] -async def test_expose_bindinghandle_should_work(context): - targets = [] +async def test_expose_bindinghandle_should_work(context: BrowserContext) -> None: + targets: List[JSHandle] = [] - def logme(t): + def logme(t: JSHandle) -> int: targets.append(t) return 17 @@ -436,16 +474,16 @@ def logme(t): assert result == 17 -async def test_route_should_intercept(context, server): +async def test_route_should_intercept(context: BrowserContext, server: Server) -> None: intercepted = [] - def handle(route, request): + def handle(route: Route, request: Request) -> None: intercepted.append(True) assert "empty.html" in request.url assert request.headers["user-agent"] assert request.method == "GET" assert request.post_data is None - assert request.is_navigation_request + assert request.is_navigation_request() assert request.resource_type == "document" assert request.frame == page.main_frame assert request.frame.url == "about:blank" @@ -454,17 +492,18 @@ def handle(route, request): await context.route("**/empty.html", lambda route, request: handle(route, request)) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.ok assert intercepted == [True] await context.close() -async def test_route_should_unroute(context, server): +async def test_route_should_unroute(context: BrowserContext, server: Server) -> None: page = await context.new_page() - intercepted = [] + intercepted: List[int] = [] - def handler(route, request, ordinal): + def handler(route: Route, request: Request, ordinal: int) -> None: intercepted.append(ordinal) asyncio.create_task(route.continue_()) @@ -476,7 +515,7 @@ def handler(route, request, ordinal): "**/empty.html", lambda route, request: handler(route, request, 3) ) - def handler4(route, request): + def handler4(route: Route, request: Request) -> None: handler(route, request, 4) await context.route(re.compile("empty.html"), handler4) @@ -495,7 +534,9 @@ def handler4(route, request): assert intercepted == [1] -async def test_route_should_yield_to_page_route(context, server): +async def test_route_should_yield_to_page_route( + context: BrowserContext, server: Server +) -> None: await context.route( "**/empty.html", lambda route, request: asyncio.create_task( @@ -512,11 +553,14 @@ async def test_route_should_yield_to_page_route(context, server): ) response = await page.goto(server.EMPTY_PAGE) + assert response assert response.ok assert await response.text() == "page" -async def test_route_should_fall_back_to_context_route(context, server): +async def test_route_should_fall_back_to_context_route( + context: BrowserContext, server: Server +) -> None: await context.route( "**/empty.html", lambda route, request: asyncio.create_task( @@ -533,46 +577,59 @@ async def test_route_should_fall_back_to_context_route(context, server): ) response = await page.goto(server.EMPTY_PAGE) + assert response assert response.ok assert await response.text() == "context" -async def test_auth_should_fail_without_credentials(context, server): +async def test_auth_should_fail_without_credentials( + context: BrowserContext, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 401 -async def test_auth_should_work_with_correct_credentials(browser, server): +async def test_auth_should_work_with_correct_credentials( + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") context = await browser.new_context( http_credentials={"username": "user", "password": "pass"} ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 200 await context.close() -async def test_auth_should_fail_with_wrong_credentials(browser, server): +async def test_auth_should_fail_with_wrong_credentials( + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") context = await browser.new_context( http_credentials={"username": "foo", "password": "bar"} ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 401 await context.close() -async def test_auth_should_return_resource_body(browser, server): +async def test_auth_should_return_resource_body( + browser: Browser, server: Server +) -> None: server.set_auth("/playground.html", "user", "pass") context = await browser.new_context( http_credentials={"username": "user", "password": "pass"} ) page = await context.new_page() response = await page.goto(server.PREFIX + "/playground.html") + assert response assert response.status == 200 assert await page.title() == "Playground" assert "Playground" in await response.text() @@ -580,8 +637,8 @@ async def test_auth_should_return_resource_body(browser, server): async def test_should_work_with_correct_credentials_and_matching_origin( - browser, server -): + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") context = await browser.new_context( http_credentials={ @@ -592,13 +649,14 @@ async def test_should_work_with_correct_credentials_and_matching_origin( ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 200 await context.close() async def test_should_work_with_correct_credentials_and_matching_origin_case_insensitive( - browser, server -): + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") context = await browser.new_context( http_credentials={ @@ -609,13 +667,14 @@ async def test_should_work_with_correct_credentials_and_matching_origin_case_ins ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 200 await context.close() async def test_should_fail_with_correct_credentials_and_mismatching_scheme( - browser, server -): + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") context = await browser.new_context( http_credentials={ @@ -626,28 +685,31 @@ async def test_should_fail_with_correct_credentials_and_mismatching_scheme( ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 401 await context.close() async def test_should_fail_with_correct_credentials_and_mismatching_hostname( - browser, server -): + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") hostname = urlparse(server.PREFIX).hostname + assert hostname origin = server.PREFIX.replace(hostname, "mismatching-hostname") context = await browser.new_context( http_credentials={"username": "user", "password": "pass", "origin": origin} ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 401 await context.close() async def test_should_fail_with_correct_credentials_and_mismatching_port( - browser, server -): + browser: Browser, server: Server +) -> None: server.set_auth("/empty.html", "user", "pass") origin = server.PREFIX.replace(str(server.PORT), str(server.PORT + 1)) context = await browser.new_context( @@ -655,11 +717,14 @@ async def test_should_fail_with_correct_credentials_and_mismatching_port( ) page = await context.new_page() response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 401 await context.close() -async def test_offline_should_work_with_initial_option(browser, server): +async def test_offline_should_work_with_initial_option( + browser: Browser, server: Server +) -> None: context = await browser.new_context(offline=True) page = await context.new_page() with pytest.raises(Error) as exc_info: @@ -667,11 +732,14 @@ async def test_offline_should_work_with_initial_option(browser, server): assert exc_info.value await context.set_offline(False) response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 200 await context.close() -async def test_offline_should_emulate_navigator_online(context, server): +async def test_offline_should_emulate_navigator_online( + context: BrowserContext, server: Server +) -> None: page = await context.new_page() assert await page.evaluate("window.navigator.onLine") await context.set_offline(True) @@ -680,7 +748,9 @@ async def test_offline_should_emulate_navigator_online(context, server): assert await page.evaluate("window.navigator.onLine") -async def test_page_event_should_have_url(context, server): +async def test_page_event_should_have_url( + context: BrowserContext, server: Server +) -> None: page = await context.new_page() async with context.expect_page() as other_page_info: await page.evaluate("url => window.open(url)", server.EMPTY_PAGE) @@ -688,7 +758,9 @@ async def test_page_event_should_have_url(context, server): assert other_page.url == server.EMPTY_PAGE -async def test_page_event_should_have_url_after_domcontentloaded(context, server): +async def test_page_event_should_have_url_after_domcontentloaded( + context: BrowserContext, server: Server +) -> None: page = await context.new_page() async with context.expect_page() as other_page_info: await page.evaluate("url => window.open(url)", server.EMPTY_PAGE) @@ -698,8 +770,8 @@ async def test_page_event_should_have_url_after_domcontentloaded(context, server async def test_page_event_should_have_about_blank_url_with_domcontentloaded( - context, server -): + context: BrowserContext, server: Server +) -> None: page = await context.new_page() async with context.expect_page() as other_page_info: await page.evaluate("url => window.open(url)", "about:blank") @@ -709,8 +781,8 @@ async def test_page_event_should_have_about_blank_url_with_domcontentloaded( async def test_page_event_should_have_about_blank_for_empty_url_with_domcontentloaded( - context, server -): + context: BrowserContext, server: Server +) -> None: page = await context.new_page() async with context.expect_page() as other_page_info: await page.evaluate("window.open()") @@ -720,8 +792,8 @@ async def test_page_event_should_have_about_blank_for_empty_url_with_domcontentl async def test_page_event_should_report_when_a_new_page_is_created_and_closed( - context, server -): + context: BrowserContext, server: Server +) -> None: page = await context.new_page() async with context.expect_page() as page_info: await page.evaluate( @@ -739,7 +811,7 @@ async def test_page_event_should_report_when_a_new_page_is_created_and_closed( assert other_page in all_pages close_event_received = [] - other_page.once("close", lambda: close_event_received.append(True)) + other_page.once("close", lambda _: close_event_received.append(True)) await other_page.close() assert close_event_received == [True] @@ -748,7 +820,9 @@ async def test_page_event_should_report_when_a_new_page_is_created_and_closed( assert other_page not in all_pages -async def test_page_event_should_report_initialized_pages(context, server): +async def test_page_event_should_report_initialized_pages( + context: BrowserContext, server: Server +) -> None: async with context.expect_page() as page_info: await context.new_page() new_page = await page_info.value @@ -760,7 +834,9 @@ async def test_page_event_should_report_initialized_pages(context, server): assert popup.url == "about:blank" -async def test_page_event_should_have_an_opener(context, server): +async def test_page_event_should_have_an_opener( + context: BrowserContext, server: Server +) -> None: page = await context.new_page() await page.goto(server.EMPTY_PAGE) async with context.expect_page() as page_info: @@ -771,12 +847,14 @@ async def test_page_event_should_have_an_opener(context, server): assert await page.opener() is None -async def test_page_event_should_fire_page_lifecycle_events(context, server): - events = [] +async def test_page_event_should_fire_page_lifecycle_events( + context: BrowserContext, server: Server +) -> None: + events: List[str] = [] - def handle_page(page): + def handle_page(page: Page) -> None: events.append("CREATED: " + page.url) - page.on("close", lambda: events.append("DESTROYED: " + page.url)) + page.on("close", lambda _: events.append("DESTROYED: " + page.url)) context.on("page", handle_page) @@ -787,7 +865,9 @@ def handle_page(page): @pytest.mark.skip_browser("webkit") -async def test_page_event_should_work_with_shift_clicking(context, server): +async def test_page_event_should_work_with_shift_clicking( + context: BrowserContext, server: Server +) -> None: # WebKit: Shift+Click does not open a new window. page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -799,7 +879,9 @@ async def test_page_event_should_work_with_shift_clicking(context, server): @pytest.mark.only_browser("chromium") -async def test_page_event_should_work_with_ctrl_clicking(context, server, is_mac): +async def test_page_event_should_work_with_ctrl_clicking( + context: BrowserContext, server: Server, is_mac: bool +) -> None: # Firefox: reports an opener in this case. # WebKit: Ctrl+Click does not open a new tab. page = await context.new_page() @@ -811,7 +893,7 @@ async def test_page_event_should_work_with_ctrl_clicking(context, server, is_mac assert await popup.opener() is None -async def test_strict_selectors_on_context(browser: Browser, server: Server): +async def test_strict_selectors_on_context(browser: Browser, server: Server) -> None: context = await browser.new_context(strict_selectors=True) page = await context.new_page() await page.goto(server.EMPTY_PAGE) @@ -829,7 +911,7 @@ async def test_strict_selectors_on_context(browser: Browser, server: Server): @pytest.mark.skip_browser("webkit") # https://bugs.webkit.org/show_bug.cgi?id=225281 -async def test_should_support_forced_colors(browser: Browser): +async def test_should_support_forced_colors(browser: Browser) -> None: context = await browser.new_context(forced_colors="active") page = await context.new_page() assert await page.evaluate("matchMedia('(forced-colors: active)').matches") diff --git a/tests/async/test_browsercontext_add_cookies.py b/tests/async/test_browsercontext_add_cookies.py index 6ce2e60882..744e989d1d 100644 --- a/tests/async/test_browsercontext_add_cookies.py +++ b/tests/async/test_browsercontext_add_cookies.py @@ -14,13 +14,16 @@ import asyncio import datetime +from typing import Callable, List import pytest -from playwright.async_api import Error +from playwright.async_api import Browser, BrowserContext, Error, Page +from tests.server import HttpRequestWithPostBody, Server +from tests.utils import must -async def test_should_work(context, page, server): +async def test_should_work(context: BrowserContext, page: Page, server: Server) -> None: await page.goto(server.EMPTY_PAGE) await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "password", "value": "123456"}] @@ -28,7 +31,9 @@ async def test_should_work(context, page, server): assert await page.evaluate("() => document.cookie") == "password=123456" -async def test_should_roundtrip_cookie(context, page, server): +async def test_should_roundtrip_cookie( + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) # @see https://en.wikipedia.org/wiki/Year_2038_problem date = int(datetime.datetime(2038, 1, 1).timestamp() * 1000) @@ -48,11 +53,13 @@ async def test_should_roundtrip_cookie(context, page, server): assert await context.cookies() == cookies -async def test_should_send_cookie_header(server, context): - cookie = [] +async def test_should_send_cookie_header( + server: Server, context: BrowserContext +) -> None: + cookie: List[str] = [] - def handler(request): - cookie.extend(request.requestHeaders.getRawHeaders("cookie")) + def handler(request: HttpRequestWithPostBody) -> None: + cookie.extend(must(request.requestHeaders.getRawHeaders("cookie"))) request.finish() server.set_route("/empty.html", handler) @@ -64,7 +71,9 @@ def handler(request): assert cookie == ["cookie=value"] -async def test_should_isolate_cookies_in_browser_contexts(context, server, browser): +async def test_should_isolate_cookies_in_browser_contexts( + context: BrowserContext, server: Server, browser: Browser +) -> None: another_context = await browser.new_context() await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "isolatecookie", "value": "page1value"}] @@ -84,7 +93,9 @@ async def test_should_isolate_cookies_in_browser_contexts(context, server, brows await another_context.close() -async def test_should_isolate_session_cookies(context, server, browser): +async def test_should_isolate_session_cookies( + context: BrowserContext, server: Server, browser: Browser +) -> None: server.set_route( "/setcookie.html", lambda r: ( @@ -110,7 +121,9 @@ async def test_should_isolate_session_cookies(context, server, browser): await context_b.close() -async def test_should_isolate_persistent_cookies(context, server, browser): +async def test_should_isolate_persistent_cookies( + context: BrowserContext, server: Server, browser: Browser +) -> None: server.set_route( "/setcookie.html", lambda r: ( @@ -136,10 +149,12 @@ async def test_should_isolate_persistent_cookies(context, server, browser): await context_2.close() -async def test_should_isolate_send_cookie_header(server, context, browser): - cookie = [] +async def test_should_isolate_send_cookie_header( + server: Server, context: BrowserContext, browser: Browser +) -> None: + cookie: List[str] = [] - def handler(request): + def handler(request: HttpRequestWithPostBody) -> None: cookie.extend(request.requestHeaders.getRawHeaders("cookie") or []) request.finish() @@ -161,7 +176,9 @@ def handler(request): await context_2.close() -async def test_should_isolate_cookies_between_launches(browser_factory, server): +async def test_should_isolate_cookies_between_launches( + browser_factory: Callable[..., "asyncio.Future[Browser]"], server: Server +) -> None: browser_1 = await browser_factory() context_1 = await browser_1.new_context() await context_1.add_cookies( @@ -183,7 +200,9 @@ async def test_should_isolate_cookies_between_launches(browser_factory, server): await browser_2.close() -async def test_should_set_multiple_cookies(context, page, server): +async def test_should_set_multiple_cookies( + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) await context.add_cookies( [ @@ -202,7 +221,9 @@ async def test_should_set_multiple_cookies(context, page, server): ) -async def test_should_have_expires_set_to_neg_1_for_session_cookies(context, server): +async def test_should_have_expires_set_to_neg_1_for_session_cookies( + context: BrowserContext, server: Server +) -> None: await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "expires", "value": "123456"}] ) @@ -210,7 +231,9 @@ async def test_should_have_expires_set_to_neg_1_for_session_cookies(context, ser assert cookies[0]["expires"] == -1 -async def test_should_set_cookie_with_reasonable_defaults(context, server, is_chromium): +async def test_should_set_cookie_with_reasonable_defaults( + context: BrowserContext, server: Server, is_chromium: bool +) -> None: await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "defaults", "value": "123456"}] ) @@ -230,7 +253,9 @@ async def test_should_set_cookie_with_reasonable_defaults(context, server, is_ch ] -async def test_should_set_a_cookie_with_a_path(context, page, server, is_chromium): +async def test_should_set_a_cookie_with_a_path( + context: BrowserContext, page: Page, server: Server, is_chromium: bool +) -> None: await page.goto(server.PREFIX + "/grid.html") await context.add_cookies( [ @@ -261,7 +286,9 @@ async def test_should_set_a_cookie_with_a_path(context, page, server, is_chromiu assert await page.evaluate("document.cookie") == "gridcookie=GRID" -async def test_should_not_set_a_cookie_with_blank_page_url(context, server): +async def test_should_not_set_a_cookie_with_blank_page_url( + context: BrowserContext, server: Server +) -> None: with pytest.raises(Error) as exc_info: await context.add_cookies( [ @@ -275,7 +302,9 @@ async def test_should_not_set_a_cookie_with_blank_page_url(context, server): ) -async def test_should_not_set_a_cookie_on_a_data_url_page(context): +async def test_should_not_set_a_cookie_on_a_data_url_page( + context: BrowserContext, +) -> None: with pytest.raises(Error) as exc_info: await context.add_cookies( [ @@ -292,8 +321,8 @@ async def test_should_not_set_a_cookie_on_a_data_url_page(context): async def test_should_default_to_setting_secure_cookie_for_https_websites( - context, page, server -): + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) SECURE_URL = "https://example.com" await context.add_cookies([{"url": SECURE_URL, "name": "foo", "value": "bar"}]) @@ -302,8 +331,8 @@ async def test_should_default_to_setting_secure_cookie_for_https_websites( async def test_should_be_able_to_set_unsecure_cookie_for_http_website( - context, page, server -): + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) HTTP_URL = "http://example.com" await context.add_cookies([{"url": HTTP_URL, "name": "foo", "value": "bar"}]) @@ -312,8 +341,8 @@ async def test_should_be_able_to_set_unsecure_cookie_for_http_website( async def test_should_set_a_cookie_on_a_different_domain( - context, page, server, is_chromium -): + context: BrowserContext, page: Page, server: Server, is_chromium: bool +) -> None: await page.goto(server.EMPTY_PAGE) await context.add_cookies( [{"url": "https://www.example.com", "name": "example-cookie", "value": "best"}] @@ -333,7 +362,9 @@ async def test_should_set_a_cookie_on_a_different_domain( ] -async def test_should_set_cookies_for_a_frame(context, page, server): +async def test_should_set_cookies_for_a_frame( + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) await context.add_cookies( [{"url": server.PREFIX, "name": "frame-cookie", "value": "value"}] @@ -355,8 +386,12 @@ async def test_should_set_cookies_for_a_frame(context, page, server): async def test_should_not_block_third_party_cookies( - context, page, server, is_chromium, is_firefox -): + context: BrowserContext, + page: Page, + server: Server, + is_chromium: bool, + is_firefox: bool, +) -> None: await page.goto(server.EMPTY_PAGE) await page.evaluate( """src => { diff --git a/tests/async/test_browsercontext_clearcookies.py b/tests/async/test_browsercontext_clearcookies.py index 27e33126be..6b0f03283e 100644 --- a/tests/async/test_browsercontext_clearcookies.py +++ b/tests/async/test_browsercontext_clearcookies.py @@ -12,8 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +from playwright.async_api import Browser, BrowserContext, Page +from tests.server import Server -async def test_should_clear_cookies(context, page, server): + +async def test_should_clear_cookies( + context: BrowserContext, page: Page, server: Server +) -> None: await page.goto(server.EMPTY_PAGE) await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "cookie1", "value": "1"}] @@ -25,7 +30,9 @@ async def test_should_clear_cookies(context, page, server): assert await page.evaluate("document.cookie") == "" -async def test_should_isolate_cookies_when_clearing(context, server, browser): +async def test_should_isolate_cookies_when_clearing( + context: BrowserContext, server: Server, browser: Browser +) -> None: another_context = await browser.new_context() await context.add_cookies( [{"url": server.EMPTY_PAGE, "name": "page1cookie", "value": "page1value"}] diff --git a/tests/async/test_browsercontext_cookies.py b/tests/async/test_browsercontext_cookies.py index b810373078..e994395075 100644 --- a/tests/async/test_browsercontext_cookies.py +++ b/tests/async/test_browsercontext_cookies.py @@ -16,12 +16,19 @@ import pytest +from playwright.async_api import BrowserContext, Page +from tests.server import Server -async def test_should_return_no_cookies_in_pristine_browser_context(context): + +async def test_should_return_no_cookies_in_pristine_browser_context( + context: BrowserContext, +) -> None: assert await context.cookies() == [] -async def test_should_get_a_cookie(context, page, server, is_chromium): +async def test_should_get_a_cookie( + context: BrowserContext, page: Page, server: Server, is_chromium: bool +) -> None: await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -44,7 +51,9 @@ async def test_should_get_a_cookie(context, page, server, is_chromium): ] -async def test_should_get_a_non_session_cookie(context, page, server, is_chromium): +async def test_should_get_a_non_session_cookie( + context: BrowserContext, page: Page, server: Server, is_chromium: bool +) -> None: await page.goto(server.EMPTY_PAGE) # @see https://en.wikipedia.org/wiki/Year_2038_problem date = int(datetime.datetime(2038, 1, 1).timestamp() * 1000) @@ -81,7 +90,9 @@ async def test_should_get_a_non_session_cookie(context, page, server, is_chromiu ] -async def test_should_properly_report_httpOnly_cookie(context, page, server): +async def test_should_properly_report_httpOnly_cookie( + context: BrowserContext, page: Page, server: Server +) -> None: server.set_route( "/empty.html", lambda r: ( @@ -97,8 +108,8 @@ async def test_should_properly_report_httpOnly_cookie(context, page, server): async def test_should_properly_report_strict_sameSite_cookie( - context, page, server, is_webkit, is_win -): + context: BrowserContext, page: Page, server: Server, is_webkit: bool, is_win: bool +) -> None: if is_webkit and is_win: pytest.skip() @@ -116,8 +127,8 @@ async def test_should_properly_report_strict_sameSite_cookie( async def test_should_properly_report_lax_sameSite_cookie( - context, page, server, is_webkit, is_win -): + context: BrowserContext, page: Page, server: Server, is_webkit: bool, is_win: bool +) -> None: if is_webkit and is_win: pytest.skip() @@ -134,7 +145,9 @@ async def test_should_properly_report_lax_sameSite_cookie( assert cookies[0]["sameSite"] == "Lax" -async def test_should_get_multiple_cookies(context, page, server, is_chromium): +async def test_should_get_multiple_cookies( + context: BrowserContext, page: Page, server: Server, is_chromium: bool +) -> None: await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -170,7 +183,9 @@ async def test_should_get_multiple_cookies(context, page, server, is_chromium): ] -async def test_should_get_cookies_from_multiple_urls(context, is_chromium): +async def test_should_get_cookies_from_multiple_urls( + context: BrowserContext, is_chromium: bool +) -> None: await context.add_cookies( [ {"url": "https://foo.com", "name": "doggo", "value": "woofs"}, diff --git a/tests/async/test_browsercontext_events.py b/tests/async/test_browsercontext_events.py index dd86427862..9cae739dc3 100644 --- a/tests/async/test_browsercontext_events.py +++ b/tests/async/test_browsercontext_events.py @@ -13,10 +13,12 @@ # limitations under the License. import asyncio +from typing import Optional import pytest -from playwright.sync_api import Page +from playwright.async_api import Page +from tests.utils import must from ..server import HttpRequestWithPostBody, Server @@ -86,7 +88,7 @@ async def test_console_event_should_work_in_immediately_closed_popup( async def test_dialog_event_should_work1(page: Page) -> None: - prompt_task = None + prompt_task: Optional[asyncio.Future[str]] = None async def open_dialog() -> None: nonlocal prompt_task @@ -101,11 +103,11 @@ async def open_dialog() -> None: assert dialog1.message == "hey?" assert dialog1.page == page await dialog1.accept("hello") - assert await prompt_task == "hello" + assert await must(prompt_task) == "hello" async def test_dialog_event_should_work_in_popup(page: Page) -> None: - prompt_task = None + prompt_task: Optional[asyncio.Future[str]] = None async def open_dialog() -> None: nonlocal prompt_task @@ -121,7 +123,7 @@ async def open_dialog() -> None: assert dialog.message == "hey?" assert dialog.page == popup await dialog.accept("hello") - assert await prompt_task == "hello" + assert await must(prompt_task) == "hello" # console message from javascript: url is not reported at all @@ -179,7 +181,7 @@ def handle_route(request: HttpRequestWithPostBody) -> None: assert dialog.page == popup await dialog.accept("hello") await promise - await popup.evaluate("window.result") == "hello" + assert await popup.evaluate("window.result") == "hello" async def test_console_event_should_work_with_context_manager(page: Page) -> None: diff --git a/tests/async/test_browsercontext_proxy.py b/tests/async/test_browsercontext_proxy.py index e76c59e1d8..07f52a5623 100644 --- a/tests/async/test_browsercontext_proxy.py +++ b/tests/async/test_browsercontext_proxy.py @@ -12,20 +12,29 @@ # See the License for the specific language governing permissions and # limitations under the License. +import asyncio import base64 +from typing import AsyncGenerator, Awaitable, Callable import pytest from flaky import flaky +from playwright.async_api import Browser, BrowserContext +from tests.server import HttpRequestWithPostBody, Server + @pytest.fixture(scope="session") -async def browser(browser_factory): +async def browser( + browser_factory: "Callable[..., asyncio.Future[Browser]]", +) -> AsyncGenerator[Browser, None]: browser = await browser_factory(proxy={"server": "dummy"}) yield browser await browser.close() -async def test_should_use_proxy(context_factory, server): +async def test_should_use_proxy( + context_factory: "Callable[..., asyncio.Future[BrowserContext]]", server: Server +) -> None: server.set_route( "/target.html", lambda r: ( @@ -39,7 +48,9 @@ async def test_should_use_proxy(context_factory, server): assert await page.title() == "Served by the proxy" -async def test_should_use_proxy_for_second_page(context_factory, server): +async def test_should_use_proxy_for_second_page( + context_factory: "Callable[..., Awaitable[BrowserContext]]", server: Server +) -> None: server.set_route( "/target.html", lambda r: ( @@ -58,7 +69,9 @@ async def test_should_use_proxy_for_second_page(context_factory, server): assert await page2.title() == "Served by the proxy" -async def test_should_work_with_ip_port_notion(context_factory, server): +async def test_should_work_with_ip_port_notion( + context_factory: "Callable[..., Awaitable[BrowserContext]]", server: Server +) -> None: server.set_route( "/target.html", lambda r: ( @@ -73,8 +86,10 @@ async def test_should_work_with_ip_port_notion(context_factory, server): @flaky # Upstream flaky -async def test_should_authenticate(context_factory, server): - def handler(req): +async def test_should_authenticate( + context_factory: "Callable[..., Awaitable[BrowserContext]]", server: Server +) -> None: + def handler(req: HttpRequestWithPostBody) -> None: auth = req.getHeader("proxy-authorization") if not auth: req.setHeader( @@ -102,8 +117,10 @@ def handler(req): @flaky # Upstream flaky -async def test_should_authenticate_with_empty_password(context_factory, server): - def handler(req): +async def test_should_authenticate_with_empty_password( + context_factory: "Callable[..., Awaitable[BrowserContext]]", server: Server +) -> None: + def handler(req: HttpRequestWithPostBody) -> None: auth = req.getHeader("proxy-authorization") if not auth: req.setHeader( diff --git a/tests/async/test_browsercontext_request_fallback.py b/tests/async/test_browsercontext_request_fallback.py index 4407dc3f96..b003a9db9c 100644 --- a/tests/async/test_browsercontext_request_fallback.py +++ b/tests/async/test_browsercontext_request_fallback.py @@ -13,6 +13,7 @@ # limitations under the License. import asyncio +from typing import Any, Callable, Coroutine, cast import pytest @@ -29,28 +30,28 @@ async def test_should_fall_back( page: Page, context: BrowserContext, server: Server ) -> None: intercepted = [] + + def _handler1(route: Route) -> None: + intercepted.append(1) + asyncio.create_task(route.fallback()) + + await context.route("**/empty.html", _handler1) + + def _handler2(route: Route) -> None: + intercepted.append(2) + asyncio.create_task(route.fallback()) + await context.route( "**/empty.html", - lambda route: ( - intercepted.append(1), - asyncio.create_task(route.fallback()), - ), - ) - await context.route( - "**/empty.html", - lambda route: ( - intercepted.append(2), - asyncio.create_task(route.fallback()), - ), - ) - await context.route( - "**/empty.html", - lambda route: ( - intercepted.append(3), - asyncio.create_task(route.fallback()), - ), + _handler2, ) + def _handler3(route: Route) -> None: + intercepted.append(3) + asyncio.create_task(route.fallback()) + + await context.route("**/empty.html", _handler3) + await page.goto(server.EMPTY_PAGE) assert intercepted == [3, 2, 1] @@ -60,8 +61,8 @@ async def test_should_fall_back_async_delayed( ) -> None: intercepted = [] - def create_handler(i: int): - async def handler(route): + def create_handler(i: int) -> Callable[[Route], Coroutine]: + async def handler(route: Route) -> None: intercepted.append(i) await asyncio.sleep(0.1) await route.fallback() @@ -90,6 +91,7 @@ async def test_should_chain_once( ) resp = await page.goto(server.PREFIX + "/madeup.txt") + assert resp body = await resp.body() assert body == b"fulfilled one" @@ -99,7 +101,7 @@ async def test_should_not_chain_fulfill( ) -> None: failed = [False] - def handler(route: Route): + def handler(route: Route) -> None: failed[0] = True await context.route("**/empty.html", handler) @@ -112,6 +114,7 @@ def handler(route: Route): ) response = await page.goto(server.EMPTY_PAGE) + assert response body = await response.body() assert body == b"fulfilled" assert not failed[0] @@ -126,7 +129,7 @@ async def test_should_not_chain_abort( ) -> None: failed = [False] - def handler(route: Route): + def handler(route: Route) -> None: failed[0] = True await context.route("**/empty.html", handler) @@ -153,9 +156,9 @@ async def test_should_fall_back_after_exception( ) -> None: await context.route("**/empty.html", lambda route: route.continue_()) - async def handler(route: Route): + async def handler(route: Route) -> None: try: - await route.fulfill(response=47) + await route.fulfill(response=cast(Any, {})) except Exception: await route.fallback() @@ -169,14 +172,14 @@ async def test_should_amend_http_headers( ) -> None: values = [] - async def handler(route: Route): + async def handler(route: Route) -> None: values.append(route.request.headers.get("foo")) values.append(await route.request.header_value("FOO")) await route.continue_() await context.route("**/sleep.zzz", handler) - async def handler_with_header_mods(route: Route): + async def handler_with_header_mods(route: Route) -> None: await route.fallback(headers={**route.request.headers, "FOO": "bar"}) await context.route("**/*", handler_with_header_mods) @@ -204,13 +207,13 @@ async def test_should_delete_header_with_undefined_value( intercepted_request = [] - async def capture_and_continue(route: Route, request: Request): + async def capture_and_continue(route: Route, request: Request) -> None: intercepted_request.append(request) await route.continue_() await context.route("**/*", capture_and_continue) - async def delete_foo_header(route: Route, request: Request): + async def delete_foo_header(route: Route, request: Request) -> None: headers = await request.all_headers() await route.fallback(headers={**headers, "foo": None}) @@ -247,13 +250,12 @@ async def test_should_amend_method( await page.goto(server.EMPTY_PAGE) method = [] - await context.route( - "**/*", - lambda route: ( - method.append(route.request.method), - asyncio.create_task(route.continue_()), - ), - ) + + def _handler1(route: Route) -> None: + method.append(route.request.method) + asyncio.create_task(route.continue_()) + + await context.route("**/*", _handler1) await context.route( "**/*", lambda route: asyncio.create_task(route.fallback(method="POST")) ) @@ -271,18 +273,22 @@ async def test_should_override_request_url( page: Page, context: BrowserContext, server: Server ) -> None: url = [] + + def _handler1(route: Route) -> None: + url.append(route.request.url) + asyncio.create_task(route.continue_()) + await context.route( "**/global-var.html", - lambda route: ( - url.append(route.request.url), - asyncio.create_task(route.continue_()), - ), + _handler1, ) + + def _handler2(route: Route) -> None: + asyncio.create_task(route.fallback(url=server.PREFIX + "/global-var.html")) + await context.route( "**/foo", - lambda route: asyncio.create_task( - route.fallback(url=server.PREFIX + "/global-var.html") - ), + _handler2, ) [server_request, response, _] = await asyncio.gather( @@ -304,13 +310,12 @@ async def test_should_amend_post_data( ) -> None: await page.goto(server.EMPTY_PAGE) post_data = [] - await context.route( - "**/*", - lambda route: ( - post_data.append(route.request.post_data), - asyncio.create_task(route.continue_()), - ), - ) + + def _handler1(route: Route) -> None: + post_data.append(route.request.post_data) + asyncio.create_task(route.continue_()) + + await context.route("**/*", _handler1) await context.route( "**/*", lambda route: asyncio.create_task(route.fallback(post_data="doggo")) ) @@ -324,22 +329,20 @@ async def test_should_amend_post_data( async def test_should_amend_binary_post_data( page: Page, context: BrowserContext, server: Server -): +) -> None: await page.goto(server.EMPTY_PAGE) post_data_buffer = [] - await context.route( - "**/*", - lambda route: ( - post_data_buffer.append(route.request.post_data), - asyncio.create_task(route.continue_()), - ), - ) - await context.route( - "**/*", - lambda route: asyncio.create_task( - route.fallback(post_data=b"\x00\x01\x02\x03\x04") - ), - ) + + def _handler1(route: Route) -> None: + post_data_buffer.append(route.request.post_data) + asyncio.create_task(route.continue_()) + + await context.route("**/*", _handler1) + + def _handler2(route: Route) -> None: + asyncio.create_task(route.fallback(post_data=b"\x00\x01\x02\x03\x04")) + + await context.route("**/*", _handler2) [server_request, result] = await asyncio.gather( server.wait_for_request("/sleep.zzz"), @@ -355,30 +358,42 @@ async def test_should_chain_fallback_into_page( context: BrowserContext, page: Page, server: Server ) -> None: intercepted = [] - await context.route( - "**/empty.html", - lambda route: (intercepted.append(1), asyncio.create_task(route.fallback())), - ) - await context.route( - "**/empty.html", - lambda route: (intercepted.append(2), asyncio.create_task(route.fallback())), - ) - await context.route( - "**/empty.html", - lambda route: (intercepted.append(3), asyncio.create_task(route.fallback())), - ) - await page.route( - "**/empty.html", - lambda route: (intercepted.append(4), asyncio.create_task(route.fallback())), - ) - await page.route( - "**/empty.html", - lambda route: (intercepted.append(5), asyncio.create_task(route.fallback())), - ) - await page.route( - "**/empty.html", - lambda route: (intercepted.append(6), asyncio.create_task(route.fallback())), - ) + + def _handler1(route: Route) -> None: + intercepted.append(1) + asyncio.create_task(route.fallback()) + + await context.route("**/empty.html", _handler1) + + def _handler2(route: Route) -> None: + intercepted.append(2) + asyncio.create_task(route.fallback()) + + await context.route("**/empty.html", _handler2) + + def _handler3(route: Route) -> None: + intercepted.append(3) + asyncio.create_task(route.fallback()) + + await context.route("**/empty.html", _handler3) + + def _handler4(route: Route) -> None: + intercepted.append(4) + asyncio.create_task(route.fallback()) + + await page.route("**/empty.html", _handler4) + + def _handler5(route: Route) -> None: + intercepted.append(5) + asyncio.create_task(route.fallback()) + + await page.route("**/empty.html", _handler5) + + def _handler6(route: Route) -> None: + intercepted.append(6) + asyncio.create_task(route.fallback()) + + await page.route("**/empty.html", _handler6) await page.goto(server.EMPTY_PAGE) assert intercepted == [6, 5, 4, 3, 2, 1] diff --git a/tests/async/test_browsercontext_request_intercept.py b/tests/async/test_browsercontext_request_intercept.py index 763073df0d..ffb5103c19 100644 --- a/tests/async/test_browsercontext_request_intercept.py +++ b/tests/async/test_browsercontext_request_intercept.py @@ -23,8 +23,8 @@ async def test_should_fulfill_intercepted_response( page: Page, context: BrowserContext, server: Server -): - async def handle(route: Route): +) -> None: + async def handle(route: Route) -> None: response = await page.request.fetch(route.request) await route.fulfill( response=response, @@ -36,6 +36,7 @@ async def handle(route: Route): await context.route("**/*", handle) response = await page.goto(server.PREFIX + "/empty.html") + assert response assert response.status == 201 assert response.headers["foo"] == "bar" assert response.headers["content-type"] == "text/plain" @@ -44,8 +45,8 @@ async def handle(route: Route): async def test_should_fulfill_response_with_empty_body( page: Page, context: BrowserContext, server: Server -): - async def handle(route: Route): +) -> None: + async def handle(route: Route) -> None: response = await page.request.fetch(route.request) await route.fulfill( response=response, status=201, body="", headers={"content-length": "0"} @@ -53,26 +54,28 @@ async def handle(route: Route): await context.route("**/*", handle) response = await page.goto(server.PREFIX + "/title.html") + assert response assert response.status == 201 assert await response.text() == "" async def test_should_override_with_defaults_when_intercepted_response_not_provided( page: Page, context: BrowserContext, server: Server, browser_name: str -): - def server_handler(request: http.Request): +) -> None: + def server_handler(request: http.Request) -> None: request.setHeader("foo", "bar") request.write("my content".encode()) request.finish() server.set_route("/empty.html", server_handler) - async def handle(route: Route): + async def handle(route: Route) -> None: await page.request.fetch(route.request) await route.fulfill(status=201) await context.route("**/*", handle) response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 201 assert await response.text() == "" if browser_name == "webkit": @@ -83,8 +86,8 @@ async def handle(route: Route): async def test_should_fulfill_with_any_response( page: Page, context: BrowserContext, server: Server -): - def server_handler(request: http.Request): +) -> None: + def server_handler(request: http.Request) -> None: request.setHeader("foo", "bar") request.write("Woo-hoo".encode()) request.finish() @@ -98,6 +101,7 @@ def server_handler(request: http.Request): ), ) response = await page.goto(server.EMPTY_PAGE) + assert response assert response.status == 201 assert await response.text() == "Woo-hoo" assert response.headers["foo"] == "bar" @@ -105,15 +109,16 @@ def server_handler(request: http.Request): async def test_should_support_fulfill_after_intercept( page: Page, context: BrowserContext, server: Server, assetdir: Path -): +) -> None: request_future = asyncio.create_task(server.wait_for_request("/title.html")) - async def handle_route(route: Route): + async def handle_route(route: Route) -> None: response = await page.request.fetch(route.request) await route.fulfill(response=response) await context.route("**", handle_route) response = await page.goto(server.PREFIX + "/title.html") + assert response request = await request_future assert request.uri.decode() == "/title.html" original = (assetdir / "title.html").read_text() @@ -122,10 +127,10 @@ async def handle_route(route: Route): async def test_should_give_access_to_the_intercepted_response( page: Page, context: BrowserContext, server: Server -): +) -> None: await page.goto(server.EMPTY_PAGE) - route_task = asyncio.Future() + route_task: "asyncio.Future[Route]" = asyncio.Future() await context.route("**/title.html", lambda route: route_task.set_result(route)) eval_task = asyncio.create_task( @@ -155,10 +160,10 @@ async def test_should_give_access_to_the_intercepted_response( async def test_should_give_access_to_the_intercepted_response_body( page: Page, context: BrowserContext, server: Server -): +) -> None: await page.goto(server.EMPTY_PAGE) - route_task = asyncio.Future() + route_task: "asyncio.Future[Route]" = asyncio.Future() await context.route("**/simple.json", lambda route: route_task.set_result(route)) eval_task = asyncio.create_task( diff --git a/tests/async/test_browsercontext_storage_state.py b/tests/async/test_browsercontext_storage_state.py index b4214e310c..4a00da1c3d 100644 --- a/tests/async/test_browsercontext_storage_state.py +++ b/tests/async/test_browsercontext_storage_state.py @@ -14,9 +14,12 @@ import asyncio import json +from pathlib import Path +from playwright.async_api import Browser, BrowserContext -async def test_should_capture_local_storage(context, is_webkit, is_win): + +async def test_should_capture_local_storage(context: BrowserContext) -> None: page1 = await context.new_page() await page1.route( "**/*", lambda route: asyncio.create_task(route.fulfill(body="")) @@ -39,7 +42,7 @@ async def test_should_capture_local_storage(context, is_webkit, is_win): } -async def test_should_set_local_storage(browser, is_webkit, is_win): +async def test_should_set_local_storage(browser: Browser) -> None: context = await browser.new_context( storage_state={ "origins": [ @@ -61,7 +64,9 @@ async def test_should_set_local_storage(browser, is_webkit, is_win): await context.close() -async def test_should_round_trip_through_the_file(browser, context, tmpdir): +async def test_should_round_trip_through_the_file( + browser: Browser, context: BrowserContext, tmpdir: Path +) -> None: page1 = await context.new_page() await page1.route( "**/*", diff --git a/tests/async/test_browsertype_connect.py b/tests/async/test_browsertype_connect.py index ffb3fed311..556e8eefdf 100644 --- a/tests/async/test_browsertype_connect.py +++ b/tests/async/test_browsertype_connect.py @@ -23,13 +23,13 @@ from playwright.async_api import BrowserType, Error, Playwright, Route from tests.conftest import RemoteServer -from tests.server import Server +from tests.server import HttpRequestWithPostBody, Server from tests.utils import parse_trace async def test_browser_type_connect_should_be_able_to_reconnect_to_a_browser( - server: Server, browser_type: BrowserType, launch_server -): + server: Server, browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) browser_context = await browser.new_context() @@ -48,8 +48,8 @@ async def test_browser_type_connect_should_be_able_to_reconnect_to_a_browser( async def test_browser_type_connect_should_be_able_to_connect_two_browsers_at_the_same_time( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser1 = await browser_type.connect(remote_server.ws_endpoint) assert len(browser1.contexts) == 0 @@ -71,8 +71,8 @@ async def test_browser_type_connect_should_be_able_to_connect_two_browsers_at_th async def test_browser_type_connect_disconnected_event_should_be_emitted_when_browser_is_closed_or_server_is_closed( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: # Launch another server to not affect other tests. remote = launch_server() @@ -81,8 +81,8 @@ async def test_browser_type_connect_disconnected_event_should_be_emitted_when_br disconnected1 = [] disconnected2 = [] - browser1.on("disconnected", lambda: disconnected1.append(True)) - browser2.on("disconnected", lambda: disconnected2.append(True)) + browser1.on("disconnected", lambda _: disconnected1.append(True)) + browser2.on("disconnected", lambda _: disconnected2.append(True)) page2 = await browser2.new_page() @@ -100,15 +100,15 @@ async def test_browser_type_connect_disconnected_event_should_be_emitted_when_br async def test_browser_type_connect_disconnected_event_should_be_emitted_when_remote_killed_connection( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: # Launch another server to not affect other tests. remote = launch_server() browser = await browser_type.connect(remote.ws_endpoint) disconnected = [] - browser.on("disconnected", lambda: disconnected.append(True)) + browser.on("disconnected", lambda _: disconnected.append(True)) page = await browser.new_page() remote.kill() with pytest.raises(Error): @@ -117,8 +117,8 @@ async def test_browser_type_connect_disconnected_event_should_be_emitted_when_re async def test_browser_type_disconnected_event_should_have_browser_as_argument( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) event_payloads = [] @@ -128,8 +128,8 @@ async def test_browser_type_disconnected_event_should_have_browser_as_argument( async def test_browser_type_connect_set_browser_connected_state( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) assert browser.is_connected() @@ -138,8 +138,8 @@ async def test_browser_type_connect_set_browser_connected_state( async def test_browser_type_connect_should_throw_when_used_after_is_connected_returns_false( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) page = await browser.new_page() @@ -153,8 +153,8 @@ async def test_browser_type_connect_should_throw_when_used_after_is_connected_re async def test_browser_type_connect_should_reject_navigation_when_browser_closes( - server: Server, browser_type: BrowserType, launch_server -): + server: Server, browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) page = await browser.new_page() @@ -166,9 +166,9 @@ async def test_browser_type_connect_should_reject_navigation_when_browser_closes async def test_should_not_allow_getting_the_path( - browser_type: BrowserType, launch_server, server: Server -): - def handle_download(request): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer], server: Server +) -> None: + def handle_download(request: HttpRequestWithPostBody) -> None: request.setHeader("Content-Type", "application/octet-stream") request.setHeader("Content-Disposition", "attachment") request.write(b"Hello world") @@ -193,8 +193,11 @@ def handle_download(request): async def test_prevent_getting_video_path( - browser_type: BrowserType, launch_server, tmpdir, server -): + browser_type: BrowserType, + launch_server: Callable[[], RemoteServer], + tmpdir: Path, + server: Server, +) -> None: remote_server = launch_server() browser = await browser_type.connect(remote_server.ws_endpoint) page = await browser.new_page(record_video_dir=tmpdir) @@ -211,8 +214,8 @@ async def test_prevent_getting_video_path( async def test_connect_to_closed_server_without_hangs( - browser_type: BrowserType, launch_server -): + browser_type: BrowserType, launch_server: Callable[[], RemoteServer] +) -> None: remote_server = launch_server() remote_server.kill() with pytest.raises(Error) as exc: @@ -253,10 +256,9 @@ async def handle_request(route: Route) -> None: async def test_should_upload_large_file( browser_type: BrowserType, launch_server: Callable[[], RemoteServer], - playwright: Playwright, server: Server, - tmp_path, -): + tmp_path: Path, +) -> None: remote = launch_server() browser = await browser_type.connect(remote.ws_endpoint) @@ -295,11 +297,13 @@ async def test_should_upload_large_file( assert contents[:1024] == data # flake8: noqa: E203 assert contents[len(contents) - 1024 :] == data + assert request.post_body match = re.search( rb'^.*Content-Disposition: form-data; name="(?P.*)"; filename="(?P.*)".*$', request.post_body, re.MULTILINE, ) + assert match assert match.group("name") == b"file1" assert match.group("filename") == b"200MB.zip" @@ -309,7 +313,7 @@ async def test_should_record_trace_with_source( server: Server, tmp_path: Path, browser_type: BrowserType, -): +) -> None: remote = launch_server() browser = await browser_type.connect(remote.ws_endpoint) context = await browser.new_context() @@ -338,9 +342,8 @@ async def test_should_record_trace_with_source( async def test_should_record_trace_with_relative_trace_path( launch_server: Callable[[], RemoteServer], server: Server, - tmp_path: Path, browser_type: BrowserType, -): +) -> None: remote = launch_server() browser = await browser_type.connect(remote.ws_endpoint) context = await browser.new_context() diff --git a/tests/async/test_browsertype_connect_cdp.py b/tests/async/test_browsertype_connect_cdp.py index 0e1e940096..de3d96e770 100644 --- a/tests/async/test_browsertype_connect_cdp.py +++ b/tests/async/test_browsertype_connect_cdp.py @@ -26,7 +26,7 @@ async def test_connect_to_an_existing_cdp_session( launch_arguments: Dict, browser_type: BrowserType -): +) -> None: port = find_free_port() browser_server = await browser_type.launch( **launch_arguments, args=[f"--remote-debugging-port={port}"] @@ -39,7 +39,7 @@ async def test_connect_to_an_existing_cdp_session( async def test_connect_to_an_existing_cdp_session_twice( launch_arguments: Dict, browser_type: BrowserType, server: Server -): +) -> None: port = find_free_port() browser_server = await browser_type.launch( **launch_arguments, args=[f"--remote-debugging-port={port}"] @@ -72,7 +72,7 @@ def _ws_endpoint_from_url(url: str) -> str: async def test_conect_over_a_ws_endpoint( launch_arguments: Dict, browser_type: BrowserType, server: Server -): +) -> None: port = find_free_port() browser_server = await browser_type.launch( **launch_arguments, args=[f"--remote-debugging-port={port}"] @@ -90,8 +90,8 @@ async def test_conect_over_a_ws_endpoint( async def test_connect_over_cdp_passing_header_works( - launch_arguments: Dict, browser_type: BrowserType, server: Server -): + browser_type: BrowserType, server: Server +) -> None: request = asyncio.create_task(server.wait_for_request("/ws")) with pytest.raises(Error): await browser_type.connect_over_cdp( diff --git a/tests/async/test_cdp_session.py b/tests/async/test_cdp_session.py index af8f0715d9..5118ab9fa5 100644 --- a/tests/async/test_cdp_session.py +++ b/tests/async/test_cdp_session.py @@ -14,12 +14,13 @@ import pytest -from playwright.async_api import Browser, Error +from playwright.async_api import Browser, Error, Page +from tests.server import Server from tests.utils import TARGET_CLOSED_ERROR_MESSAGE @pytest.mark.only_browser("chromium") -async def test_should_work(page): +async def test_should_work(page: Page) -> None: client = await page.context.new_cdp_session(page) events = [] client.on("Runtime.consoleAPICalled", lambda params: events.append(params)) @@ -35,7 +36,7 @@ async def test_should_work(page): @pytest.mark.only_browser("chromium") -async def test_should_receive_events(page, server): +async def test_should_receive_events(page: Page, server: Server) -> None: client = await page.context.new_cdp_session(page) await client.send("Network.enable") events = [] @@ -45,7 +46,7 @@ async def test_should_receive_events(page, server): @pytest.mark.only_browser("chromium") -async def test_should_be_able_to_detach_session(page): +async def test_should_be_able_to_detach_session(page: Page) -> None: client = await page.context.new_cdp_session(page) await client.send("Runtime.enable") eval_response = await client.send( @@ -61,7 +62,7 @@ async def test_should_be_able_to_detach_session(page): @pytest.mark.only_browser("chromium") -async def test_should_not_break_page_close(browser): +async def test_should_not_break_page_close(browser: Browser) -> None: context = await browser.new_context() page = await context.new_page() session = await page.context.new_cdp_session(page) @@ -71,7 +72,7 @@ async def test_should_not_break_page_close(browser): @pytest.mark.only_browser("chromium") -async def test_should_detach_when_page_closes(browser): +async def test_should_detach_when_page_closes(browser: Browser) -> None: context = await browser.new_context() page = await context.new_page() session = await context.new_cdp_session(page) @@ -82,7 +83,7 @@ async def test_should_detach_when_page_closes(browser): @pytest.mark.only_browser("chromium") -async def test_should_work_with_main_frame(browser: Browser): +async def test_should_work_with_main_frame(browser: Browser) -> None: context = await browser.new_context() page = await context.new_page() client = await context.new_cdp_session(page.main_frame) diff --git a/tests/async/test_check.py b/tests/async/test_check.py index d4fcf43f0f..428ca2a7bc 100644 --- a/tests/async/test_check.py +++ b/tests/async/test_check.py @@ -12,32 +12,34 @@ # See the License for the specific language governing permissions and # limitations under the License. +from playwright.async_api import Page -async def test_check_the_box(page): + +async def test_check_the_box(page: Page) -> None: await page.set_content('') await page.check("input") assert await page.evaluate("checkbox.checked") -async def test_not_check_the_checked_box(page): +async def test_not_check_the_checked_box(page: Page) -> None: await page.set_content('') await page.check("input") assert await page.evaluate("checkbox.checked") -async def test_uncheck_the_box(page): +async def test_uncheck_the_box(page: Page) -> None: await page.set_content('') await page.uncheck("input") assert await page.evaluate("checkbox.checked") is False -async def test_not_uncheck_the_unchecked_box(page): +async def test_not_uncheck_the_unchecked_box(page: Page) -> None: await page.set_content('') await page.uncheck("input") assert await page.evaluate("checkbox.checked") is False -async def test_check_the_box_by_label(page): +async def test_check_the_box_by_label(page: Page) -> None: await page.set_content( '' ) @@ -45,7 +47,7 @@ async def test_check_the_box_by_label(page): assert await page.evaluate("checkbox.checked") -async def test_check_the_box_outside_label(page): +async def test_check_the_box_outside_label(page: Page) -> None: await page.set_content( '
' ) @@ -53,7 +55,7 @@ async def test_check_the_box_outside_label(page): assert await page.evaluate("checkbox.checked") -async def test_check_the_box_inside_label_without_id(page): +async def test_check_the_box_inside_label_without_id(page: Page) -> None: await page.set_content( '' ) @@ -61,7 +63,7 @@ async def test_check_the_box_inside_label_without_id(page): assert await page.evaluate("checkbox.checked") -async def test_check_radio(page): +async def test_check_radio(page: Page) -> None: await page.set_content( """ one @@ -72,7 +74,7 @@ async def test_check_radio(page): assert await page.evaluate("two.checked") -async def test_check_the_box_by_aria_role(page): +async def test_check_the_box_by_aria_role(page: Page) -> None: await page.set_content( """ ') with pytest.raises(Error) as exc: @@ -184,29 +220,42 @@ async def test_should_support_javascript_enabled_option(launch_persistent, is_we assert "something is not defined" in exc.value.message -async def test_should_support_http_credentials_option(server, launch_persistent): +async def test_should_support_http_credentials_option( + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent( http_credentials={"username": "user", "password": "pass"} ) server.set_auth("/playground.html", "user", "pass") response = await page.goto(server.PREFIX + "/playground.html") + assert response assert response.status == 200 -async def test_should_support_offline_option(server, launch_persistent): +async def test_should_support_offline_option( + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(offline=True) with pytest.raises(Error): await page.goto(server.EMPTY_PAGE) -async def test_should_support_has_touch_option(server, launch_persistent): +async def test_should_support_has_touch_option( + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(has_touch=True) await page.goto(server.PREFIX + "/mobile.html") assert await page.evaluate('() => "ontouchstart" in window') @pytest.mark.skip_browser("firefox") -async def test_should_work_in_persistent_context(server, launch_persistent): +async def test_should_work_in_persistent_context( + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: # Firefox does not support mobile. (page, context) = await launch_persistent( viewport={"width": 320, "height": 480}, is_mobile=True @@ -215,7 +264,9 @@ async def test_should_work_in_persistent_context(server, launch_persistent): assert await page.evaluate("() => window.innerWidth") == 980 -async def test_should_support_color_scheme_option(server, launch_persistent): +async def test_should_support_color_scheme_option( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(color_scheme="dark") assert ( await page.evaluate('() => matchMedia("(prefers-color-scheme: light)").matches') @@ -226,7 +277,9 @@ async def test_should_support_color_scheme_option(server, launch_persistent): ) -async def test_should_support_timezone_id_option(launch_persistent): +async def test_should_support_timezone_id_option( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(timezone_id="America/Jamaica") assert ( await page.evaluate("() => new Date(1479579154987).toString()") @@ -234,14 +287,17 @@ async def test_should_support_timezone_id_option(launch_persistent): ) -async def test_should_support_locale_option(launch_persistent): +async def test_should_support_locale_option( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(locale="fr-FR") assert await page.evaluate("() => navigator.language") == "fr-FR" async def test_should_support_geolocation_and_permission_option( - server, launch_persistent -): + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent( geolocation={"longitude": 10, "latitude": 10}, permissions=["geolocation"] ) @@ -255,14 +311,19 @@ async def test_should_support_geolocation_and_permission_option( async def test_should_support_ignore_https_errors_option( - https_server, launch_persistent -): + https_server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(ignore_https_errors=True) response = await page.goto(https_server.EMPTY_PAGE) + assert response assert response.ok -async def test_should_support_extra_http_headers_option(server, launch_persistent): +async def test_should_support_extra_http_headers_option( + server: Server, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(extra_http_headers={"foo": "bar"}) [request, _] = await asyncio.gather( server.wait_for_request("/empty.html"), @@ -271,7 +332,10 @@ async def test_should_support_extra_http_headers_option(server, launch_persisten assert request.getHeader("foo") == "bar" -async def test_should_accept_user_data_dir(server, tmpdir, launch_persistent): +async def test_should_accept_user_data_dir( + tmpdir: Path, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent() # Note: we need an open page to make sure its functional. assert len(os.listdir(tmpdir)) > 0 @@ -280,8 +344,11 @@ async def test_should_accept_user_data_dir(server, tmpdir, launch_persistent): async def test_should_restore_state_from_userDataDir( - browser_type, launch_arguments, server, tmp_path_factory -): + browser_type: BrowserType, + launch_arguments: Dict, + server: Server, + tmp_path_factory: pytest.TempPathFactory, +) -> None: user_data_dir1 = tmp_path_factory.mktemp("test") browser_context = await browser_type.launch_persistent_context( user_data_dir1, **launch_arguments @@ -309,7 +376,9 @@ async def test_should_restore_state_from_userDataDir( await browser_context3.close() -async def test_should_have_default_url_when_launching_browser(launch_persistent): +async def test_should_have_default_url_when_launching_browser( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent() urls = list(map(lambda p: p.url, context.pages)) assert urls == ["about:blank"] @@ -317,28 +386,35 @@ async def test_should_have_default_url_when_launching_browser(launch_persistent) @pytest.mark.skip_browser("firefox") async def test_should_throw_if_page_argument_is_passed( - browser_type, server, tmpdir, launch_arguments -): + browser_type: BrowserType, server: Server, tmpdir: Path, launch_arguments: Dict +) -> None: options = {**launch_arguments, "args": [server.EMPTY_PAGE]} with pytest.raises(Error) as exc: await browser_type.launch_persistent_context(tmpdir, **options) assert "can not specify page" in exc.value.message -async def test_should_fire_close_event_for_a_persistent_context(launch_persistent): +async def test_should_fire_close_event_for_a_persistent_context( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent() - fired_event = asyncio.Future() - context.on("close", lambda: fired_event.set_result(True)) + fired_event: "asyncio.Future[bool]" = asyncio.Future() + context.on("close", lambda _: fired_event.set_result(True)) await context.close() await fired_event -async def test_should_support_reduced_motion(launch_persistent): +async def test_should_support_reduced_motion( + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent(reduced_motion="reduce") assert await page.evaluate("matchMedia('(prefers-reduced-motion: reduce)').matches") -async def test_should_support_har_option(browser, server, assetdir, launch_persistent): +async def test_should_support_har_option( + assetdir: Path, + launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]", +) -> None: (page, context) = await launch_persistent() await page.route_from_har(har=assetdir / "har-fulfill.har") await page.goto("http://no.playwright/") diff --git a/tests/async/test_device_descriptors.py b/tests/async/test_device_descriptors.py index ee2e72cdd9..f14fc1ffd9 100644 --- a/tests/async/test_device_descriptors.py +++ b/tests/async/test_device_descriptors.py @@ -11,11 +11,15 @@ # 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. +from typing import Dict + import pytest +from playwright.async_api import Playwright + @pytest.mark.only_browser("chromium") -async def test_should_work(playwright, launch_arguments) -> None: +async def test_should_work(playwright: Playwright, launch_arguments: Dict) -> None: device_descriptor = playwright.devices["Pixel 2"] device_type = device_descriptor["default_browser_type"] browser = await playwright[device_type].launch(**launch_arguments) diff --git a/tests/async/test_dialog.py b/tests/async/test_dialog.py index 41028d1349..7ad32f8bc8 100644 --- a/tests/async/test_dialog.py +++ b/tests/async/test_dialog.py @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. -from playwright.async_api import Dialog, Page +from playwright.async_api import Browser, Dialog, Page -async def test_should_fire(page: Page, server): +async def test_should_fire(page: Page) -> None: result = [] - async def on_dialog(dialog: Dialog): + async def on_dialog(dialog: Dialog) -> None: result.append(True) assert dialog.type == "alert" assert dialog.default_value == "" @@ -30,10 +30,10 @@ async def on_dialog(dialog: Dialog): assert result -async def test_should_allow_accepting_prompts(page: Page, server): +async def test_should_allow_accepting_prompts(page: Page) -> None: result = [] - async def on_dialog(dialog: Dialog): + async def on_dialog(dialog: Dialog) -> None: result.append(True) assert dialog.type == "prompt" assert dialog.default_value == "yes." @@ -45,10 +45,10 @@ async def on_dialog(dialog: Dialog): assert result -async def test_should_dismiss_the_prompt(page: Page, server): +async def test_should_dismiss_the_prompt(page: Page) -> None: result = [] - async def on_dialog(dialog: Dialog): + async def on_dialog(dialog: Dialog) -> None: result.append(True) await dialog.dismiss() @@ -57,10 +57,10 @@ async def on_dialog(dialog: Dialog): assert result -async def test_should_accept_the_confirm_prompt(page: Page, server): +async def test_should_accept_the_confirm_prompt(page: Page) -> None: result = [] - async def on_dialog(dialog: Dialog): + async def on_dialog(dialog: Dialog) -> None: result.append(True) await dialog.accept() @@ -69,10 +69,10 @@ async def on_dialog(dialog: Dialog): assert result -async def test_should_dismiss_the_confirm_prompt(page: Page, server): +async def test_should_dismiss_the_confirm_prompt(page: Page) -> None: result = [] - async def on_dialog(dialog: Dialog): + async def on_dialog(dialog: Dialog) -> None: result.append(True) await dialog.dismiss() @@ -81,7 +81,9 @@ async def on_dialog(dialog: Dialog): assert result -async def test_should_be_able_to_close_context_with_open_alert(browser): +async def test_should_be_able_to_close_context_with_open_alert( + browser: Browser, +) -> None: context = await browser.new_context() page = await context.new_page() async with page.expect_event("dialog"): @@ -89,12 +91,12 @@ async def test_should_be_able_to_close_context_with_open_alert(browser): await context.close() -async def test_should_auto_dismiss_the_prompt_without_listeners(page): +async def test_should_auto_dismiss_the_prompt_without_listeners(page: Page) -> None: result = await page.evaluate('() => prompt("question?")') assert not result -async def test_should_auto_dismiss_the_alert_without_listeners(page): +async def test_should_auto_dismiss_the_alert_without_listeners(page: Page) -> None: await page.set_content( '
Click me
' ) diff --git a/tests/async/test_dispatch_event.py b/tests/async/test_dispatch_event.py index 897d797efd..50b02ba2ef 100644 --- a/tests/async/test_dispatch_event.py +++ b/tests/async/test_dispatch_event.py @@ -13,13 +13,21 @@ # limitations under the License. -async def test_should_dispatch_click_event(page, server): +from playwright.async_api import Page, Selectors +from tests.server import Server + +from .utils import Utils + + +async def test_should_dispatch_click_event(page: Page, server: Server) -> None: await page.goto(server.PREFIX + "/input/button.html") await page.dispatch_event("button", "click") assert await page.evaluate("() => result") == "Clicked" -async def test_should_dispatch_click_event_properties(page, server): +async def test_should_dispatch_click_event_properties( + page: Page, server: Server +) -> None: await page.goto(server.PREFIX + "/input/button.html") await page.dispatch_event("button", "click") assert await page.evaluate("() => bubbles") @@ -27,7 +35,7 @@ async def test_should_dispatch_click_event_properties(page, server): assert await page.evaluate("() => composed") -async def test_should_dispatch_click_svg(page): +async def test_should_dispatch_click_svg(page: Page) -> None: await page.set_content( """ @@ -39,7 +47,9 @@ async def test_should_dispatch_click_svg(page): assert await page.evaluate("() => window.__CLICKED") == 42 -async def test_should_dispatch_click_on_a_span_with_an_inline_element_inside(page): +async def test_should_dispatch_click_on_a_span_with_an_inline_element_inside( + page: Page, +) -> None: await page.set_content( """
hi
') element = await page.query_selector("div") + assert element assert await element.bounding_box() is None -async def test_bounding_box_force_a_layout(page, server): +async def test_bounding_box_force_a_layout(page: Page, server: Server) -> None: await page.set_viewport_size({"width": 500, "height": 500}) await page.set_content('
hello
') element_handle = await page.query_selector("div") + assert element_handle await page.evaluate('element => element.style.height = "200px"', element_handle) box = await element_handle.bounding_box() assert box == {"x": 8, "y": 8, "width": 100, "height": 200} -async def test_bounding_box_with_SVG_nodes(page, server): +async def test_bounding_box_with_SVG_nodes(page: Page, server: Server) -> None: await page.set_content( """ """ ) element = await page.query_selector("#therect") + assert element pw_bounding_box = await element.bounding_box() web_bounding_box = await page.evaluate( """e => { @@ -71,13 +82,14 @@ async def test_bounding_box_with_SVG_nodes(page, server): @pytest.mark.skip_browser("firefox") -async def test_bounding_box_with_page_scale(browser, server): +async def test_bounding_box_with_page_scale(browser: Browser, server: Server) -> None: context = await browser.new_context( viewport={"width": 400, "height": 400}, is_mobile=True ) page = await context.new_page() await page.goto(server.PREFIX + "/input/button.html") button = await page.query_selector("button") + assert button await button.evaluate( """button => { document.body.style.margin = '0' @@ -90,6 +102,7 @@ async def test_bounding_box_with_page_scale(browser, server): ) box = await button.bounding_box() + assert box assert round(box["x"] * 100) == 17 * 100 assert round(box["y"] * 100) == 23 * 100 assert round(box["width"] * 100) == 200 * 100 @@ -97,7 +110,9 @@ async def test_bounding_box_with_page_scale(browser, server): await context.close() -async def test_bounding_box_when_inline_box_child_is_outside_of_viewport(page, server): +async def test_bounding_box_when_inline_box_child_is_outside_of_viewport( + page: Page, +) -> None: await page.set_content( """