ci-cd-integration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese
<objective> A 20-minute serial suite on every push destroys developer velocity; a green pipeline that retries flaky tests three times hides the race condition until it ships. This skill produces CI/CD pipelines that run the right tests at the right trigger, shard them across runners, store traces and reports as evidence, quarantine flaky tests instead of masking them, and gate merges on real coverage numbers. Use this skill when the question is about running tests in a pipeline, not writing them. </objective>
<objective> 每次推送都运行20分钟的串行测试套件会严重拖慢开发效率;自动重试不稳定测试三次的「绿色管道」会掩盖竞态条件,直到问题随版本上线。本技能可构建CI/CD管道,在正确的触发时机运行合适的测试,将测试分片到多个运行器,存储跟踪信息和报告作为证据,隔离不稳定测试而非掩盖问题,并基于真实覆盖率数据管控代码合并。当问题涉及在管道中运行测试(而非编写测试)时,使用本技能。 </objective>

Discovery Questions

探索问题

Check
.agents/qa-project-context.md
first — if it exists, use it and skip anything already answered there (especially
team_maturity
and existing CI conventions). Then:
  1. Which CI platform? GitHub Actions, GitLab CI, CircleCI, Jenkins? This skill ships templates for GitHub Actions and GitLab CI.
  2. What test types need to run? Unit, integration, E2E, visual, performance? Each has different resource and timing needs.
  3. What is the current CI duration? Over 10 minutes means parallelism and sharding are mandatory, not optional.
  4. How many developers push per day? High-frequency teams need aggressive concurrency cancellation and caching.
  5. What triggers should run which tests? Not every push needs a full E2E suite — map triggers to suites before writing YAML.
首先查看
.agents/qa-project-context.md
——如果该文件存在,使用其中内容并跳过已回答的问题(尤其是
team_maturity
和现有CI约定)。然后询问:
  1. 使用哪种CI平台? GitHub Actions、GitLab CI、CircleCI还是Jenkins?本技能提供GitHub Actions和GitLab CI的模板。
  2. 需要运行哪些类型的测试? 单元测试、集成测试、E2E测试、可视化测试、性能测试?每种测试的资源和时间需求不同。
  3. 当前CI执行时长是多少? 超过10分钟意味着必须采用并行化和分片,而非可选方案。
  4. 每天有多少开发者推送代码? 高频推送的团队需要设置严格的并发取消和缓存策略。
  5. 哪些触发事件应运行哪些测试? 并非每次推送都需要完整的E2E套件——在编写YAML前先映射触发事件与测试套件的对应关系。

Calibrate to team maturity

根据团队成熟度调整

Set
team_maturity
in
.agents/qa-project-context.md
; pick the matching pipeline shape:
  • startup — one job: lint + unit + one E2E smoke on PR. Fast feedback over completeness.
  • growing — separate jobs for unit, integration, E2E. Parallelization, artifact uploads, result publishing, flaky quarantine.
  • established — full matrix: sharded E2E, multi-environment promotion gates, perf and security scans, deploy-gated checks, SLA-backed pipelines.

.agents/qa-project-context.md
中设置
team_maturity
,选择匹配的管道架构:
  • 初创团队 —— 单任务:PR中运行代码检查+单元测试+一个E2E冒烟测试。优先保证快速反馈而非测试完整性。
  • 成长中团队 —— 单元测试、集成测试、E2E测试分设独立任务。支持并行化、工件上传、结果发布、不稳定测试隔离。
  • 成熟团队 —— 完整矩阵架构:分片E2E测试、多环境发布门禁、性能与安全扫描、部署前置检查、符合SLA的管道。

Core Principles

