跳到主要内容

身份验证

简介

Playwright 在称为 浏览器上下文 的隔离环境中执行测试。这种隔离模型提高了可重复性,并防止测试失败的级联效应。测试可以加载现有的认证状态。这就无需在每个测试中进行认证,从而加快了测试执行速度。

核心概念

无论你选择何种认证策略,你都可能将已认证的浏览器状态存储在文件系统中。

我们建议创建 playwright/.auth 目录,并将其添加到你的 .gitignore 文件中。你的认证程序将生成已认证的浏览器状态,并将其保存到 playwright/.auth 目录中的一个文件中。随后,测试将重用此状态,并以已认证的状态启动。

危险

浏览器状态文件可能包含敏感的 cookie 和标头,这些信息可能被用于冒充你或你的测试账户。我们强烈建议不要将它们提交到私有或公共存储库中。

mkdir -p playwright/.auth
echo $'\nplaywright/.auth' >> .gitignore

每次测试前登录

Playwright API 可以自动与登录表单进行交互

以下示例展示了如何登录 GitHub。执行这些步骤后,浏览器上下文将处于已认证状态。

var page = await context.NewPageAsync();
await page.GotoAsync("https://github.com/login");
// 与登录表单进行交互
await page.GetByLabel("Username or email address").FillAsync("username");
await page.GetByLabel("Password").FillAsync("password");
await page.GetByRole(AriaRole.Button, new() { Name = "Sign in" }).ClickAsync();
// 继续进行测试

每次测试都重新登录会降低测试执行速度。为了缓解这个问题,可以复用现有的认证状态。

复用已登录状态

Playwright 提供了一种在测试中复用已登录状态的方法。这样一来,你只需登录一次,随后所有测试均可跳过登录步骤。

Web 应用使用基于 cookie 或基于令牌的身份验证,其中已认证状态存储为 cookies本地存储IndexedDB。Playwright 提供了 BrowserContext.StorageStateAsync() 方法,可用于从已认证的上下文检索存储状态,然后使用预先填充的状态创建新的上下文。

Cookie、本地存储和 IndexedDB 状态可在不同浏览器间使用。它们取决于应用程序的身份验证模型,该模型可能需要结合使用 cookie、本地存储或 IndexedDB。

以下代码片段从已认证的上下文检索状态,并使用该状态创建新的上下文。

// 将存储状态保存到文件中。
// 测试在 <TestProject>\bin\Debug\netX.0\ 中执行,因此使用相对路径来引用在项目根目录中创建的 playwright/.auth
await context.StorageStateAsync(new()
{
Path = "../../../playwright/.auth/state.json"
});

// 使用保存的存储状态创建新的上下文。
var context = await browser.NewContextAsync(new()
{
StorageStatePath = "../../../playwright/.auth/state.json"
});

高级场景

会话存储

重用认证状态涵盖基于 cookies本地存储IndexedDB 的认证。极少数情况下,会话存储 用于存储与登录状态相关的信息。会话存储特定于某个域,并且不会在页面加载之间持久保存。Playwright 没有提供持久化会话存储的 API,但可以使用以下代码片段来保存/加载会话存储。

// 获取会话存储并作为环境变量存储
var sessionStorage = await page.EvaluateAsync<string>("() => JSON.stringify(sessionStorage)");
Environment.SetEnvironmentVariable("SESSION_STORAGE", sessionStorage);

// 在新上下文中设置会话存储
var loadedSessionStorage = Environment.GetEnvironmentVariable("SESSION_STORAGE");
await context.AddInitScriptAsync(@"(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);
}
}
})('" + loadedSessionStorage + "')");