Your TestCafe nightly suite ran clean for a month. Then a misconfigured pipeline variable quietly disabled the test job on a Friday. By Monday, three broken user flows had escaped to production — TestCafe had no errors to show because it was never invoked.
This is the silent E2E failure problem. HTTP uptime monitors can't catch it because there's no HTTP endpoint for "test suite ran today." The solution is heartbeat monitoring: TestCafe pings a unique URL at the end of each successful run, and Vigilmon alerts you when that ping stops arriving on schedule.
This tutorial shows you how to wire TestCafe into Vigilmon so you're always notified when your end-to-end tests go quiet.
What You'll Cover
- Heartbeat monitoring for scheduled TestCafe runs
- Detecting TestCafe runners that stop triggering entirely
- Alerting on test suites that fail silently or hang
- Multi-environment E2E monitoring (staging and production)
- Catching CI schedule drift before it becomes a production incident
Prerequisites
- A TestCafe test suite (version 1.x or 3.x)
- A free account at vigilmon.online
The Problem: What Standard TestCafe Reporting Misses
TestCafe ships with rich reporters and exit codes — but nothing alerts you when:
- The CI job that schedules TestCafe is accidentally removed or paused
- A glob pattern change causes zero tests to match (exit 0 with no tests run)
- The Node.js process running TestCafe hangs on a flaky fixture
- A test machine is offline and the queue silently backs up
- An environment variable change prevents browsers from launching
Vigilmon's heartbeat pattern closes every one of these gaps.
Step 1: Create a Heartbeat Monitor in Vigilmon
A heartbeat monitor expects a ping at a regular interval. No ping → alert.
- Log in to Vigilmon and click New Monitor → Heartbeat.
- Name it something like
TestCafe E2E — Nightly. - Set Expected interval to match your test schedule. For a nightly run, use 24 hours; for pre-deploy smoke tests, try 4 hours.
- Set Grace period to 1 hour to account for slow browser launches and retries.
- Save and copy the Ping URL — it looks like
https://vigilmon.online/api/heartbeat/<unique-id>.
Step 2: Create a Vigilmon Reporter
TestCafe supports custom reporters that receive run results. Create a lightweight reporter that pings Vigilmon when all tests pass:
// testcafe-reporter-vigilmon.js
const https = require("https");
function pingVigilmon(url) {
return new Promise((resolve, reject) => {
const req = https.request(url, { method: "POST" }, (res) => {
resolve(res.statusCode);
});
req.on("error", reject);
req.setTimeout(10000, () => {
req.destroy(new Error("Vigilmon ping timed out"));
});
req.end();
});
}
module.exports = () => ({
noColors: false,
async reportTaskDone(endTime, passed, warnings, result) {
const heartbeatUrl = process.env.VIGILMON_HEARTBEAT_URL;
if (!heartbeatUrl) return;
// Only ping when every test passed and no tests were skipped
const allPassed = result.failedCount === 0 && result.skippedCount === 0;
if (allPassed) {
try {
await pingVigilmon(heartbeatUrl);
this.write("Vigilmon heartbeat sent\n");
} catch (e) {
this.write(`Vigilmon heartbeat failed: ${e.message}\n`);
}
}
},
reportFixtureStart() {},
reportTestStart() {},
reportTestActionStart() {},
reportTestActionDone() {},
reportTestDone() {},
});
The reportTaskDone hook fires after all fixtures complete. Failures suppress the ping, which causes Vigilmon to alert after the grace period expires.
Step 3: Register the Reporter and Run TestCafe
Reference the reporter in your .testcaferc.json:
{
"browsers": ["chrome:headless"],
"src": "tests/**/*.test.js",
"reporter": [
{ "name": "spec" },
{ "name": "./testcafe-reporter-vigilmon.js" }
],
"concurrency": 2
}
Or pass it on the command line:
VIGILMON_HEARTBEAT_URL="https://vigilmon.online/api/heartbeat/<id>" \
npx testcafe chrome:headless tests/ \
--reporter spec,./testcafe-reporter-vigilmon.js
GitHub Actions
# .github/workflows/e2e.yml
name: TestCafe E2E
on:
schedule:
- cron: "0 2 * * *" # 02:00 UTC nightly
push:
branches: [main]
jobs:
testcafe:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: npm ci
- name: Start application
run: npm run start:ci &
- name: Wait for server
run: npx wait-on http://localhost:3000 --timeout 30000
- name: Run TestCafe
env:
VIGILMON_HEARTBEAT_URL: ${{ secrets.VIGILMON_TESTCAFE_HEARTBEAT_URL }}
run: |
npx testcafe chrome:headless tests/ \
--reporter spec,./testcafe-reporter-vigilmon.js
GitLab CI
# .gitlab-ci.yml
testcafe:nightly:
stage: test
image: node:20
variables:
VIGILMON_HEARTBEAT_URL: $VIGILMON_TESTCAFE_HEARTBEAT_URL
only:
- schedules
script:
- npm ci
- npm run start:ci &
- npx wait-on http://localhost:3000
- npx testcafe chrome:headless tests/ --reporter spec,./testcafe-reporter-vigilmon.js
Step 4: Handle Parallel TestCafe Runs
When running TestCafe across multiple machines, only send the heartbeat after all shards complete. Use a dedicated post-run job in your CI pipeline:
# .github/workflows/e2e-parallel.yml
jobs:
testcafe:
strategy:
matrix:
shard: [1, 2, 3]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run start:ci &
- run: npx wait-on http://localhost:3000
- name: Run shard ${{ matrix.shard }}
run: |
npx testcafe chrome:headless tests/ \
--reporter spec \
--concurrency 2
heartbeat:
needs: testcafe # Runs only after ALL shards succeed
runs-on: ubuntu-latest
if: success()
steps:
- name: Ping Vigilmon
run: |
curl -fsS -X POST "${{ secrets.VIGILMON_TESTCAFE_HEARTBEAT_URL }}" \
--max-time 10 --retry 3 --retry-delay 2
The needs: testcafe + if: success() combination ensures the heartbeat fires only when every shard passed.
Step 5: Multi-Environment Monitoring
For teams running TestCafe against staging and production:
| Suite | Environment | Monitor name | Interval |
|---|---|---|---|
| Nightly full regression | Staging | TestCafe E2E — Staging — Nightly | 25 h |
| Pre-deploy smoke | Staging | TestCafe Smoke — Staging | 4 h |
| Post-deploy verify | Production | TestCafe Smoke — Production | 2 h |
| Weekly cross-browser | Staging | TestCafe Cross-Browser — Weekly | 8 days |
Parameterize by environment:
// In reportTaskDone:
const env = process.env.TARGET_ENV || "staging";
const heartbeatVar = `VIGILMON_${env.toUpperCase()}_HEARTBEAT_URL`;
const heartbeatUrl = process.env[heartbeatVar];
TARGET_ENV=production \
VIGILMON_PRODUCTION_HEARTBEAT_URL="..." \
npx testcafe chrome:headless tests/ --reporter ./testcafe-reporter-vigilmon.js
Step 6: Configure Alert Channels
In Vigilmon, go to Notifications → New Channel and configure:
- Email — immediate alert when a heartbeat is missed
- Slack webhook — ping your
#qa-alertsor#e2e-testschannel
When a TestCafe suite stops pinging:
🔴 MISSED HEARTBEAT: TestCafe E2E — Nightly
Last ping: 26 hours ago
Expected interval: 24 hours
When it recovers:
✅ HEARTBEAT RECOVERED: TestCafe E2E — Nightly
Gap: 26 hours
What You're Now Catching
| Silent failure mode | How Vigilmon detects it | |---|---| | CI job disabled or removed | No ping arrives → alert after grace period | | Zero tests match the glob (exit 0) | No ping on empty run → alert | | Runner machine is offline | No ping → alert after grace period | | TestCafe hangs on a flaky fixture | Suite timeout → no ping → alert | | Browser fails to launch | Process exits non-zero → no ping → alert | | Environment variable misconfiguration | Test job errors silently → no ping → alert |
TestCafe gives you fast, cross-browser E2E coverage — until the runner quietly disappears. Vigilmon's heartbeat monitors give you the external signal TestCafe can't: a definitive alert when your end-to-end tests haven't run in longer than expected.
Add heartbeat monitoring to your TestCafe suite today — register free at vigilmon.online.