核心原则

  1. Fast feedback: right tests at the right time. Unit tests on every push (under 2 min). E2E on PRs (under 10 min). Full suite on merge and nightly. The trigger-to-suite map below is the contract.
  2. Parallel first: shard tests across workers. A 20-minute serial suite becomes 5 minutes across 4 shards. Always worth the runner cost.
  3. Artifacts are evidence. Every run stores traces, screenshots, coverage, and HTML reports. Without artifacts, a CI failure is an undebuggable "reproduce locally" cycle.
  4. Flaky tests need quarantine, not retries. Retrying hides the problem — the test passes on retry, the report is green, the race condition persists. Move flaky tests to a non-blocking job, track them, fix the root cause.
  5. Quality gates get stricter toward production. Define what must pass at each stage; PR gate is fast and cheap, deploy gate is comprehensive.
  6. Read thresholds from config, not from bash. Let the test runner enforce coverage via its own
    coverageThreshold
    /
    thresholds
    and exit non-zero. Scraping percentages out of stdout with regex is fragile across runner versions.

  1. 快速反馈:在正确的时机运行正确的测试。每次推送运行单元测试(耗时≤2分钟)。PR中运行E2E测试(耗时≤10分钟)。合并到主分支和夜间定时任务运行完整套件。下方的触发-套件映射为标准约定。
  2. 优先并行:将测试分片到多个运行器。20分钟的串行套件在4个分片下可缩短至5分钟。即使增加运行器成本也值得。
  3. 工件即证据。每次运行都存储跟踪信息、截图、覆盖率报告和HTML报告。没有工件的话,CI失败就会变成无法调试的「本地复现」循环。
  4. 不稳定测试需要隔离而非重试。重试会掩盖问题——测试重试后通过,报告显示绿色,但竞态条件依然存在。将不稳定测试移至非阻塞任务,跟踪并修复根本原因。
  5. 越接近生产环境,质量门禁越严格。定义每个阶段必须通过的检查;PR门禁快速且低成本,部署门禁全面且严格。
  6. 从配置读取阈值,而非从bash脚本。让测试运行器通过自身的
    coverageThreshold
    /
    thresholds
    配置强制覆盖率要求,并在不满足时返回非零退出码。通过正则表达式从标准输出中提取百分比的方式在不同版本的运行器中容易失效。

Pipeline Architecture

管道架构

Push to branch:   lint+types (30s) → unit (1-2m)
PR opened:        + integration (2-3m) → E2E sharded (5-8m) → merge report
Merge to main:    full E2E ∥ visual ∥ perf budget → deploy (OIDC)
Nightly (cron):   full suite + npm audit + axe a11y + flaky quarantine
分支推送:   lint+类型检查(30s) → 单元测试(1-2m)
PR创建:        + 集成测试(2-3m) → 分片E2E测试(5-8m) → 合并报告
合并到主分支:    完整E2E测试 ∥ 可视化测试 ∥ 性能预算检查 → 部署(OIDC)
夜间定时任务(cron):   完整套件 + npm审计 + axe无障碍测试 + 不稳定测试隔离

What runs when

触发事件与测试对应关系

TriggerTestsMax duration
Push to branchlint, type-check, unit2 min
PR opened/updated+ integration, E2E smoke10 min
Merge to main+ full E2E, visual, perf budget15 min
Nightly schedulefull suite, security, a11y, flaky quarantine30 min
Release tagfull suite, smoke against staging20 min

触发事件测试内容最长耗时
分支推送代码检查、类型检查、单元测试2分钟
PR创建/更新+ 集成测试、E2E冒烟测试10分钟
合并到主分支+ 完整E2E测试、可视化测试、性能预算检查15分钟
夜间定时任务完整套件、安全测试、无障碍测试、不稳定测试隔离30分钟
发布标签完整套件、 staging环境冒烟测试20分钟

GitHub Actions

GitHub Actions

For complete copy-paste workflow files (unit, sharded Playwright E2E, full pipeline, nightly, PR gate), see
references/github-actions-templates.md
.
完整的可复用工作流文件(单元测试、分片Playwright E2E测试、完整管道、夜间任务、PR门禁)请查看
references/github-actions-templates.md

Action versions (June 2026)

动作版本(2026年6月)

