AVA runs your tests concurrently and finishes fast. That concurrency is its killer feature — and the reason silent failures are particularly dangerous. When AVA stops running, the absence is as quick and quiet as a successful run. Your CI log shows no red, your Slack channel stays green, and nobody investigates.
A misconfigured files glob, a failing Node.js version matrix step, or a scheduled CI trigger that stopped firing can silence your AVA suite completely. No output. No error. Just a missing timestamp in the test report.
This tutorial shows you how to pair AVA with Vigilmon heartbeat monitors so that the absence of a test run is as loud as a test failure.
What You'll Cover
- Heartbeat monitoring for AVA test pipelines
- Using AVA's configuration and CLI hooks to send success pings
- Detecting zero-test runs and silent CI skips
- Integrating with GitHub Actions and GitLab CI
- Monitoring parallel and matrix test runs
Prerequisites
- A Node.js project using AVA
- A free account at vigilmon.online
The Problem: What AVA's Concurrent Model Hides
AVA's concurrent execution model means tests finish quickly — which is great for developer experience but can mask operational gaps:
- A
filespattern change that matches zero test files (AVA may exit 0 or 1 depending on config) - A
--matchtitle filter narrowing execution to nothing - A failing
requireorimportin a worker thread that crashes before assertions run - A scheduled CI job that stopped triggering because the repo went quiet
- A Node.js version incompatibility in a matrix build that skips the test step silently
Vigilmon's heartbeat pattern addresses this at the pipeline level: your AVA run sends a ping after successful completion, and Vigilmon alerts you if no ping arrives within the expected window.
Step 1: Create a Heartbeat Monitor in Vigilmon
- Log in to Vigilmon and click New Monitor → Heartbeat.
- Name it:
AVA Tests — mainorAVA Integration — nightly. - Set the Expected interval: 2 hours for push-triggered suites, 25 hours for nightly runs.
- Set the Grace period: 20 minutes for fast push suites, 1 hour for scheduled jobs.
- Save and copy the Ping URL —
https://vigilmon.online/api/heartbeat/<unique-id>.
Step 2: Ping Vigilmon After AVA Completes
AVA doesn't provide a direct afterAll lifecycle hook like Jest or Mocha, so the cleanest approach is to wrap the AVA invocation in your npm script or CI pipeline.
Option A: npm Script with Shell Guard
{
"scripts": {
"test": "ava",
"test:ci": "ava && node scripts/ping-heartbeat.mjs"
}
}
Create the ping script:
// scripts/ping-heartbeat.mjs
const url = process.env.VIGILMON_HEARTBEAT_URL;
if (!url) {
process.exit(0);
}
try {
const res = await fetch(url, {
method: "POST",
signal: AbortSignal.timeout(10_000),
});
if (!res.ok) {
console.error(`Vigilmon heartbeat returned ${res.status}`);
}
} catch (err) {
console.error("Vigilmon heartbeat failed:", err.message);
// Don't fail the build on a monitoring ping failure
}
The && operator ensures the ping only fires when AVA exits 0. If AVA fails, the script doesn't run, no ping reaches Vigilmon, and you get alerted.
Option B: AVA Tap Reporter + Exit Handler
For more control, use AVA's --tap reporter and a wrapper that checks the result:
#!/bin/bash
# scripts/run-tests.sh
set -euo pipefail
npx ava --tap | tee /tmp/ava-tap-output.txt
# If we reach here, AVA exited 0
if [ -n "$VIGILMON_HEARTBEAT_URL" ]; then
curl -fsS -X POST "$VIGILMON_HEARTBEAT_URL" \
--max-time 10 \
--retry 3 \
--retry-delay 2
fi
{
"scripts": {
"test:ci": "bash scripts/run-tests.sh"
}
}
Step 3: Integrate with GitHub Actions
# .github/workflows/test.yml
name: AVA Tests
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "15 3 * * *" # nightly 03:15 UTC
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- name: Install dependencies
run: npm ci
- name: Run AVA
run: npx ava
- name: Ping Vigilmon heartbeat
if: success()
run: |
curl -fsS -X POST "${{ secrets.VIGILMON_AVA_HEARTBEAT_URL }}" \
--max-time 10 \
--retry 3 \
--retry-delay 2
Store the secret: GitHub repo → Settings → Secrets and variables → Actions → New repository secret:
- Name:
VIGILMON_AVA_HEARTBEAT_URL - Value: ping URL from Step 1
The if: success() condition on the ping step ensures the heartbeat only fires when AVA passes. A failed AVA run causes the workflow to exit and skip the ping step.
Step 4: Matrix Build Monitoring
AVA projects often test against multiple Node.js versions. You may want separate heartbeat monitors per matrix axis, or a single monitor that requires all matrix variants to succeed.
Single heartbeat (any passing run):
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: "npm"
- run: npm ci
- run: npx ava
- name: Ping Vigilmon (Node ${{ matrix.node }})
if: success()
run: |
curl -fsS -X POST "${{ secrets[format('VIGILMON_AVA_NODE{0}_HEARTBEAT_URL', matrix.node)] }}" \
--max-time 10 \
--retry 3
Create three monitors — AVA Node 18, AVA Node 20, AVA Node 22 — each with its own secret. If any Node.js version starts failing or stops running, you get a targeted alert.
Single monitor for the primary version:
If you only care whether the latest LTS passes, add the ping only on the primary matrix entry:
- name: Ping Vigilmon heartbeat
if: success() && matrix.node == 20
run: |
curl -fsS -X POST "${{ secrets.VIGILMON_AVA_HEARTBEAT_URL }}" \
--max-time 10
Step 5: Integrate with GitLab CI
# .gitlab-ci.yml
test:ava:
image: node:20-alpine
stage: test
script:
- npm ci
- npx ava
after_script:
- |
if [ "$CI_JOB_STATUS" = "success" ]; then
curl -fsS -X POST "$VIGILMON_AVA_HEARTBEAT_URL" --max-time 10 --retry 3
fi
only:
- main
- merge_requests
- schedules
Set VIGILMON_AVA_HEARTBEAT_URL in GitLab → Settings → CI/CD → Variables (masked).
Step 6: Catch Zero-Test Runs
By default, AVA exits 0 when no test files match. To treat this as an error:
In ava.config.mjs:
// ava.config.mjs
export default {
files: ["test/**/*.test.mjs"],
// failWithoutAssertions: true — ensures each test has at least one assertion
failWithoutAssertions: true,
};
failWithoutAssertions: true causes AVA to fail if any test file has no assertions. Combine with a file count guard in CI:
- name: Verify test files exist
run: |
count=$(find test -name "*.test.mjs" | wc -l)
echo "Found $count test files"
[ "$count" -gt 0 ] || { echo "No test files found"; exit 1; }
If this step fails, the AVA step never runs, the ping step is skipped, and Vigilmon alerts you.
Step 7: Handle Concurrent Worker Crashes
AVA runs each test file in a separate worker process. If a worker crashes before running assertions (e.g., due to a syntax error or missing dependency), AVA exits non-zero — which is correct, but the error message can be buried in concurrent output.
Enable AVA's built-in serial mode for debugging, and monitor the concurrent production runs with Vigilmon:
{
"scripts": {
"test": "ava",
"test:serial": "ava --serial",
"test:ci": "ava && node scripts/ping-heartbeat.mjs"
}
}
The heartbeat approach means that even if a worker crash is missed in log review, the missing ping surfaces the problem within your grace period.
Step 8: Alert Channels
In Vigilmon, go to Notifications → New Channel and configure:
- Email — direct alert when a heartbeat is missed
- Slack webhook — post to
#engineeringor#test-alerts
When AVA stops pinging:
🔴 MISSED HEARTBEAT: AVA Tests — main
Last ping: 4 hours ago
Expected interval: 2 hours
When it recovers:
✅ HEARTBEAT RECOVERED: AVA Tests — main
Gap: 4 hours
Complete CI Template
# .github/workflows/ava.yml
name: AVA
on:
push:
branches: [main]
pull_request:
schedule:
- cron: "30 1 * * *"
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Verify test files exist
run: |
count=$(find test -name "*.test.mjs" -o -name "*.test.js" | wc -l)
[ "$count" -gt 0 ] || { echo "No test files found"; exit 1; }
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- name: Run AVA
run: npx ava
- name: Ping Vigilmon heartbeat
if: success()
run: |
curl -fsS -X POST "${{ secrets.VIGILMON_AVA_HEARTBEAT_URL }}" \
--max-time 10 \
--retry 3 \
--retry-delay 2
What You're Now Catching
| Silent failure mode | How Vigilmon detects it |
|---|---|
| files glob matches nothing | AVA exits 0 — guard with file count check |
| --match filter matches nothing | Same as above |
| Worker crash before assertions | AVA exits non-zero → no ping |
| CI job skipped by branch filter | No ping within interval → alert |
| Scheduled suite stops triggering | No ping → alert after grace period |
| Matrix build silently excluded | Per-Node-version monitors catch it |
| Tests fail (non-zero exit) | Ping step skipped (if: success()) → alert |
AVA's speed makes it easy to forget it's running. Vigilmon's heartbeat monitors make it impossible to forget when it stops.
Start monitoring your AVA pipelines today — register free at vigilmon.online.