身份验证
简介
Playwright 在称为 浏览器上下文 的隔离环境中执行测试。这种隔离模型提高了可重复性,并防止测试失败的级联效应。测试可以加载现有的认证状态。这样就无需在每个测试中进行认证,从而加快了测试执行速度。
核心概念
无论选择哪种认证策略,您都可能会将已认证的浏览器状态存储在文件系统中。
我们建议创建 playwright/.auth
目录,并将其添加到 .gitignore
文件中。您的认证程序将生成已认证的浏览器状态,并将其保存到 playwright/.auth
目录中的文件中。随后,测试将重用此状态,并以已认证的状态启动。
浏览器状态文件可能包含敏感的 cookie 和标头,这些信息可能会被用于冒充您或您的测试账户。我们强烈建议不要将其提交到私有或公共存储库中。
- 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
每次测试前登录
Playwright API 可以 自动与登录表单进行交互。
以下示例展示了登录 GitHub 的过程。执行完这些步骤后,浏览器上下文将处于已认证状态。
Page page = context.newPage();
page.navigate("https://github.com/login");
// 与登录表单进行交互
page.getByLabel("Username or email address").fill("username");
page.getByLabel("Password").fill("password");
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Sign in"))
.click();
// 继续进行测试
每次测试都重新登录会降低测试执行速度。为缓解这一问题,可以复用现有的认证状态。
复用已登录状态
Playwright 提供了一种在测试中复用已登录状态的方法。这样一来,你只需登录一次,随后所有测试都可以跳过登录步骤。
Web 应用使用基于 cookie 或基于令牌的身份验证,其中已认证状态存储为 cookies、本地存储 或 IndexedDB。Playwright 提供了 BrowserContext.storageState() 方法,可用于从已认证的上下文检索存储状态,然后使用预先填充的状态创建新的上下文。
Cookies、本地存储和 IndexedDB 状态可在不同浏览器中使用。它们取决于应用程序的身份验证模型,该模型可能需要 cookies、本地存储或 IndexedDB 的某种组合。
以下代码片段从已认证的上下文检索状态,并使用该状态创建新的上下文。
// 将存储状态保存到文件中。
context.storageState(new BrowserContext.StorageStateOptions().setPath(Paths.get("state.json")));
// 使用保存的存储状态创建新的上下文。
BrowserContext context = browser.newContext(
new Browser.NewContextOptions().setStorageStatePath(Paths.get("state.json")));
高级场景
会话存储
复用已认证状态涵盖基于 cookies、本地存储 和 IndexedDB 的认证。很少情况下,会话存储 会用于存储与已登录状态相关的信息。会话存储特定于某个特定域,并且在页面加载之间不会持久化。Playwright 没有提供持久化会话存储的 API,但可以使用以下代码片段来保存/加载会话存储。
// 获取会话存储并作为环境变量存储
String sessionStorage = (String) page.evaluate("JSON.stringify(sessionStorage)");
System.getenv().put("SESSION_STORAGE", sessionStorage);
// 在新上下文中设置会话存储
String sessionStorage = System.getenv("SESSION_STORAGE");
context.addInitScript("(storage => {\n" +
" if (window.location.hostname === 'example.com') {\n" +
" const entries = JSON.parse(storage);\n" +
" for (const [key, value] of Object.entries(entries)) {\n" +
" window.sessionStorage.setItem(key, value);\n" +
" };\n" +
" }\n" +
"})('" + sessionStorage + "')");