Playwright认证状态返回空Cookies数组,关联测试失败求助
我使用Playwright实现测试用共享账号认证,但导出的认证状态中cookies数组为空,导致依赖认证的后续测试无法正常运行。当前使用的@playwright/test版本为^1.45.1。
导出的认证状态内容如下:
{ "cookies": [], "origins": [ { "origin": "http://localhost:3000", "localStorage": [ { "name": "locale", "value": "en_US" } ] } ] }
我的Playwright配置文件、认证setup脚本、测试脚本分别如下:
配置文件
import { defineConfig, devices } from '@playwright/test'; import dotenv from "dotenv"; import path from "path"; // Read from ".env" file. dotenv.config({ path: path.resolve(__dirname, ".env") }); /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: './tests', /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ // baseURL: 'http://127.0.0.1:3000', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, /* Configure projects for major browsers */ projects: [ { name: 'setup', testMatch: 'tests/auth-setup.ts', }, { name: 'chromium', use: { ...devices['Desktop Chrome'], storageState: 'playwright/.auth/user.json', }, dependencies: ['setup'], }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, // { // name: 'webkit', // use: { ...devices['Desktop Safari'] }, // }, /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', // use: { ...devices['Pixel 5'] }, // }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, // }, /* Test against branded browsers. */ // { // name: 'Microsoft Edge', // use: { ...devices['Desktop Edge'], channel: 'msedge' }, // }, // { // name: 'Google Chrome', // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, // }, ], /* Run your local dev server before starting the tests */ // webServer: { // command: 'npm run start', // url: 'http://127.0.0.1:3000', // reuseExistingServer: !process.env.CI, // }, });
认证setup脚本
import { test as setup, expect, chromium, Browser, Page } from '@playwright/test'; const authFile = 'playwright/.auth/user.json'; setup('authenticate user', async ({ }) => { const browser: Browser = await chromium.launch({headless: true}); const context = await browser.newContext(); const page: Page = await context.newPage(); await page.goto(`${process.env.APP_BASE_URL}/login`); await page.locator('input[name="username"]').fill(`${process.env.APP_USERNAME}`); await page.locator('input[name="password"]').fill(`${process.env.APP_PASSWORD}`); await page.locator("button[aria-label='confirmButton']").click(); await page.waitForURL(`${process.env.APP_BASE_URL}/accounts#operations`); await expect(page.getByText('Available balance')).toHaveText('Available balance'); await page.context().storageState({ path: authFile }); });
测试脚本
import { test, expect } from '@playwright/test'; test('display accounts page', async ({ page }) => { await page.goto(`${process.env.APP_BASE_URL}/accounts#operations`); await page.waitForTimeout(5000); await expect(page.getByText('Available balance')).toHaveText('Available balance'); await page.waitForTimeout(5000); await page.screenshot({ path: "./playwright/screenshots/screen-capture.png", }); });
setup测试执行成功,但业务测试失败,截图显示停留在登录页。此前按教程操作时cookies有正常内容,测试可正常运行。
- 认证上下文不匹配:你的setup脚本手动创建了浏览器和上下文,和Playwright测试框架内置的上下文完全分离。手动创建的上下文可能没有被正确捕获状态,或者框架无法识别这个上下文的认证信息。应该直接使用setup测试提供的
page或context对象,而非手动启动浏览器。 - Cookie属性与URL不匹配:如果应用设置的Cookie域名、路径和
APP_BASE_URL不一致,比如Cookie绑定的是127.0.0.1但你的URL用的是localhost,或者路径限制为特定路由,Playwright无法导出这些不匹配的Cookie。 - 认证完成后等待不充分:虽然你添加了页面跳转和文本断言,但Cookie可能还未完全写入浏览器。可以等待认证接口的响应完成,或者直接等待目标认证Cookie出现后再导出状态。
- Headless模式差异:手动启动浏览器时指定了
headless: true,这是Playwright的旧版无头模式,而v1.38+默认使用新版无头模式。两种模式的Cookie存储行为可能存在差异,尝试改用headless: 'new'或直接使用框架默认的上下文。 - 存储状态调用对象错误:脚本中用
page.context().storageState(),如果页面跳转后切换了上下文(比如打开了新窗口),page.context()可能不是实际完成认证的上下文。应该直接使用你创建的context对象来调用storageState。 - 协议不一致:如果登录过程中HTTP和HTTPS协议切换,Cookie可能被限制在对应协议下,导出的状态无法跨协议携带。确保
APP_BASE_URL的协议和应用实际运行的协议完全一致。
修复示例
修改setup脚本,使用测试内置的上下文,避免手动启动浏览器:
import { test as setup, expect } from '@playwright/test'; const authFile = 'playwright/.auth/user.json'; setup('authenticate user', async ({ page, context }) => { await page.goto(`${process.env.APP_BASE_URL}/login`); await page.locator('input[name="username"]').fill(`${process.env.APP_USERNAME}`); await page.locator('input[name="password"]').fill(`${process.env.APP_PASSWORD}`); await page.locator("button[aria-label='confirmButton']").click(); await page.waitForURL(`${process.env.APP_BASE_URL}/accounts#operations`); await expect(page.getByText('Available balance')).toHaveText('Available balance'); // 等待目标认证Cookie出现,替换为你的实际Cookie名称 await context.waitForCookie({ name: 'auth_token' }); await context.storageState({ path: authFile }); });
内容的提问来源于stack exchange,提问作者Aron
相关产品推荐
相关产品推荐

