Files
Hermes ccaa923a5a
CI / Test & Lint (push) Canceled after 0s
CI / Security audit (push) Canceled after 0s
[grade=B] DC-071: Error tracking integration framework (Sentry-compatible)
Opt-in error tracking that forwards uncaught errors to Sentry/Bugsnag-style
services when ERROR_TRACKING_DSN env var is set. Without DSN, disabled.

Features:
- Sentry envelope format for wire compatibility
- Express error middleware (drop-in after routes)
- capture() + captureMessage() + flush()
- Non-blocking — tracking errors never crash the app
- 5s timeout on network sends
- Includes hostname, node version, memory, uptime, request context

10 tests, 1633 total pass.
2026-08-12 12:30:57 -07:00

92 lines
2.8 KiB
JavaScript

/**
* DC-071: Error tracker tests
*/
const errorTracker = require('../src/utilities/error-tracker');
describe('DC-071: Error Tracker', () => {
beforeEach(() => {
// Reset to clean state
errorTracker.dsn = null;
errorTracker.enabled = false;
});
describe('init()', () => {
it('is disabled without DSN', () => {
const enabled = errorTracker.init({});
expect(enabled).toBe(false);
expect(errorTracker.enabled).toBe(false);
});
it('enables with DSN', () => {
const enabled = errorTracker.init({
dsn: 'https://abc123@sentry.io/123',
release: '1.15.0',
});
expect(enabled).toBe(true);
expect(errorTracker.enabled).toBe(true);
expect(errorTracker.release).toBe('1.15.0');
});
it('reads DSN from env', () => {
process.env.ERROR_TRACKING_DSN = 'https://key@sentry.io/456';
const enabled = errorTracker.init({});
expect(enabled).toBe(true);
delete process.env.ERROR_TRACKING_DSN;
});
});
describe('capture()', () => {
it('returns undefined when disabled', () => {
const result = errorTracker.capture(new Error('test'));
expect(result).toBeUndefined();
});
it('returns event ID when enabled', () => {
errorTracker.init({ dsn: 'https://key@sentry.io/123' });
const eventId = errorTracker.capture(new Error('test'));
expect(eventId).toBeTruthy();
expect(typeof eventId).toBe('string');
});
it('handles null error gracefully', () => {
errorTracker.init({ dsn: 'https://key@sentry.io/123' });
const result = errorTracker.capture(null);
expect(result).toBeUndefined();
});
});
describe('captureMessage()', () => {
it('returns undefined when disabled', () => {
const result = errorTracker.captureMessage('test');
expect(result).toBeUndefined();
});
it('returns event ID when enabled', () => {
errorTracker.init({ dsn: 'https://key@sentry.io/123' });
const eventId = errorTracker.captureMessage('test info', 'info');
expect(eventId).toBeTruthy();
});
});
describe('middleware()', () => {
it('calls next(err) after capturing', () => {
errorTracker.init({ dsn: 'https://key@sentry.io/123' });
const middleware = errorTracker.middleware();
const err = new Error('middleware test');
const req = { url: '/test', method: 'GET', headers: {}, path: '/test' };
const res = {};
let nextCalled = false;
let nextArg = null;
middleware(err, req, res, (e) => { nextCalled = true; nextArg = e; });
expect(nextCalled).toBe(true);
expect(nextArg).toBe(err);
});
});
describe('flush()', () => {
it('resolves without error', async () => {
await expect(errorTracker.flush(100)).resolves.toBeUndefined();
});
});
});