GitLab流水线Docker容器中Playwright storageSession失效问题
GitLab CI中Playwright storageState不生效问题
本地测试正常,但GitLab CI流水线内测试失败:
- storageState未生效,受保护路由超时
- 退出登录按钮处于禁用状态,确认localStorage中
headertoken项未正确设置
相关配置文件
playwright_tests/auth.setup.js
import { test as setup, expect } from '@playwright/test'; const authFile = 'playwright/.auth/user.json'; setup('authenticate', async ({ page }) => { // Perform authentication steps. await page.goto('/'); await page.setViewportSize({ width: 1920, height: 1080 }); await page.getByRole('button', { name: 'Sign in' }).click(); await page.waitForURL('/login'); await page.setViewportSize({ width: 1920, height: 1080 }); await page.getByLabel('Username').click(); await page.getByLabel('Username').fill('user'); await page.getByLabel('Password', { exact: true }).click(); await page.getByLabel('Password', { exact: true }).fill('password'); await page.getByLabel('Password', { exact: true }).press('Enter'); // Wait until the page receives the cookies. // // Sometimes login flow sets cookies in the process of several redirects. // Wait for the final URL to ensure that the cookies are actually set. await page.waitForURL('/'); // End of authentication steps. await page.context().storageState({ path: authFile }); });
playwright.config.js
// @ts-check const { defineConfig, devices } = require('@playwright/test'); // import process const process = require('process'); /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ // require('dotenv').config(); /** * @see https://playwright.dev/docs/test-configuration */ module.exports = defineConfig({ testDir: './playwright_tests', outputDir: 'playwright/test_results', /* 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', { outputFolder: 'playwright_results/playwright_report', open: 'never' }, ], [ 'junit', { outputFile: 'playwright_results/playwright_report/reports.xml' }, ], ], /* 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: process.env.FRONTEND_URL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, /* Configure projects for major browsers */ projects: [ // Setup project { name: 'setup', testMatch: /.*\.setup\.js/ }, { name: 'chromium', use: { ...devices['Desktop Chrome'], // Use prepared auth state. storageState: 'playwright/.auth/user.json', }, dependencies: ['setup'] }, { name: 'firefox', use: { ...devices['Desktop Firefox'], // Use prepared auth state. storageState: 'playwright/.auth/user.json', }, dependencies: ['setup'] },
本地生成的storageState示例(playwright/.auth/user.json)
{ "cookies": [], "origins": [ { "origin": "http://localhost:8080", "localStorage": [ { "name": "header", "value": "3c9cf469144b01c34eb09dfb9fbfa09b19dc4139" } ] } ] }
排查与解决步骤
1. 修复origin不匹配问题
本地storageState中的origin是http://localhost:8080,但CI环境的FRONTEND_URL通常是域名或其他地址,导致Playwright无法匹配origin,无法注入localStorage。
解决:
- 在CI流水线中添加步骤,替换storageState里的origin为当前环境的
FRONTEND_URL:# GitLab CI配置片段 stages: - test playwright_test: script: - npm install - npx playwright install --with-deps - npx playwright test --project=setup - sed -i "s|http://localhost:8080|$FRONTEND_URL|g" playwright/.auth/user.json - npx playwright test --project=chromium
2. 确保登录后localStorage已写入
部分应用会异步写入localStorage,仅等待URL跳转可能不足以确保token已生成。修改auth.setup.js,添加登录成功验证与等待:
// 登录步骤后添加: // 验证退出按钮已启用,确认登录状态 await expect(page.getByRole('button', { name: 'Sign out' })).toBeEnabled(); // 强制等待异步写入完成(按需调整时长) await page.waitForTimeout(1000); await page.context().storageState({ path: authFile });
3. 验证CI中storageState文件的正确性
在setup步骤末尾添加日志,确认生成的storageState内容:
const fs = require('fs'); console.log('Generated storageState content:', fs.readFileSync(authFile, 'utf8'));
查看CI日志,确认文件包含header token且origin与CI环境匹配。
4. 调试localStorage注入情况
在测试脚本中添加调试代码,打印当前页面的localStorage内容:
test('verify auth state', async ({ page }) => { await page.goto('/'); const headerToken = await page.evaluate(() => localStorage.getItem('header')); console.log('Current header token:', headerToken); expect(headerToken).not.toBeNull(); });
通过CI日志确认token是否存在,定位问题环节。
内容的提问来源于stack exchange,提问作者jaycarn
相关产品推荐
相关产品推荐