Pin to the current major and let Dependabot bump them. The
actions/*
family runs on the Node 24 runner; Node 20 is deprecated on GH-hosted runners.
ActionCurrent majorNotes
actions/checkout
@v6
actions/setup-node
@v6
v5+ auto-caches only when
packageManager
is set; use
cache: npm
to be explicit
actions/cache
@v5
new cache service v2 backend
actions/upload-artifact
@v7
v7 can upload unzipped (
archive: false
)
actions/download-artifact
@v7
pair with upload-artifact major
dorny/test-reporter
@v3
v3 requires Node 24 runner; reporter keys unchanged
dorny/paths-filter
@v3
marocchino/sticky-pull-request-comment
@v3
slackapi/slack-github-action
@v2
floating major; see notification note before adopting v3
For supply-chain-sensitive pipelines, pin third-party actions (dorny, marocchino, slackapi, knapsack) to a full-length commit SHA with a version comment, and let Dependabot update the SHA:
uses: dorny/test-reporter@<40-char-sha> # v3.0.0
. First-party
actions/*
are lower risk; tags are acceptable there.
固定使用当前大版本,让Dependabot自动更新。
actions/*
系列动作运行在Node 24运行器上;Node 20在GitHub托管运行器中已被弃用。
动作当前大版本说明
actions/checkout
@v6
actions/setup-node
@v6
v5+仅在设置
packageManager
时自动缓存;显式使用
cache: npm
更可靠
actions/cache
@v5
采用新的缓存服务v2后端
actions/upload-artifact
@v7
v7支持上传未压缩文件(
archive: false
actions/download-artifact
@v7
与upload-artifact大版本保持一致
dorny/test-reporter
@v3
v3需要Node 24运行器;报告器密钥未变更
dorny/paths-filter
@v3
marocchino/sticky-pull-request-comment
@v3
slackapi/slack-github-action
@v2
使用浮动大版本;升级到v3前请查看通知说明
对于对供应链安全敏感的管道,将第三方动作(dorny、marocchino、slackapi、knapsack)固定到完整的提交SHA并添加版本注释,让Dependabot自动更新SHA:
uses: dorny/test-reporter@<40位SHA> # v3.0.0
。官方
actions/*
动作风险较低,使用标签即可。

Key concepts

核心概念

Concurrency groups cancel wasted runs when a branch gets multiple pushes:
yaml
concurrency:
  group: tests-${{ github.ref }}
  cancel-in-progress: true
Matrix sharding across runners:
yaml
strategy:
  fail-fast: false
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}/4
Caching browsers so they aren't re-downloaded every run:
yaml
- uses: actions/setup-node@v6
  with: { node-version: 22, cache: npm }

- name: Cache Playwright browsers
  id: playwright-cache
  uses: actions/cache@v5
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

- name: Install Playwright browsers
  if: steps.playwright-cache.outputs.cache-hit != 'true'
  run: npx playwright install --with-deps chromium
Artifacts for reports and traces, and merging sharded reports into one HTML report — see
references/github-actions-templates.md
(E2E workflow). The merge job uses
actions/download-artifact@v7
with
pattern: test-results-*
then
npx playwright merge-reports --reporter=html
.
并发组可在分支多次推送时取消冗余运行:
yaml
concurrency:
  group: tests-${{ github.ref }}
  cancel-in-progress: true
矩阵分片跨运行器执行:
yaml
strategy:
  fail-fast: false
  matrix:
    shard: [1, 2, 3, 4]
steps:
  - run: npx playwright test --shard=${{ matrix.shard }}/4
缓存浏览器避免每次运行重新下载:
yaml
- uses: actions/setup-node@v6
  with: { node-version: 22, cache: npm }

- name: Cache Playwright browsers
  id: playwright-cache
  uses: actions/cache@v5
  with:
    path: ~/.cache/ms-playwright
    key: playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }}

- name: Install Playwright browsers
  if: steps.playwright-cache.outputs.cache-hit != 'true'
  run: npx playwright install --with-deps chromium
工件存储报告和跟踪信息,以及合并分片报告为单个HTML报告——请查看
references/github-actions-templates.md
(E2E工作流)。合并任务使用
actions/download-artifact@v7
并设置
pattern: test-results-*
,然后执行
npx playwright merge-reports --reporter=html

Smarter sharding at scale

大规模场景下的智能分片

Past 10–15 shards, naïve hash-based splitting wastes runner time on uneven shards. Use a timing-aware balancer:
  • knapsack-pro
    — timing-data based, supports Playwright/Jest/Cypress/RSpec; distributes by historical duration.
  • CloudBees Smart Tests (formerly Launchable) — ML prioritization + Test Impact Analysis; runs only the tests likely to fail for the diff.
  • Datadog Test Optimization — TIA + flake management; shard-balancing by historical time.
  • Trunk Flaky Tests — flake-aware quarantine + retry budgeting.
Before reaching for a paid balancer: Playwright's
--shard
already distributes by file and balances on duration from prior runs. To inspect or feed custom timing data, dump it yourself —
npx playwright test --reporter=json | jq '[.suites[].specs[] | {file: .file, duration: .tests[].results[].duration}]'
. For Jest,
jest-slow-test-reporter
surfaces the slowest specs so you can split or fix them.
For self-hosted runners on Kubernetes, use Actions Runner Controller (
arc-runner-set
/
gha-runner-scale-set
) — Helm-installed, auto-scales runner pods per workflow. Replaces the deprecated
runner-deployment
CRD.
当分片数量超过10-15个时,简单的哈希分片会因分片负载不均浪费运行器时间。使用基于时间的平衡工具:
  • knapsack-pro
    —— 基于时间数据,支持Playwright/Jest/Cypress/RSpec;根据历史执行时长分配测试。
  • CloudBees Smart Tests(原Launchable)—— ML优先级排序+测试影响分析;仅运行可能因代码变更失败的测试。
  • Datadog Test Optimization —— 测试影响分析+不稳定测试管理;根据历史时间平衡分片。
  • Trunk Flaky Tests —— 感知不稳定测试的隔离+重试预算管理。
在使用付费平衡工具前:Playwright的
--shard
已支持按文件分配,并根据之前的运行时长平衡负载。如需查看或自定义时间数据,可自行导出——
npx playwright test --reporter=json | jq '[.suites[].specs[] | {file: .file, duration: .tests[].results[].duration}]'
。对于Jest,
jest-slow-test-reporter
可显示最慢的测试用例,方便拆分或优化。
对于Kubernetes上的自托管运行器,使用Actions Runner Controller
arc-runner-set
/
gha-runner-scale-set
)——通过Helm安装,可根据工作流自动扩缩容运行器Pod。替代已弃用的
runner-deployment
CRD。

Required status checks

必需状态检查

Protect main in Settings → Branches → Branch protection rules: enable "Require status checks to pass before merging," add
lint
,
unit-tests
, and
e2e
(all shards) as required checks, and enable "Require branches to be up to date."

在设置→分支→分支保护规则中保护主分支:启用「合并前需要状态检查通过」,添加
lint
unit-tests
e2e
(所有分片)作为必需检查,并启用「要求分支保持最新」。

GitLab CI

GitLab CI

For the full pipeline, see
references/gitlab-ci-template.md
. Key points:
  • Stages
    [validate, test, e2e, deploy]
    ;
    node:22-alpine
    for lint/unit,
    mcr.microsoft.com/playwright:v1.60.0-noble
    for E2E (keep this pinned to your installed
    @playwright/test
    minor).
  • Parallel sharding:
    parallel: 4
    exposes
    CI_NODE_INDEX
    /
    CI_NODE_TOTAL
    ; run
    npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
    .
  • Coverage: emit a cobertura
    coverage_report
    artifact and a
    junit
    report; GitLab reads the percentage and test results from those. The legacy
    coverage:
    stdout regex is a fragile fallback across Jest versions — prefer the cobertura report.

完整管道请查看
references/gitlab-ci-template.md
。核心要点:
  • 阶段为
    [validate, test, e2e, deploy]
    ;lint/单元测试使用
    node:22-alpine
    镜像,E2E测试使用
    mcr.microsoft.com/playwright:v1.60.0-noble
    镜像(请固定到与已安装
    @playwright/test
    匹配的小版本)。
  • 并行分片:
    parallel: 4
    会暴露
    CI_NODE_INDEX
    /
    CI_NODE_TOTAL
    变量;执行
    npx playwright test --shard=$CI_NODE_INDEX/$CI_NODE_TOTAL
  • 覆盖率:生成cobertura格式的
    coverage_report
    工件和
    junit
    报告;GitLab会从中读取覆盖率百分比和测试结果。不同Jest版本中,通过标准输出正则表达式提取覆盖率的传统
    coverage:
    配置容易失效——优先使用cobertura报告。

Advanced Patterns

高级模式

Test result publishing to PR comments

测试结果发布到PR评论

yaml
- name: Publish test results
  uses: dorny/test-reporter@v3
  if: ${{ !cancelled() }}
  with:
    name: Test Results
    path: test-results/junit.xml
    reporter: jest-junit  # use java-junit for a Playwright JUnit report
For the sticky coverage PR comment (
marocchino/sticky-pull-request-comment@v3
), see
references/github-actions-templates.md
(PR Quality Gate).
yaml
- name: Publish test results
  uses: dorny/test-reporter@v3
  if: ${{ !cancelled() }}
  with:
    name: Test Results
    path: test-results/junit.xml
    reporter: jest-junit  # Playwright JUnit报告使用java-junit
固定覆盖率PR评论(
marocchino/sticky-pull-request-comment@v3
)示例请查看
references/github-actions-templates.md
(PR质量门禁)。

Conditional test execution

条件测试执行

Only test what changed. Use
dorny/paths-filter@v3
to set outputs, then gate steps on them — see
references/github-actions-templates.md
(Conditional execution).
仅测试变更的代码。使用
dorny/paths-filter@v3
设置输出变量,然后根据变量管控步骤执行——示例请查看
references/github-actions-templates.md
(条件执行)。

Flaky test quarantine

不稳定测试隔离

Separate flaky tests into a non-blocking job so they run in CI but don't block merges:
yaml
e2e-stable:        # required for merge
  steps:
    - run: npx playwright test --grep-invert @flaky

e2e-quarantine:    # non-blocking
  continue-on-error: true
  steps:
    - run: npx playwright test --grep @flaky
    - if: failure()
      run: echo "::warning::Quarantined tests failed. Review and fix or remove."
Tag flaky tests at the source so the grep splits them:
typescript
test('sometimes fails due to race condition @flaky', async ({ page }) => {
  // runs in CI but doesn't block merges
});
If a quarantined test passes 10 consecutive runs, remove the
@flaky
tag. For runtime self-healing of a single flaky test (selector recovery, auto-retry policy), use
test-reliability
.
将不稳定测试分离到非阻塞任务,使其在CI中运行但不阻止代码合并:
yaml
e2e-stable:        # 合并必需任务
  steps:
    - run: npx playwright test --grep-invert @flaky

e2e-quarantine:    # 非阻塞任务
  continue-on-error: true
  steps:
    - run: npx playwright test --grep @flaky
    - if: failure()
      run: echo "::warning::隔离测试失败,请检查修复或移除。"
在测试源代码中标记不稳定测试,以便通过grep拆分:
typescript
test('有时因竞态条件失败 @flaky', async ({ page }) => {
  // 在CI中运行但不阻止合并
});
如果隔离测试连续10次运行通过,移除
@flaky
标签。如需实现单不稳定测试的运行时自修复(选择器恢复、自动重试策略),请使用
test-reliability
技能。

Cache strategies

缓存策略

LayerPathCache key
Node modules(handled by
setup-node
cache: npm
)
automatic
Playwright browsers
~/.cache/ms-playwright
pw-{os}-{hash(package-lock.json)}
Build cache (Next.js)
.next/cache
nextjs-{os}-{hash(lockfile)}-{hash(src)}
Test fixtures
e2e/fixtures/.cache
test-data-{hash(seed.sql)}
Use
actions/cache@v5
for layers 2–4; add
restore-keys
on build caches for partial matches.
层级路径缓存键
Node模块(由
setup-node
cache: npm
处理)
自动生成
Playwright浏览器
~/.cache/ms-playwright
pw-{os}-{hash(package-lock.json)}
构建缓存(Next.js)
.next/cache
nextjs-{os}-{hash(lockfile)}-{hash(src)}
测试夹具
e2e/fixtures/.cache
test-data-{hash(seed.sql)}
使用
actions/cache@v5
处理第2-4层级;构建缓存添加
restore-keys
以支持部分匹配恢复。

OIDC keyless deploy

OIDC无密钥部署

Don't store a long-lived
DEPLOY_TOKEN
. Use GitHub Actions OIDC to assume a cloud role for short-lived credentials — nothing static to leak or rotate:
yaml
deploy:
  permissions:
    id-token: write   # request the OIDC JWT
    contents: read
  steps:
    - uses: aws-actions/configure-aws-credentials@v6
      with:
        role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
        aws-region: eu-central-1
    - run: ./deploy.sh production   # uses short-lived STS creds, no static secret
The IAM role's trust policy pins the
sub
claim to your repo and branch. GCP (
google-github-actions/auth
) and Azure (
azure/login
) have equivalent OIDC flows.
不要存储长期有效的
DEPLOY_TOKEN
。使用GitHub Actions OIDC获取云角色的短期凭证——无需静态密钥,避免泄露或轮换成本:
yaml
deploy:
  permissions:
    id-token: write   # 请求OIDC JWT
    contents: read
  steps:
    - uses: aws-actions/configure-aws-credentials@v6
      with:
        role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
        aws-region: eu-central-1
    - run: ./deploy.sh production   # 使用短期STS凭证,无静态密钥
IAM角色的信任策略需将
sub
声明绑定到你的仓库和分支。GCP(
google-github-actions/auth
)和Azure(
azure/login
)有类似的OIDC流程。

Slack/Teams notification on failure

失败时发送Slack/Teams通知

Use
slackapi/slack-github-action@v2
with
webhook-type: incoming-webhook
, gated on
if: failure() && github.ref == 'refs/heads/main'
so only main-branch failures notify. Before moving to
@v3
, note v3 changed payload handling for workflow-trigger webhooks (no longer flattened/stringified) — verify your payload against the v3 docs first. Full example in
references/github-actions-templates.md
(Nightly Full Suite).

使用
slackapi/slack-github-action@v2
并设置
webhook-type: incoming-webhook
,仅在主分支失败时触发(
if: failure() && github.ref == 'refs/heads/main'
)。升级到
@v3
前请注意,v3变更了工作流触发webhook的负载处理方式(不再扁平化/字符串化)——请先对照v3文档验证负载格式。完整示例请查看
references/github-actions-templates.md
(夜间完整套件)。

Quality Gates

质量门禁

GateWhenRequired checksBlocking?
PR GatePR opened/updatedlint, type-check, unit, coverage thresholdYes
Merge GateBefore merge to main+ E2E smoke suiteYes
Deploy GateBefore production deploy+ full E2E, visual, perf budgetYes
Nightly GateScheduled 2am dailyfull suite, npm audit, axe a11yAlert only
门禁触发时机必需检查是否阻塞
PR门禁PR创建/更新代码检查、类型检查、单元测试、覆盖率阈值
合并门禁合并到主分支前+ E2E冒烟测试
部署门禁生产环境部署前+ 完整E2E测试、可视化测试、性能预算检查
夜间门禁每日凌晨2点定时任务完整套件、npm审计、axe无障碍测试仅告警

PR Gate (under 3 minutes)

PR门禁(耗时≤3分钟)

Enforce the coverage floor in the test runner's config, not in bash. In
jest.config.js
(or
vitest.config.ts
coverage.thresholds
):
javascript
coverageThreshold: { global: { lines: 80, statements: 80, branches: 70 } }
Then
jest --coverage
exits non-zero when coverage drops, so the job fails with no extra script. If you must read the number in CI (e.g. to print it), have Jest emit
json-summary
and read the file — there is no
coverage-summary
CLI:
yaml
- run: npm test -- --ci --coverage   # exits 1 if below coverageThreshold
- name: Print coverage (optional)
  run: |
    PCT=$(jq '.total.lines.pct' coverage/coverage-summary.json)
    echo "Line coverage: ${PCT}%"
(
json-summary
reporter writes
coverage/coverage-summary.json
. For nyc/c8 projects,
nyc report --reporter=text-summary
. The standalone
istanbul
CLI is deprecated — don't use
istanbul report
.)
在测试运行器的配置中强制覆盖率下限,而非通过bash脚本。在
jest.config.js
(或
vitest.config.ts
coverage.thresholds
)中设置:
javascript
coverageThreshold: { global: { lines: 80, statements: 80, branches: 70 } }
然后执行
jest --coverage
,当覆盖率低于阈值时会返回非零退出码,任务自动失败,无需额外脚本。如果必须在CI中读取覆盖率数值(例如打印),让Jest生成
json-summary
报告并读取文件——没有
coverage-summary
命令行工具:
yaml
- run: npm test -- --ci --coverage   # 覆盖率低于阈值时退出码为1
- name: 打印覆盖率(可选)
  run: |
    PCT=$(jq '.total.lines.pct' coverage/coverage-summary.json)
    echo "行覆盖率: ${PCT}%"
json-summary
报告器会生成
coverage/coverage-summary.json
。对于nyc/c8项目,执行
nyc report --reporter=text-summary
。独立的
istanbul
命令行工具已弃用——请勿使用
istanbul report
。)

Merge Gate (under 10 minutes)

合并门禁(耗时≤10分钟)

PR Gate + E2E smoke. Configure as required status checks in branch protection.
PR门禁 + E2E冒烟测试。在分支保护中配置为必需状态检查。

Deploy Gate (under 15 minutes)

部署门禁(耗时≤15分钟)

Needs
[unit-tests, e2e-tests, visual-tests]
, then a perf budget check (
npx lhci autorun
/
lhci assert --config=lighthouserc.json
) before the OIDC deploy step above.
需要通过
[unit-tests, e2e-tests, visual-tests]
,然后在上述OIDC部署步骤前执行性能预算检查(
npx lhci autorun
/
lhci assert --config=lighthouserc.json
)。

Nightly Gate (up to 30 minutes)

夜间门禁(耗时≤30分钟)

Full E2E across all browsers, security scan, a11y audit, flaky quarantine. Wire the security and a11y steps as real jobs, not just prose:
yaml
- run: npm audit --audit-level=high   # fails on high/critical advisories
- run: npx playwright test --grep @a11y   # specs that call @axe-core/playwright
Where the
@a11y
-tagged specs use
@axe-core/playwright
:
typescript
import AxeBuilder from '@axe-core/playwright';
test('home page has no a11y violations @a11y', async ({ page }) => {
  await page.goto('/');
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
});
Results go to Slack, not as blocking checks.

全浏览器完整E2E测试、安全扫描、无障碍审计、不稳定测试隔离。将安全和无障碍步骤配置为真实任务,而非仅文档说明:
yaml
- run: npm audit --audit-level=high   # 高/严重漏洞时任务失败
- run: npx playwright test --grep @a11y   # 调用@axe-core/playwright的测试用例
其中
@a11y
标记的测试用例使用
@axe-core/playwright
typescript
import AxeBuilder from '@axe-core/playwright';
test('首页无无障碍违规 @a11y', async ({ page }) => {
  await page.goto('/');
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
});
结果发送到Slack,不设置为阻塞检查。

Anti-Patterns

反模式

1. Running all tests on every commit

1. 每次提交运行所有测试

A 20-minute full suite on every push destroys velocity. Use the trigger-to-suite map: fast tests on push, comprehensive on PR and merge.
每次推送都运行20分钟的完整套件会严重拖慢开发效率。使用触发-套件映射:推送时运行快速测试,PR和合并时运行全面测试。

2. No artifact storage

2. 不存储工件

Without traces, screenshots, and logs, every CI failure becomes a "reproduce locally" cycle that wastes hours. Upload artifacts on
if: ${{ !cancelled() }}
.
没有跟踪信息、截图和日志的话,每次CI失败都会变成浪费时间的「本地复现」循环。在
if: ${{ !cancelled() }}
条件下上传工件。

3. Retrying flaky tests without tracking them

3. 重试不稳定测试但不跟踪

retries: 3
hides flakiness — the report is green but the race condition persists. Quarantine, track, fix the root cause.
retries: 3
会掩盖不稳定问题——报告显示绿色,但竞态条件依然存在。应隔离、跟踪并修复根本原因。

4. CI-only failures without local reproduction

4. CI专属失败无法本地复现

If a test only fails in CI, document why (timezone, missing env var, screen resolution) and add a script that replicates CI locally with the same Playwright image you run in CI — don't pin a stale image. See
references/github-actions-templates.md
(Local repro).
如果测试仅在CI中失败,记录原因(时区、缺失环境变量、屏幕分辨率)并添加脚本,使用与CI中相同的Playwright镜像在本地复现——不要固定过时的镜像。示例请查看
references/github-actions-templates.md
(本地复现)。

5. Shared state between CI jobs

5. CI任务间共享状态

Jobs that read files from sibling jobs without artifacts or
needs
. Each job starts fresh; pass data via
upload-artifact
/
download-artifact
.
任务通过读取兄弟任务的文件(而非工件或
needs
)共享状态。每个任务都从全新环境开始;通过
upload-artifact
/
download-artifact
传递数据。

6. No concurrency controls

6. 无并发控制

Multiple runs for the same branch waste runners. Always use a concurrency group with
cancel-in-progress: true
.
同一分支的多次运行会浪费运行器资源。始终设置并发组并启用
cancel-in-progress: true

7. Hardcoded secrets in workflow files

7. 工作流文件中硬编码密钥

Never put tokens, passwords, or keys in YAML. Use repo secrets (
${{ secrets.X }}
) or GitLab CI/CD variables — and prefer OIDC keyless auth over any long-lived deploy token.
永远不要在YAML中存储令牌、密码或密钥。使用仓库密钥(
${{ secrets.X }}
)或GitLab CI/CD变量——并且优先使用OIDC无密钥认证,而非任何长期有效的部署令牌。

8. Ignoring job timeouts

8. 忽略任务超时

A stuck test can hold a runner for hours. Set
timeout-minutes
on every job and
actionTimeout
/
navigationTimeout
in the Playwright config.

卡住的测试会占用运行器数小时。为每个任务设置
timeout-minutes
,并在Playwright配置中设置
actionTimeout
/
navigationTimeout

Verification

验证

Prove the pipeline before relying on it. Smallest check first:
  1. Lint the workflow syntax
    actionlint .github/workflows/*.yml
    catches expression,
    needs
    , and shell-quoting errors before they fail at runtime. Add a
    yamllint .github/workflows/
    pass for indentation. Run actionlint as a job too.
  2. Dry-run a job locally
    act -j unit-tests
    runs the job in a container so you can iterate without pushing.
  3. Confirm required checks appear — push to a throwaway branch, open a draft PR, and verify the expected check runs (
    lint
    ,
    unit-tests
    ,
    e2e
    ) show up and that the coverage gate fails when you drop coverage below the threshold.
  4. Verify artifacts — download the run's artifacts from the Actions UI (or
    gh run download <id>
    ) and confirm
    playwright-report/
    and traces are present.

在依赖管道前先验证其有效性。从最小检查开始:
  1. 检查工作流语法 ——
    actionlint .github/workflows/*.yml
    可在运行前捕获表达式、
    needs
    和shell引号错误。添加
    yamllint .github/workflows/
    检查缩进。也可将actionlint作为CI任务运行。
  2. 本地试运行任务 ——
    act -j unit-tests
    可在容器中运行任务,无需推送代码即可迭代调试。
  3. 确认必需检查显示 —— 推送代码到临时分支,创建草稿PR,验证预期的检查(
    lint
    unit-tests
    e2e
    )是否运行,且当覆盖率低于阈值时门禁是否失败。
  4. 验证工件 —— 从Actions UI下载运行的工件(或使用
    gh run download <id>
    ),确认
    playwright-report/
    和跟踪信息存在。

Done When

完成标准

  • A trigger map exists: push runs lint+unit only; the PR workflow gates E2E behind
    if: github.event_name == 'pull_request'
    (verify the YAML, not "integration runs somewhere").
  • actionlint .github/workflows/*.yml
    exits 0.
  • A non-blocking quarantine job runs
    --grep @flaky
    with
    continue-on-error: true
    ; the stable job runs
    --grep-invert @flaky
    and is in the required checks list.
  • Test artifacts (reports, screenshots, traces) upload on
    if: ${{ !cancelled() }}
    with an explicit
    retention-days
    /
    expire_in
    .
  • Concurrency groups with
    cancel-in-progress: true
    are set on the PR/test workflows.
  • Coverage is enforced by the runner's
    coverageThreshold
    /
    thresholds
    (job exits non-zero below the floor) — no
    coverage-summary
    CLI scrape.
  • Branch protection lists
    lint
    ,
    unit-tests
    , and
    e2e
    as required status checks.
  • No long-lived deploy token in YAML — deploy uses OIDC (
    id-token: write
    + cloud role) or, at minimum, a secrets-store reference.

  • 存在触发映射:分支推送仅运行lint+单元测试;PR工作流通过
    if: github.event_name == 'pull_request'
    管控E2E测试(验证YAML配置,而非仅确认「集成测试在某处运行」)。
  • actionlint .github/workflows/*.yml
    返回0。
  • 存在非阻塞隔离任务,执行
    --grep @flaky
    并设置
    continue-on-error: true
    ;稳定任务执行
    --grep-invert @flaky
    并加入必需检查列表。
  • 测试工件(报告、截图、跟踪信息)在
    if: ${{ !cancelled() }}
    条件下上传,并设置明确的
    retention-days
    /
    expire_in
  • PR/测试工作流设置了带有
    cancel-in-progress: true
    的并发组。
  • 覆盖率通过运行器的
    coverageThreshold
    /
    thresholds
    强制管控(低于下限任务返回非零退出码)——无
    coverage-summary
    命令行提取逻辑。
  • 分支保护列表中
    lint
    unit-tests
    e2e
    为必需状态检查。
  • YAML中无长期有效部署令牌——部署使用OIDC(
    id-token: write
    + 云角色),或至少使用密钥存储引用。

Related Skills

相关技能

  • playwright-automation — writing the E2E tests, Page Object Model, and the
    playwright.config.ts
    whose sharding/timeouts this pipeline drives.
  • test-reliability — runtime self-healing of one flaky test (selector recovery, retry policy); go there to fix a flaky test, come here to quarantine it in CI.
  • qa-metrics — turning the JUnit/coverage artifacts this pipeline produces into dashboards and flakiness trends.
  • release-readiness — the human go/no-go decision and release checklist that consumes these gate results; this skill builds the gates, that one decides on them.
  • coverage-analysis — finding the coverage gaps and setting the threshold this skill's PR gate enforces.
  • playwright-automation —— 编写E2E测试、页面对象模型,以及配置分片/超时的
    playwright.config.ts
    ,本管道基于这些配置运行。
  • test-reliability —— 单不稳定测试的运行时自修复(选择器恢复、重试策略);修复不稳定测试请使用该技能,在CI中隔离不稳定测试请使用本技能。
  • qa-metrics —— 将本管道生成的JUnit/覆盖率工件转换为仪表板和不稳定测试趋势报告。
  • release-readiness —— 基于门禁结果做出人工发布决策和发布清单;本技能构建门禁,该技能基于门禁做出决策。
  • coverage-analysis —— 发现覆盖率缺口并设置本技能PR门禁强制执行的阈值。

Reference Files (in
references/
)

参考文件(位于
references/

  • github-actions-templates.md — copy-paste unit, sharded Playwright E2E (+ report merge), full pipeline, nightly (Slack + audit + axe), and PR quality-gate workflows, plus conditional execution and local-repro snippets.
  • gitlab-ci-template.md — full
    .gitlab-ci.yml
    with parallel sharding, cobertura coverage, and JUnit MR reporting.
  • github-actions-templates.md —— 可直接复用的单元测试、分片Playwright E2E测试(+报告合并)、完整管道、夜间任务(Slack+审计+axe)、PR质量门禁工作流,以及条件执行和本地复现代码片段。
  • gitlab-ci-template.md —— 完整的
    .gitlab-ci.yml
    ,包含并行分片、cobertura覆盖率、JUnit MR报告。