Skip to content
Back to skills

Gitlab Ci Test Jobs

ASecurity

Configures GitLab CI/CD test stages - `.gitlab-ci.yml` with parallel matrix, artifact reports (junit, coverage), services (postgres, redis), needs / dependencies between jobs, only/except + rules for trigger filtering, retry policy. Use when the project hosts on GitLab and the team wants idiomatic GitLab CI patterns.

  • 10 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 12, 2026
testingsqlnodedockerdebugginggitapidatabaseci/cd

Works with

  • api

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned October 12, 2026

npx -y skills add testland/qa --skill gitlab-ci-test-jobs --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gitlab Ci Test Jobs?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gitlab Ci Test Jobs
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/testland-gitlab-ci-test-jobs/badge)](https://www.skillsdirectory.com/skills/testland-gitlab-ci-test-jobs)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gitlab-ci-test-jobs
description: "Configures GitLab CI/CD test stages - `.gitlab-ci.yml` with parallel matrix, artifact reports (junit, coverage), services (postgres, redis), needs / dependencies between jobs, only/except + rules for trigger filtering, retry policy. Use when the project hosts on GitLab and the team wants idiomatic GitLab CI patterns."
---

# gitlab-ci-test-jobs

## Overview

Configured via `.gitlab-ci.yml` at the repo root. Structure:
**stages** (sequential phases) → **jobs** (parallel within a
stage) → **steps** (a job's `script:` array).

## When to use

- Project hosts on GitLab (self-hosted or .com).
- Existing `.gitlab-ci.yml` needs standardization.
- The team values GitLab's tight VCS / CI / registry / artifacts
  integration.

## Step 1 - Basic test job

```yaml
# .gitlab-ci.yml
stages:
  - test

test:
  stage: test
  image: node:22
  script:
    - npm ci
    - npm test
```

Default: runs on every push to any branch. Per-branch / per-MR
filtering via `rules:` (Step 7).

## Step 2 - Parallel matrix

```yaml
test:
  stage: test
  image: node:22
  parallel:
    matrix:
      - NODE_VERSION: ['20', '22']
        OS_IMAGE: ['node:20', 'node:22']
  script:
    - npm ci
    - npm test
```

`parallel: matrix:` runs the job once per matrix entry. Use
GitLab's matrix syntax for cross-product / explicit `include` for
specific combinations.

## Step 3 - Services (PostgreSQL, Redis)

```yaml
test:
  stage: test
  image: node:22
  services:
    - name: postgres:15
      alias: postgres
      variables:
        POSTGRES_PASSWORD: test
    - name: redis:7
      alias: redis
  variables:
    DATABASE_URL: 'postgres://postgres:test@postgres:5432/postgres'
    REDIS_URL: 'redis://redis:6379'
  script:
    - npm ci
    - npm test
```

The service hostname is the `alias` field; reachable from the job
container.

## Step 4 - JUnit + coverage reports

```yaml
test:
  stage: test
  script:
    - npm ci
    - npm test -- --reporters=default --reporters=jest-junit
  artifacts:
    when: always
    reports:
      junit: junit.xml
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml
    paths:
      - junit.xml
      - coverage/
    expire_in: 30 days
  coverage: '/Lines\s*:\s*([0-9.]+)%/'
```

GitLab natively renders:
- JUnit XML in the MR's "Test summary."
- Coverage in the MR widget (the `coverage:` regex parses %).
- Cobertura coverage as inline annotations on diff lines.

## Step 5 - Stages + needs

```yaml
stages:
  - lint
  - test
  - integration
  - e2e

lint:
  stage: lint
  script: npm run lint

unit:
  stage: test
  script: npm test
  needs: [lint]   # don't wait for stage; run as soon as lint passes

integration:
  stage: integration
  script: npm run test:integration
  needs: [unit]

e2e:
  stage: e2e
  script: npm run test:e2e
  needs: [integration]
```

`needs:` enables DAG-style pipelines (newer GitLab feature) - jobs
run as soon as their dependencies finish, not waiting for the
full stage.

## Step 6 - Retry policy

```yaml
test:
  retry:
    max: 2
    when:
      - runner_system_failure
      - stuck_or_timeout_failure
      - api_failure
```

Distinguish retry classes:
- `runner_system_failure` - runner died; safe to retry.
- `script_failure` - test failed; **don't retry** (masks bugs).
- `unknown_failure` - case by case.

## Step 7 - Trigger filtering via `rules:`

```yaml
test:
  rules:
    - if: $CI_PIPELINE_SOURCE == 'merge_request_event'
      changes:
        - 'src/**/*'
        - 'tests/**/*'
        - 'package.json'
    - if: $CI_COMMIT_BRANCH == 'main'
    - if: $CI_PIPELINE_SOURCE == 'schedule'
  script:
    - npm test
```

Modern `rules:` replaces older `only:` / `except:` (still work but
deprecated for new config).

## Step 8 - Caching

```yaml
test:
  cache:
    key:
      files:
        - package-lock.json
    paths:
      - .npm/
      - node_modules/
  script:
    - npm ci --cache .npm --prefer-offline
    - npm test
```

`cache:` per-job; speeds repeat installs. Pin the key to
`package-lock.json` so cache invalidates on dep changes.

## Step 9 - Variables + secrets

```yaml
variables:
  CI: 'true'
  NODE_ENV: 'test'

test:
  script:
    - npm test
  variables:
    # Job-level overrides
    NODE_AUTH_TOKEN: $CI_NPM_TOKEN
```

Secrets configured in **Project Settings → CI/CD → Variables**
(masked + protected for sensitive values).

## Anti-patterns

| Anti-pattern                                                          | Why it fails                                                              | Fix |
|-----------------------------------------------------------------------|---------------------------------------------------------------------------|-----|
| `retry: 5` on test failures                                            | Hides flake; never resolved.                                              | `retry: when:` only for runner / API failures (Step 6). |
| Hardcoded credentials in `.gitlab-ci.yml`                              | Secrets in repo.                                                          | CI/CD Variables (Step 9). |
| One mega-stage with all jobs                                            | No parallelism; slow pipeline.                                            | Stages + needs (Step 5). |
| Missing artifact upload on failure                                      | Failure debugging needs results.                                          | `when: always` (Step 4). |
| Default `image:` for everything                                         | Pulls Docker image per job; slow.                                         | Pin lightweight default (e.g., `alpine:latest` for non-build jobs). |

## Limitations

- **GitLab Runner setup for self-hosted.** Initial setup adds
  ops cost.
- **SaaS quota.** GitLab.com free tier has minute caps; private
  projects have stricter limits.
- **Per-job overhead.** Each job pulls images + clones repo;
  short-lived jobs are inefficient.
- **YAML complexity grows.** Large pipelines benefit from
  `include:` to split across files.

## References

- GitLab CI/CD docs at `docs.gitlab.com/ee/ci/`.
- `github-actions-test-jobs`,
  `jenkinsfile-test-stages` - 
  alternatives.
- `ci-test-job-conventions` - cross-CI conventions; CircleCI patterns
  live in its references/circleci.md.
- `junit-xml-analysis` - JUnit XML parser.
- `lcov-analysis` - Cobertura parser (GitLab's native coverage format).

Files in this skill

  • .tessl-plugin/plugin.json454 B
  • SKILL.md6.3 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.