Playwright 使用指南-2

简介: Playwright 在执行操作之前对元素执行一系列可操作性检查,以确保这些操作按预期运行。

Playwright 使用指南,Playwright 入门介绍 请参考另一篇博客



此博客为官方文档译文 希望读者可以快速了解 Playwriht 可以用来做什么,怎么用。有些专业名词可能翻译不准确哈


文章目录


Playwrigh 使用指南-1

1 Auto-waiting 自动等待

2 API testing API 测试

2.1 Writing API Test 编写 API测试

2.1.1 Configure 配置

2.1.2 Write tests 编写测试

2.1.3 Setup and teardown 安装和拆卸

2.1.4 Complete test example 完整的测试示例

2.2 Prepare server state via API calls 通过API调用准备服务器状态

2.3 Check the server state after running user actions 运行用户操作后检查服务器状态

2.4 Reuse authentication state 重用的认证状态

3. Assertions 断言


Playwrigh 使用指南-1


1 Auto-waiting 自动等待


Playwright 在执行操作之前对元素执行一系列可操作性检查,以确保这些操作按预期运行。它会自动等待所有相关检查通过,然后才执行请求的操作。如果所需的检查未在给定范围内通过timeout,则操作失败并显示TimeoutError.


例如,对于[page.click(selector, **kwargs)],Playwright 将确保:


元素Attached 附加到 DOM

元素Visible 可见

元素是Stable 稳定的,就像没有动画或完成动画一样

元素 Receives Events 接收事件,因为没有被其他元素遮挡

元素已 Enabled 启用

以下是为每个操作执行的可操作性检查的完整列表:

image.png

image.png


Forcing actions 强制行为


page.click(selector, **kwargs)等一些操作支持force禁用非必要可操作性检查的选项,例如将真值传递force给page.click(selector, **kwargs)方法不会检查目标元素是否实际接收到点击事件.


Attached


当元素连接到 Document 或 ShadowRoot时,它被认为是附加的。


Visible


当元素具有非空边界框并且没有visibility:hidden计算样式时,元素被认为是可见的。请注意,大小为零或 with 的元素display:none不被视为可见。


Stable


当元素在至少两个连续的动画帧中保持相同的边界框时,元素被认为是稳定的。


Enabled


元素被视为已启用,除非它是<button>、或具有属性。<select>``<input>``<textarea>``disabled


Editable


当元素被启用并且没有readonly设置属性时,它被认为是可编辑的。


Receives Events 接收事件


当元素在动作点是指针事件的命中目标时,被认为接收指针事件。例如,当点击 点时(10;10),Playwright 会检查是否有其他元素(通常是叠加层)会捕获点击点(10;10)。


例如,考虑一个场景,Sign Up无论何时调用page.click(selector, **kwargs),Playwright 都会点击按钮:


页面正在检查用户名是否唯一且Sign Up按钮已禁用;

在与服务器核对后,禁用的Sign Up按钮将替换为另一个现在启用的按钮。


2 API testing API 测试


Playwright 可用于访问应用程序的 REST API。


有时您可能希望直接从 Python 向服务器发送请求,而无需加载页面并在其中运行 js 代码。它可能会派上用场的几个例子:


测试您的服务器 API。

在测试中访问 Web 应用程序之前准备服务器端状态。

在浏览器中运行一些操作后验证服务器端的后置条件。

所有这些都可以通过APIRequestContext方法来实现。


以下示例依赖于pytest-playwright将 Playwright 固定装置添加到 Pytest 测试运行器的包。


编写 API 测试

通过 API 调用准备服务器状态

运行用户操作后检查服务器状态

重用认证状态


2.1 Writing API Test 编写 API测试


APIRequestContext可以通过网络发送各种 HTTP(S) 请求。


以下示例演示了如何使用 Playwright 通过GitHub API测试问题创建。测试套件将执行以下操作:


在运行测试之前创建一个新的存储库。

