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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 21:43:17