验证
介绍
🌐 Introduction
Playwright 在称为 浏览器上下文 的隔离环境中执行测试。这种隔离模型提高了可重复性并防止了连锁测试失败。测试可以加载已有的认证状态,这消除了每次测试都进行认证的需求,并加快了测试执行速度。
🌐 Playwright executes tests in isolated environments called browser contexts. This isolation model improves reproducibility and prevents cascading test failures. Tests can load existing authenticated state. This eliminates the need to authenticate in every test and speeds up test execution.
核心理念
🌐 Core concepts
无论你选择哪种身份验证策略,你都可能将经过身份验证的浏览器状态存储在文件系统上。
🌐 Regardless of the authentication strategy you choose, you are likely to store authenticated browser state on the file system.
我们建议创建 playwright/.auth 目录并将其添加到你的 .gitignore 中。你的认证程序将生成已认证的浏览器状态并将其保存到该 playwright/.auth 目录中的文件中。之后,测试将重用该状态并以已认证的状态启动。
🌐 We recommend to create playwright/.auth directory and add it to your .gitignore. Your authentication routine will produce authenticated browser state and save it to a file in this playwright/.auth directory. Later on, tests will reuse this state and start already authenticated.
浏览器状态文件可能包含敏感的 Cookie 和头信息,这些信息可能被用来冒充你或你的测试账户。我们强烈不建议将它们提交到私有或公共仓库。
🌐 The browser state file may contain sensitive cookies and headers that could be used to impersonate you or your test account. We strongly discourage checking them into private or public repositories.
- Bash
- PowerShell
- Batch
mkdir -p playwright/.auth
echo $'\nplaywright/.auth' >> .gitignore
New-Item -ItemType Directory -Force -Path playwright\.auth
Add-Content -path .gitignore "`r`nplaywright/.auth"
md playwright\.auth
echo. >> .gitignore
echo "playwright/.auth" >> .gitignore
每次测试前登录
🌐 Signing in before each test
Playwright API 可以自动化与登录表单的交互。
🌐 The Playwright API can automate interaction with a login form.
以下示例演示了如何登录 GitHub。执行这些步骤后,浏览器上下文将被认证。
🌐 The following example logs into GitHub. Once these steps are executed, the browser context will be authenticated.
- Sync
- Async
page = context.new_page()
page.goto('https://github.com/login')
# Interact with login form
page.get_by_label("Username or email address").fill("username")
page.get_by_label("Password").fill("password")
page.get_by_role("button", name="Sign in").click()
# Continue with the test
page = await context.new_page()
await page.goto('https://github.com/login')
# Interact with login form
await page.get_by_label("Username or email address").fill("username")
await page.get_by_label("Password").fill("password")
await page.get_by_role("button", name="Sign in").click()
# Continue with the test
每次测试都重新登录会降低测试执行速度。为减轻这种情况,可以重用现有的认证状态。
🌐 Redoing login for every test can slow down test execution. To mitigate that, reuse existing authentication state instead.
重用登录状态
🌐 Reusing signed in state
Playwright 提供了一种在测试中重用已登录状态的方法。这样你只需登录一次,就可以在所有测试中跳过登录步骤。
🌐 Playwright provides a way to reuse the signed-in state in the tests. That way you can log in only once and then skip the log in step for all of the tests.
Web 应用使用基于 Cookie 或基于令牌的身份验证,其中经过身份验证的状态会存储在 cookies、本地存储、IndexedDB 或作为通行密钥(WebAuthn 凭证)。Playwright 提供了 browser_context.storage_state() 方法,可以用它从已认证的上下文中获取存储状态,然后创建带有预填充状态的新上下文。
🌐 Web apps use cookie-based or token-based authentication, where authenticated state is stored as cookies, in local storage, in IndexedDB, or as passkeys (WebAuthn credentials). Playwright provides browser_context.storage_state() method that can be used to retrieve storage state from authenticated contexts and then create new contexts with prepopulated state.
Cookie、本地存储、IndexedDB 和虚拟 WebAuthn 凭证(通行密钥)可以在不同的浏览器间使用。这取决于你的应用认证模型,可能需要某些组合的 Cookie、本地存储、IndexedDB 或通行密钥。
🌐 Cookies, local storage, IndexedDB and virtual WebAuthn credentials (passkeys) can be used across different browsers. They depend on your application's authentication model which may require some combination of cookies, local storage, IndexedDB or passkeys.
以下代码片段从已验证的上下文中检索状态,并使用该状态创建一个新的上下文。
🌐 The following code snippet retrieves state from an authenticated context and creates a new context with that state.
- Sync
- Async
# Save storage state into the file.
storage = context.storage_state(path="state.json")
# Create a new context with the saved storage state.
context = browser.new_context(storage_state="state.json")
# Save storage state into the file.
storage = await context.storage_state(path="state.json")
# Create a new context with the saved storage state.
context = await browser.new_context(storage_state="state.json")
高级场景
🌐 Advanced scenarios
会话存储
🌐 Session storage
重用已认证的状态涵盖了 cookies、本地存储、IndexedDB 以及基于 passkey (WebAuthn) 的认证。很少情况下,会话存储 会用来保存与登录状态相关的信息。会话存储是针对特定域的,并且不会在页面加载间保持。Playwright 并没有提供持久化会话存储的 API,但可以使用下面的代码片段来保存/加载会话存储。
🌐 Reusing authenticated state covers cookies, local storage, IndexedDB and passkey (WebAuthn) based authentication. Rarely, session storage is used for storing information associated with the signed-in state. Session storage is specific to a particular domain and is not persisted across page loads. Playwright does not provide API to persist session storage, but the following snippet can be used to save/load session storage.
- Sync
- Async
import os
# Get session storage and store as env variable
session_storage = page.evaluate("() => JSON.stringify(sessionStorage)")
os.environ["SESSION_STORAGE"] = session_storage
# Set session storage in a new context
session_storage = os.environ["SESSION_STORAGE"]
escaped_session_storage = session_storage.replace("\\", "\\\\").replace("'", "\\'")
context.add_init_script("""(storage => {
if (window.location.hostname === 'example.com') {
const entries = JSON.parse(storage)
for (const [key, value] of Object.entries(entries)) {
window.sessionStorage.setItem(key, value)
}
}
})('""" + escaped_session_storage + "')")
import os
# Get session storage and store as env variable
session_storage = await page.evaluate("() => JSON.stringify(sessionStorage)")
os.environ["SESSION_STORAGE"] = session_storage
# Set session storage in a new context
session_storage = os.environ["SESSION_STORAGE"]
escaped_session_storage = session_storage.replace("\\", "\\\\").replace("'", "\\'")
await context.add_init_script("""(storage => {
if (window.location.hostname === 'example.com') {
const entries = JSON.parse(storage)
for (const [key, value] of Object.entries(entries)) {
window.sessionStorage.setItem(key, value)
}
}
})('""" + escaped_session_storage + "')")