You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Playwright共享认证状态仅在fullyParallel模式下生效问题咨询

Playwright串行测试时无法共享认证状态的问题

问题现象

使用Playwright编写测试,按官方文档配置了setup项目生成认证状态文件,用于跨测试用例共享登录态。但**非全并行模式(或worker数量少于测试用例数)**运行时,只有第一个测试用例能正常继承登录状态,第二个测试用例会丢失认证;开启fullyParallel后所有测试均可正常运行。开发阶段希望保持串行运行,需解决该问题。

相关代码片段

auth.setup.js

import { test as setup, expect } from "@playwright/test";
const username = process.env.USER_NAME;
const password = process.env.PASSWORD;

setup("Log into the web app", async ({ page }) => {
    await page.goto("https://www.example.com/");
    await page
        .getByRole("textbox", {
            name: /email address/i,
        })
        .fill(username);
    await page
        .getByRole("button", {
            name: /continue/i,
        })
        .click();
    await page.getByLabel("Password").fill(password);
    await page
        .getByRole("button", {
            name: /continue/i,
        })
        .click();
    await expect(page).toHaveTitle(/example.com/);
    await page.context().storageState({ path: "playwright/.auth/user.json" });
});

playwright.config.js

export default defineConfig({
    // ...
    fullyParallel: !!process.env.CI,
    // ...
    projects: [
        {
            name: "setup",
            testMatch: /.*\.setup\.js/,
        },
        {
            name: "chromium",
            use: {
                ...devices["Desktop Chrome"],
                baseURL: "https://example.com",
                storageState: "playwright/.auth/user.json",
            },
            dependencies: ["setup"],
        },
        // ...
    ],
});

example.spec.js

test.describe("Website", () => {
    test("Homepage", async ({ page }) => {
        await test.step("See homepage fields", async () => {
            await page.goto("/");
            await expect(page).toHaveTitle(/homepage/i);
        });
    });

    test("Info page", async ({ page }) => {
        await test.step("See users", async () => {
            await page.goto("/info");
            await expect(page).toHaveTitle(/info/i);
        });
    });
});

原因分析

当测试串行运行(或worker数不足)时,Playwright会在同一个浏览器上下文中依次运行多个测试用例。第一个测试用例加载storageState后,后续操作可能会修改上下文的Cookie、localStorage等认证数据(比如页面跳转后的会话更新、页面状态变更),导致第二个测试用例启动时,上下文已经不是初始的认证状态。

而开启fullyParallel后,每个测试用例会被分配到独立的浏览器上下文,每个上下文都会重新加载storageState文件,因此不会互相干扰,所有测试都能正常获取认证状态。

解决方法(保持串行运行的前提下)

方法1:全局配置强制每个上下文加载初始状态

修改playwright.config.js中chromium项目的配置,通过contextOptions指定storageState,确保每个新创建的浏览器上下文都从文件加载干净的认证状态:

{
    name: "chromium",
    use: {
        ...devices["Desktop Chrome"],
        baseURL: "https://example.com",
        contextOptions: {
            storageState: "playwright/.auth/user.json",
        },
    },
    dependencies: ["setup"],
}

注:原配置中的storageState是给页面层级用的,contextOptions.storageState会确保每个测试用例启动时都创建新上下文并加载初始状态,避免串行时的状态污染。

方法2:测试前置钩子重置上下文

在测试描述块中添加beforeEach钩子,每次测试前清空当前上下文的状态并重新加载storageState:

test.describe("Website", () => {
    test.beforeEach(async ({ context }) => {
        await context.clearCookies();
        await context.storageState({ path: "playwright/.auth/user.json" });
    });

    test("Homepage", async ({ page }) => {
        await test.step("See homepage fields", async () => {
            await page.goto("/");
            await expect(page).toHaveTitle(/homepage/i);
        });
    });

    test("Info page", async ({ page }) => {
        await test.step("See users", async () => {
            await page.goto("/info");
            await expect(page).toHaveTitle(/info/i);
        });
    });
});

方法3:手动为每个测试创建独立上下文

在测试用例中手动创建新的浏览器上下文并加载storageState,替代默认的共享上下文:

test.describe("Website", () => {
    test("Homepage", async ({ browser }) => {
        const context = await browser.newContext({
            storageState: "playwright/.auth/user.json",
            ...devices["Desktop Chrome"],
        });
        const page = await context.newPage();
        await page.goto("/");
        await expect(page).toHaveTitle(/homepage/i);
        await context.close();
    });

    test("Info page", async ({ browser }) => {
        const context = await browser.newContext({
            storageState: "playwright/.auth/user.json",
            ...devices["Desktop Chrome"],
        });
        const page = await context.newPage();
        await page.goto("/info");
        await expect(page).toHaveTitle(/info/i);
        await context.close();
    });
});

内容的提问来源于stack exchange,提问作者justinw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 08:29:51