You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

99 lines
3.3 KiB

from __future__ import annotations
from collections.abc import Callable
from pathlib import Path
from typing import Pattern
from playwright.sync_api import Download, Page, expect
def login(
page: Page,
base_url: str,
*,
username: str,
password: str,
expected_path: str | Pattern[str] | None = None,
) -> None:
page.goto(f"{base_url}/auth/login")
expect(page.get_by_label("用户名")).to_be_editable()
page.get_by_label("用户名").fill(username)
page.get_by_label("密码").fill(password)
page.get_by_role("button", name="登录").click()
if expected_path is not None:
expect_path(page, base_url, expected_path)
def logout(page: Page, base_url: str) -> None:
open_user_menu(page)
page.get_by_role("menuitem", name="退出登录").click()
expect_path(page, base_url, "/auth/login")
expect_flash(page, "您已退出登录。")
def open_user_menu(page: Page) -> None:
toggle = page.locator("#user-menu-toggle")
expect(toggle).to_be_visible()
if toggle.get_attribute("aria-expanded") != "true":
toggle.click()
expect(page.locator("#user-menu-panel")).to_be_visible()
def accept_next_dialog(page: Page, expected_message_substring: str | None = None) -> None:
def _accept(dialog) -> None:
if expected_message_substring is not None:
assert expected_message_substring in dialog.message
dialog.accept()
page.once("dialog", _accept)
def dismiss_next_dialog(page: Page, expected_message_substring: str | None = None) -> None:
def _dismiss(dialog) -> None:
if expected_message_substring is not None:
assert expected_message_substring in dialog.message
dialog.dismiss()
page.once("dialog", _dismiss)
def expect_sidebar_link(page: Page, link_name: str) -> None:
toggle_count = page.locator("[data-sidebar-toggle]").count()
for index in range(toggle_count):
toggle = page.locator("[data-sidebar-toggle]").nth(index)
if not toggle.is_visible():
continue
if toggle.get_attribute("aria-expanded") == "false":
toggle.click()
break
expect(page.get_by_role("link", name=link_name)).to_be_visible()
def expect_flash(page: Page, message: str, *, category: str | None = None) -> None:
locator = page.get_by_text(message)
expect(locator).to_be_visible()
if category is not None:
expect(page.get_by_text(f"{category}{message}")).to_be_visible()
def expect_path(page: Page, base_url: str, expected_path: str | Pattern[str]) -> None:
if isinstance(expected_path, str):
expect(page).to_have_url(f"{base_url}{expected_path}")
return
expect(page).to_have_url(expected_path)
def upload_file(page: Page, selector: str, file_path: str | Path) -> None:
input_locator = page.locator(selector)
expect(input_locator).to_be_attached()
input_locator.set_input_files(str(file_path))
def download_via_action(page: Page, action: Callable[[], None], destination: str | Path) -> Download:
destination_path = Path(destination)
destination_path.parent.mkdir(parents=True, exist_ok=True)
with page.expect_download() as download_info:
action()
download = download_info.value
download.save_as(str(destination_path))
return download