创建一些问题并验证服务器状态。

运行测试后删除存储库。


2.1.1 Configure 配置

GitHub API 需要授权,因此我们将为所有测试配置一次令牌。在此期间,我们还将设置baseURL以简化测试。
import os
from typing import Generator
import pytest
from playwright.sync_api import Playwright, APIRequestContext
GITHUB_API_TOKEN = os.getenv("GITHUB_API_TOKEN")
assert GITHUB_API_TOKEN, "GITHUB_API_TOKEN is not set"
@pytest.fixture(scope="session")
def api_request_context(
    playwright: Playwright,
) -> Generator[APIRequestContext, None, None]:
    headers = {
        # We set this header per GitHub guidelines.
        "Accept": "application/vnd.github.v3+json",
        # Add authorization token to all requests.
        # Assuming personal access token available in the environment.
        "Authorization": f"token {GITHUB_API_TOKEN}",
    }
    request_context = playwright.request.new_context(
        base_url="https://api.github.com", extra_http_headers=headers
    )
    yield request_context
    request_context.dispose()

2.1.2 Write tests 编写测试


现在我们初始化了请求对象,我们可以添加一些测试,这些测试将在存储库中创建新问题。

import os
from typing import Generator
import pytest
from playwright.sync_api import Playwright, APIRequestContext
GITHUB_API_TOKEN = os.getenv("GITHUB_API_TOKEN")
assert GITHUB_API_TOKEN, "GITHUB_API_TOKEN is not set"
GITHUB_USER = os.getenv("GITHUB_USER")
assert GITHUB_USER, "GITHUB_USER is not set"
GITHUB_REPO = "test"
# ...
def test_should_create_bug_report(api_request_context: APIRequestContext) -> None:
    data = {
        "title": "[Bug] report 1",
        "body": "Bug description",
    }
    new_issue = api_request_context.post(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues", data=data)
    assert new_issue.ok
    issues = api_request_context.get(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues")
   assert issues.ok
    issues_response = issues.json()
    issue = list(filter(lambda issue: issue["title"] == "[Bug] report 1", issues_response))[0]
    assert issue
    assert issue["body"] == "Bug description"
def test_should_create_feature_request(api_request_context: APIRequestContext) -> None:
   data = {
        "title": "[Feature] request 1",
        "body": "Feature description",
    }
    new_issue = api_request_context.post(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues", data=data)
    assert new_issue.ok
    issues = api_request_context.get(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues")
   assert issues.ok
    issues_response = issues.json()
    issue = list(filter(lambda issue: issue["title"] == "[Feature] request 1", issues_response))[0]
    assert issue
    assert issue["body"] == "Feature description"

2.1.3 Setup and teardown 安装和拆卸


这些测试假定存储库存在。您可能希望在运行测试之前创建一个新的,然后再将其删除。为此使用会话夹具。之前的部分yield是之前的部分,之后的部分是之后的部分。

# ...
@pytest.fixture(scope="session", autouse=True)
def create_test_repository(
    api_request_context: APIRequestContext,
) -> Generator[None, None, None]:
    # Before all
    new_repo = api_request_context.post("/user/repos", data={"name": GITHUB_REPO})
    assert new_repo.ok
    yield
    # After all
    deleted_repo = api_request_context.delete(f"/repos/{GITHUB_USER}/{GITHUB_REPO}")
    assert deleted_repo.ok

2.1.4 Complete test example 完整的测试示例


以下是 API 测试的完整示例:

from enum import auto
import os
from typing import Generator
import pytest
from playwright.sync_api import Playwright, Page, APIRequestContext, expect
GITHUB_API_TOKEN = os.getenv("GITHUB_API_TOKEN")
assert GITHUB_API_TOKEN, "GITHUB_API_TOKEN is not set"
GITHUB_USER = os.getenv("GITHUB_USER")
assert GITHUB_USER, "GITHUB_USER is not set"
GITHUB_REPO = "test"
@pytest.fixture(scope="session")
def api_request_context(
    playwright: Playwright,
) -> Generator[APIRequestContext, None, None]:
    headers = {
        # We set this header per GitHub guidelines.
        "Accept": "application/vnd.github.v3+json",
        # Add authorization token to all requests.
        # Assuming personal access token available in the environment.
        "Authorization": f"token {GITHUB_API_TOKEN}",
    }
    request_context = playwright.request.new_context(
        base_url="https://api.github.com", extra_http_headers=headers
    )
    yield request_context
    request_context.dispose()
@pytest.fixture(scope="session", autouse=True)
def create_test_repository(
    api_request_context: APIRequestContext,
) -> Generator[None, None, None]:
    # Before all
    new_repo = api_request_context.post("/user/repos", data={"name": GITHUB_REPO})
    assert new_repo.ok
    yield
    # After all
    deleted_repo = api_request_context.delete(f"/repos/{GITHUB_USER}/{GITHUB_REPO}")
    assert deleted_repo.ok
def test_should_create_bug_report(api_request_context: APIRequestContext) -> None:
    data = {
        "title": "[Bug] report 1",
        "body": "Bug description",
    }
    new_issue = api_request_context.post(
        f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues", data=data
    )
    assert new_issue.ok
    issues = api_request_context.get(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues")
    assert issues.ok
    issues_response = issues.json()
    issue = list(
        filter(lambda issue: issue["title"] == "[Bug] report 1", issues_response)
    )[0]
    assert issue
    assert issue["body"] == "Bug description"
def test_should_create_feature_request(api_request_context: APIRequestContext) -> None:
    data = {
        "title": "[Feature] request 1",
        "body": "Feature description",
    }
    new_issue = api_request_context.post(
        f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues", data=data
    )
    assert new_issue.ok
    issues = api_request_context.get(f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues")
    assert issues.ok
    issues_response = issues.json()
    issue = list(
        filter(lambda issue: issue["title"] == "[Feature] request 1", issues_response)
    )[0]
    assert issue
    assert issue["body"] == "Feature description"


2.2 Prepare server state via API calls 通过API调用准备服务器状态


以下测试通过 API 创建一个新问题,然后导航到项目中所有问题的列表以检查它是否出现在列表顶部。使用LocatorAssertions执行检查。

def test_last_created_issue_should_be_first_in_the_list(api_request_context: APIRequestContext, page: Page) -> None:
    def create_issue(title: str) -> None:
        data = {
            "title": title,
            "body": "Feature description",
        }
        new_issue = api_request_context.post(
            f"/repos/{GITHUB_USER}/{GITHUB_REPO}/issues", data=data
        )
        assert new_issue.ok
    create_issue("[Feature] request 1")
    create_issue("[Feature] request 2")
    page.goto(f"https://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues")
    first_issue = page.locator("a[data-hovercard-type='issue']").first
    expect(first_issue).to_have_text("[Feature] request 2")


2.3 Check the server state after running user actions 运行用户操作后检查服务器状态


以下测试通过浏览器中的用户界面创建一个新问题,然后通过 API 检查它是否已创建:

def test_last_created_issue_should_be_on_the_server(api_request_context: APIRequestContext, page: Page) -> None:
    page.goto(f"https://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues")
    page.locator("text=New issue").click()
    page.locator("[aria-label='Title']").fill("Bug report 1")
    page.locator("[aria-label='Comment body']").fill("Bug description")
    page.locator("text=Submit new issue").click()
    issue_id = page.url.split("/")[-1]
    new_issue = api_request_context.get(f"https://github.com/{GITHUB_USER}/{GITHUB_REPO}/issues/{issue_id}")
    assert new_issue.ok
    assert new_issue.json()["title"] == "[Bug] report 1"
    assert new_issue.json()["body"] == "Bug description"


2.4 Reuse authentication state 重用的认证状态


Web 应用程序使用基于 cookie 或基于令牌的身份验证,其中经过身份验证的状态存储为cookie。Playwright 提供了api_request_context.storage_state(**kwargs)方法,该方法可用于从经过身份验证的上下文中检索存储状态,然后使用该状态创建新的上下文。


存储状态在BrowserContext和APIRequestContext之间是可互换的。您可以使用它通过 API 调用登录,然后使用已有的 cookie 创建新的上下文。以下代码片段从经过身份验证的APIRequestContext 中检索状态,并使用该状态创建一个新的BrowserContext。

request_context = playwright.request.new_context(http_credentials={"username": "test", "password": "test"})
request_context.get("https://api.example.com/login")
# Save storage state into a variable.
state = request_context.storage_state()
# Create a new context with the saved storage state.
context = browser.new_context(storage_state=state)


3. Assertions 断言


Playwright 为您提供了 Web-First Assertions 以及方便的方法来创建断言,这些断言将等待并重试,直到满足预期的条件。


考虑以下示例:


同步

from playwright.sync_api import Page, expect
def test_status_becomes_submitted(page: Page) -> None:
    # ..
    page.locator("#submit-button").click()
    expect(page.locator(".status")).to_have_text("Submitted")


异步

from playwright.async_api import Page, expect
async def test_status_becomes_submitted(page: Page) -> None:
    # ..
    await page.locator("#submit-button").click()
    await expect(page.locator(".status")).to_have_text("Submitted")


Playwright 将使用选择器重新测试节点,.status直到获取的节点具有"Submitted"文本。它将重新获取节点并一遍又一遍地检查它,直到满足条件或达到超时。您可以将此超时作为选项传递。


默认情况下,断言超时设置为 5 秒。


详细使用请参考官方文档


相关文章
|
8月前
|
Web App开发 API Python
Playwright系列(8):认识playwright 相关库
Playwright系列(8):认识playwright 相关库
214 0
Playwright系列(8):认识playwright 相关库
|
2月前
|
Web App开发 iOS开发 C++
Playwright 运行项目。
Playwright 运行项目。
52 3
|
2月前
|
Web App开发 JavaScript 测试技术
Playwright 测试夹具
Playwright 测试夹具
24 1
|
4月前
|
JavaScript
文档工具GitBook使用指南
这篇博客提供了GitBook的安装和使用指南,包括如何在本地安装Node.js和GitBook、初始化GitBook项目、生成HTML和电子书格式(PDF、mobi)的文档,以及推荐的相关阅读资源。
163 8
文档工具GitBook使用指南
|
8月前
|
Web App开发 测试技术 C++
Playwright安装与Python集成:探索跨浏览器测试的奇妙世界
Playwright是新兴的跨浏览器测试工具,相比Selenium,它支持Chrome、Firefox、WebKit,执行速度快,选择器更稳定。安装Playwright只需一条`pip install playwright`的命令,随后的`playwright install`会自动添加浏览器,无需处理浏览器驱动问题。这一优势免去了Selenium中匹配驱动的烦恼。文章适合寻求高效自动化测试解决方案的开发者。
|
8月前
|
Web App开发 Linux C++
Playwright系列(7):用VSCode 开始写Playwright 脚本
Playwright系列(7):用VSCode 开始写Playwright 脚本
1038 0
Playwright系列(7):用VSCode 开始写Playwright 脚本
|
8月前
|
Web App开发 Python
【python自动化】Playwright基础教程(二)
【python自动化】Playwright基础教程(二)
148 0
|
8月前
|
Web App开发 前端开发 程序员
【 selenium】selenium4新版本使用指南
【 selenium】selenium4新版本使用指南
1419 1
|
8月前
|
Web App开发 Linux iOS开发
PlayWright 系列1:安装
PlayWright 系列1:安装
196 0
|
8月前
|
Web App开发 存储 测试技术
Playwright系列(11):Playwright命令行
Playwright系列(11):Playwright命令行
504 0