@gitlab/jest-metrics-exporter
A Jest reporter that collects test execution data and pushes it to the GitLab
Quality Observer service.
Installation
pnpm add -D @gitlab/jest-metrics-exporter
Usage
Preconditions
For reporter to correctly detect file locations,
it requires flag --testLocationInResults to be set.
Minimal (env-only) setup
Register the reporter in jest.config.js and rely on environment variables
for everything else:
module.exports = {
testLocationInResults: true,
reporters: ['default', '@gitlab/jest-metrics-exporter'],
};
testLocationInResults: true is required — without it the reporter logs an
error and skips export for the run.
Full setup with options and predicates
For function-typed options (skipRecord, testRetried, customMetrics),
import the reporter class and use the tuple form:
module.exports = {
testLocationInResults: true,
reporters: [
'default',
['@gitlab/jest-metrics-exporter', {
runType: 'frontend_unit',
specFilePathPrefix: 'frontend/',
skipRecord: (testCase) => testCase.fullName.includes('@flaky'),
testRetried: (testCase) => testCase.invocations > 1,
customMetrics: (testCase) => ({
pipelineType: 'merge_request_pipeline',
}),
}],
],
};
Configuration options
Options can be passed via the reporter-options object (second element of the
tuple in reporters) or via environment variables. Explicit options always
take precedence over the corresponding environment variable.
runType | GLCI_TEST_METRICS_RUN_TYPE | Suite name (falls back to testLevel, then CI_JOB_NAME, or "unknown") |
testLevel | GLCI_TEST_METRICS_TEST_LEVEL | Suite-wide test level / tier (e.g. unit, integration) |
observerUrl | GLCI_OBSERVER_URL | Observer service base URL |
observerToken | GLCI_OBSERVER_AUTH_TOKEN | Auth token sent as X-Gitlab-Token |
specFilePathPrefix | (none) | Prepended to file paths (useful for monorepos) |
extraMetadataKeys | (none) | Magic-comment keys forwarded verbatim into the metric record (see below) |
skipRecord | (none) | (testCase) => boolean; return true to drop the record |
testRetried | (none) | (testCase) => boolean; return true if this run was a retry |
customMetrics | (none) | (testCase) => object; merged into every metric record |
logger | (none) | Logger-like object with debug/info/warn/error methods |
Two control-flow variables gate whether the reporter activates at all:
CI | Must be set (any non-empty value) for the reporter to run |
GLCI_EXPORT_TEST_METRICS | Set to "false" to disable export. Defaults to "true". |
Activation requirements
The reporter is a no-op (i.e. does nothing, never crashes the run) unless
all of the following hold:
CI is set.
GLCI_EXPORT_TEST_METRICS is not "false".
observerUrl and observerToken are both resolved (from options or env).
The reporter logs a warning in this case.
You can annotate individual tests (or whole describe blocks) with
// gitlab:key=value comments placed directly above the call:
describe('Push branch', () => {
it.skip('handles fast-forward push', () => {
});
});
The following annotations are applied automatically:
feature_category overrides the default "unknown" on the metric record.
quarantine_issue_url populates the matching field; the test is also
marked quarantined: true only when its status is skipped or pending.
A failing test in quarantine keeps quarantined: false — the field is
meant to track "currently skipped because of an open quarantine issue",
matching the Observer's documented schema.
Any additional annotation key (e.g. owner, priority) is forwarded
verbatim only when the key is listed in extraMetadataKeys:
['@gitlab/jest-metrics-exporter', {
extraMetadataKeys: ['owner', 'priority'],
}]
Rules:
- Both
// gitlab:key=value and // gitlab:key: value are accepted.
- Annotations must be contiguous with the test or
describe they
belong to — a blank line (or any non-comment statement) between the
comment and the call breaks the attachment. Plain // regular comments
between the annotation and the call are tolerated and do not detach
it, matching the way Go's doc-comment groups work.
- Annotations on an enclosing
describe propagate to nested tests; a
matching key on an inner block (or customMetrics) overrides them.
Development
pnpm install
pnpm test
pnpm run lint
Release
The canonical version lives in src/version.ts. Bump it
there and open an MR. CI runs a sync-package-version
job on the MR that keeps package.json's version field aligned by pushing
a sync commit back to the MR branch.
Once the MR is merged to the default branch, CI creates a jest-<version>
git tag automatically, which triggers a publish to the GitLab Package
Registry.
The sync-back step requires a DEVELOPMENT_API_TOKEN CI/CD variable with
write_repository scope.
License
MIT.