Some checks failed
Create issues from TODOs / todos (push) Failing after 3s
Close inactive issues / close-issues (push) Has been cancelled
Deploy GitHub Pages / deploy-preview (push) Has been cancelled
CI / ⚙️ Variables Setup (push) Has been cancelled
CI / ⚙️ Test Guard (push) Has been cancelled
CI / 🚀 Notify external services - draft (push) Has been cancelled
CI / 📦 Build Packages (push) Has been cancelled
CI / 📦 Meteor Build (coverage) (push) Has been cancelled
CI / 📦 Meteor Build (production) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [account-service presence-service omnichannel-transcript-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [authorization-service queue-worker-service ddp-streamer-service], fips) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Build Docker (amd64, [rocketchat], fips) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [account-service presence-service omnichannel-transcript-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [authorization-service queue-worker-service ddp-streamer-service], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], ${{ (github.event_name != 'release' && github.ref != 'refs/heads/develop') && 'coverage' || 'production' }}) (push) Has been cancelled
CI / 🚢 Build Docker (arm64, [rocketchat], coverage) (push) Has been cancelled
CI / 🚢 Publish Docker Images (ghcr.io) (push) Has been cancelled
CI / 📦 Track Image Sizes (push) Has been cancelled
CI / 🔎 Code Check - Action Lint (push) Has been cancelled
CI / 🔎 Code Check (push) Has been cancelled
CI / 🔨 Test Storybook (push) Has been cancelled
CI / 🔨 Test Unit (push) Has been cancelled
CI / 🔨 Test API (CE) (push) Has been cancelled
CI / 🔨 Test API Livechat (CE) (push) Has been cancelled
CI / 🔨 Test UI (CE) (push) Has been cancelled
CI / 🔨 Test API (EE) (push) Has been cancelled
CI / 🔨 Test API Livechat (EE) (push) Has been cancelled
CI / 🔨 Test API Apps (deno-runtime - EE) (push) Has been cancelled
CI / 🔨 Test UI (EE) (push) Has been cancelled
CI / 🔨 Test API (FIPS) (push) Has been cancelled
CI / 🔨 Test API Livechat (FIPS) (push) Has been cancelled
CI / 🔨 Test UI (FIPS) (push) Has been cancelled
CI / 🔨 Test Federation Matrix (push) Has been cancelled
CI / 📊 Report Coverage (push) Has been cancelled
CI / ✅ Tests Done (push) Has been cancelled
CI / 🚀 Publish build assets (push) Has been cancelled
CI / 🚀 Publish Docker Images (DockerHub) (push) Has been cancelled
CI / 🚀 Notify external services (push) Has been cancelled
CI / Update Version Durability (push) Has been cancelled
Release / Release (push) Has been cancelled
Auto-close duplicate issues / auto-close-duplicates (push) Failing after 1s
Code scanning - action / CodeQL-Build (push) Failing after 2s
126 lines
4.6 KiB
Markdown
126 lines
4.6 KiB
Markdown
# Code Coverage
|
|
|
|
This document explains how code coverage instrumentation works in Rocket.Chat's build and CI pipeline.
|
|
|
|
## Overview
|
|
|
|
Coverage is collected during E2E test runs (API, UI, Livechat) to measure how much of the server-side code is exercised by tests. The instrumentation uses [Istanbul](https://istanbul.js.org/)-compatible tooling, which injects counters (`__coverage__`) into the compiled code at build time.
|
|
|
|
## Architecture
|
|
|
|
The coverage pipeline has three components:
|
|
|
|
1. **Build-time instrumentation** - injects coverage counters into the code during Meteor build
|
|
2. **Runtime collection** - the `rocketchat:coverage` Meteor package collects `__coverage__` data on process exit
|
|
3. **CI reporting** - test workflows merge coverage data and upload reports
|
|
|
|
```
|
|
Build (SWC + plugin) --> Run tests --> Process exit triggers report --> Merge & upload
|
|
```
|
|
|
|
## Build-time instrumentation
|
|
|
|
### Modern build stack (SWC)
|
|
|
|
Rocket.Chat uses Meteor's modern build stack with [SWC](https://swc.rs/) as the transpiler. For coverage builds, the [`swc-plugin-coverage-instrument`](https://github.com/kwonoj/swc-plugin-coverage-instrument) plugin is injected into `.swcrc` at build time.
|
|
|
|
This is configured in `.github/actions/meteor-build/action.yml`:
|
|
|
|
```yaml
|
|
env:
|
|
BABEL_ENV: ${{ inputs.type }} # "production" or "coverage"
|
|
```
|
|
|
|
When `BABEL_ENV=coverage`, the build script:
|
|
|
|
1. Adds `rocketchat:coverage` to `.meteor/packages`
|
|
2. Injects `swc-plugin-coverage-instrument` into `.swcrc` via a node script:
|
|
|
|
```js
|
|
const swcrc = JSON.parse(fs.readFileSync('./apps/meteor/.swcrc', 'utf8'));
|
|
swcrc.jsc.experimental = swcrc.jsc.experimental || {};
|
|
swcrc.jsc.experimental.plugins = swcrc.jsc.experimental.plugins || [];
|
|
swcrc.jsc.experimental.plugins.push(['swc-plugin-coverage-instrument', {}]);
|
|
fs.writeFileSync('./apps/meteor/.swcrc', JSON.stringify(swcrc, null, 2) + '\n');
|
|
```
|
|
|
|
This approach ensures the same build pipeline (SWC) is used for both regular and coverage builds, avoiding behavioral differences between build modes.
|
|
|
|
### Legacy build stack (Babel)
|
|
|
|
Before the modern build stack, coverage was handled via `babel-plugin-istanbul` configured in `.babelrc`:
|
|
|
|
```json
|
|
{
|
|
"env": {
|
|
"coverage": {
|
|
"plugins": [
|
|
["istanbul", { "exclude": ["**/*.spec.js", "**/*.test.js"] }]
|
|
]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
This section is still present in `.babelrc` as a fallback for files that fall back to Babel compilation (e.g., SWC-incompatible code).
|
|
|
|
## Runtime collection: `rocketchat:coverage`
|
|
|
|
The `rocketchat:coverage` Meteor package (`apps/meteor/packages/rocketchat-coverage/`) is only added to the build during coverage runs. It:
|
|
|
|
1. Registers a `process.on('exit')` handler
|
|
2. Reads `globalThis['__coverage__']` (populated by the instrumentation)
|
|
3. Generates a coverage report using `istanbul-lib-coverage` and `istanbul-reports`
|
|
|
|
Configuration via environment variables:
|
|
|
|
| Variable | Description | Example |
|
|
|---|---|---|
|
|
| `COVERAGE_DIR` | Output directory for reports | `/tmp/coverage/api` |
|
|
| `COVERAGE_FILE_NAME` | Report filename | `api-1.json` |
|
|
| `COVERAGE_REPORTER` | Istanbul reporter format | `json`, `lcov` |
|
|
|
|
## CI workflow
|
|
|
|
Coverage is collected in the `ci-test-e2e.yml` workflow:
|
|
|
|
1. **Build**: `meteor-build` action runs with `type: coverage`, producing a Docker image with instrumented code
|
|
2. **Test**: E2E tests run against the instrumented server. On each test shard:
|
|
- `COVERAGE_DIR`, `COVERAGE_FILE_NAME`, and `COVERAGE_REPORTER` are set
|
|
- When the Rocket.Chat process exits after tests, the coverage plugin writes a JSON report
|
|
3. **Merge**: `nyc merge` combines per-shard JSON reports into a single coverage file
|
|
4. **Upload**: Coverage data is uploaded to Codecov
|
|
|
|
## Local development
|
|
|
|
To build with coverage locally:
|
|
|
|
```bash
|
|
cd apps/meteor
|
|
|
|
# Inject the SWC coverage plugin into .swcrc
|
|
node -e "
|
|
const fs = require('fs');
|
|
const swcrc = JSON.parse(fs.readFileSync('.swcrc', 'utf8'));
|
|
swcrc.jsc.experimental = { plugins: [['swc-plugin-coverage-instrument', {}]] };
|
|
fs.writeFileSync('.swcrc', JSON.stringify(swcrc, null, 2));
|
|
"
|
|
|
|
# Add the coverage package
|
|
echo -e "rocketchat:coverage\n" >> .meteor/packages
|
|
|
|
# Set env vars and run
|
|
COVERAGE_DIR=/tmp/coverage COVERAGE_FILE_NAME=local.json COVERAGE_REPORTER=lcov yarn dev
|
|
```
|
|
|
|
Remember to restore `.swcrc` and `.meteor/packages` after testing.
|
|
|
|
## Dependencies
|
|
|
|
| Package | Purpose |
|
|
|---|---|
|
|
| `swc-plugin-coverage-instrument` | SWC plugin for Istanbul-compatible instrumentation |
|
|
| `istanbul-lib-coverage` | Coverage map creation (used by `rocketchat:coverage`) |
|
|
| `istanbul-lib-report` | Report context creation |
|
|
| `istanbul-reports` | Report formatters (json, lcov, etc.) |
|