tutorial

Monitoring AVA Test Pipelines with Vigilmon: Alert on Silent Concurrent Test Failures

Use Vigilmon heartbeat monitors to detect when AVA test suites stop running — because concurrent test execution makes silent failures especially easy to miss.

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


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 files pattern change that matches zero test files (AVA may exit 0 or 1 depending on config)
  • A --match title filter narrowing execution to nothing
  • A failing require or import in 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

  1. Log in to Vigilmon and click New Monitor → Heartbeat.
  2. Name it: AVA Tests — main or AVA Integration — nightly.
  3. Set the Expected interval: 2 hours for push-triggered suites, 25 hours for nightly runs.
  4. Set the Grace period: 20 minutes for fast push suites, 1 hour for scheduled jobs.
  5. Save and copy the Ping URLhttps://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 #engineering or #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.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →