Playwright测试本地通过但GitLab CI失败,求排查方案
Playwright在GitLab CI中测试网页文本编辑器超时问题
本地执行以下脚本时测试全部通过:
xvfb-run playwright test --ui --ui-port=8001 --ui-host=0.0.0.0
但在GitLab CI流水线中运行时测试失败,以下是相关配置与问题详情:
GitLab CI配置(相关部分)
image: docker:26.0.2 variables: DOCKER_TLS_CERTDIR: "/certs" DOCKER_CERT_PATH: "/certs/client" DOCKER_TLS_VERIFY: "1" DOCKER_HOST: "tcp://docker:2376" services: - docker:26.0.2-dind stages: - test - build test: stage: test script: - DEBUG=pw:api docker compose -f docker-compose.test.yaml up --exit-code-from test-runner - DEBUG=pw:api docker cp test-runner:/tmp/coverage.xml ./coverage.xml coverage: '/TOTAL.*\s+(\d+\%)/' artifacts: reports: coverage_report: coverage_format: cobertura path: ./coverage.xml e2e: stage: test script: - DEBUG=pw:api docker compose -f docker-compose.e2e.yaml up --exit-code-from test-runner coverage: '/TOTAL.*\s+(\d+\%)/' artifacts: paths: - playwright-report/ expire_in: 1 week
引发问题的测试代码
test('Add a new job', async ({ page }) => { await page.goto('/en/profiles/settings/basic/', { waitUntil: 'commit' }); // Navigate to 'Jobs' and click 'Add job' const navBar = page .locator('nav > ul[data-testid=desktop_nav_bar] > li') .first() .locator('ul'); await navBar.waitFor({ state: 'visible' }); // Fill in the job title await page.locator('#id_title').fill('Backend developer'); // Add tasks description const tasksEditor = page.locator('#id_tasks'); const tasksBtnsWrapper = tasksEditor.locator('[data-testid=menu_bar]'); const boldBtn = tasksBtnsWrapper.getByRole('button', { name: 'Bold' }); await boldBtn.waitFor(); await boldBtn.click(); await tasksEditor .locator('.tiptap.ProseMirror') .fill('Task details for the Backend Developer position'); // Select all employment types const employmentTypesDropdown = page.locator( 'div#data_id_employment_types' ); await employmentTypesDropdown.click(); await page.locator('#id_employment_types_select_all_btn').click(); await employmentTypesDropdown.click(); // Submit the form const createJobButton = page.getByRole('button', { name: 'Create Job' }); await createJobButton.click(); });
流水线错误信息
Test timeout of 30000ms exceeded. test-runner | test-runner | Error: locator.waitFor: Test timeout of 30000ms exceeded. test-runner | Call log: test-runner | - waiting for locator('#id_tasks').locator('[data-testid=menu_bar]').getByRole('button', { name: 'Bold' }) to be visible test-runner | test-runner | at /home/user/app/e2e/tests/jobs.spec.ts:33:19
本地测试完全正常,推测是流水线环境的渲染或浏览器行为差异导致问题。
已尝试的解决方法
- 延长测试超时时间,排查是否为时序问题;
- 确保操作前元素已存在,如按钮点击前进行等待;
- 确保CI环境中所有依赖已安装并更新。
排查与修复建议
- 验证CI环境浏览器运行模式:Playwright在CI中默认使用无头模式,部分UI元素的加载逻辑可能与本地有头模式不同。可临时在测试配置中启用有头模式(需CI环境支持xvfb),或调整无头模式参数,观察是否解决问题。
- 优化编辑器加载等待逻辑:文本编辑器(如Tiptap)在CI环境中可能加载较慢,建议先等待编辑器内容区域(
.tiptap.ProseMirror)可见,再等待工具栏按钮:await tasksEditor.locator('.tiptap.ProseMirror').waitFor({ state: 'visible' }); await boldBtn.waitFor(); - 检查元素定位的可靠性:CI环境中DOM结构可能与本地存在差异,可查看Playwright生成的测试报告(artifacts中的
playwright-report/),通过截图和DOM快照确认[data-testid=menu_bar]是否确实在#id_tasks元素下。 - 模拟真实用户操作顺序:先点击编辑器内容区域激活编辑器,再操作工具栏按钮,避免因编辑器未激活导致按钮不可见:
await tasksEditor.locator('.tiptap.ProseMirror').click(); await boldBtn.waitFor(); await boldBtn.click(); - 调整页面加载等待策略:将
page.goto的waitUntil参数改为'networkidle',确保页面资源完全加载后再执行后续操作:await page.goto('/en/profiles/settings/basic/', { waitUntil: 'networkidle' }); - 检查CI资源限制:GitLab Runner的CPU、内存配额不足可能导致编辑器渲染缓慢,可尝试增加Runner资源,或在
docker-compose中为test-runner容器分配更多资源。
内容的提问来源于stack exchange,提问作者Jacquit Ratongamanahaja
相关产品推荐
相关产品推荐

