Files
gstack/browse/test/error-handling.test.ts
T
Garry Tan 2468a25aa1 refactor: add error-handling utility module with selective catches
safeUnlink (ignores ENOENT), safeKill (ignores ESRCH), isProcessAlive
(extracted from cli.ts with Windows support), and json() Response helper.
All catches check err.code and rethrow unexpected errors instead of
swallowing silently. Unit tests cover happy path + error code paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 04:41:32 -10:00

65 lines
2.0 KiB
TypeScript

import { describe, test, expect } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { safeUnlink, safeKill, isProcessAlive, json } from '../src/error-handling';
describe('safeUnlink', () => {
test('removes an existing file', () => {
const tmp = path.join(os.tmpdir(), `test-safeUnlink-${Date.now()}`);
fs.writeFileSync(tmp, 'hello');
safeUnlink(tmp);
expect(fs.existsSync(tmp)).toBe(false);
});
test('ignores ENOENT (file does not exist)', () => {
expect(() => safeUnlink('/tmp/nonexistent-file-' + Date.now())).not.toThrow();
});
test('rethrows non-ENOENT errors', () => {
// Attempt to unlink a directory — throws EPERM/EISDIR
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'test-safeUnlink-'));
expect(() => safeUnlink(dir)).toThrow();
fs.rmdirSync(dir);
});
});
describe('safeKill', () => {
test('sends signal to a running process', () => {
// signal 0 is a no-op existence check — safe to send to self
expect(() => safeKill(process.pid, 0)).not.toThrow();
});
test('ignores ESRCH (process does not exist)', () => {
// PID 99999999 is extremely unlikely to exist
expect(() => safeKill(99999999, 0)).not.toThrow();
});
});
describe('isProcessAlive', () => {
test('returns true for current process', () => {
expect(isProcessAlive(process.pid)).toBe(true);
});
test('returns false for non-existent process', () => {
expect(isProcessAlive(99999999)).toBe(false);
});
});
describe('json', () => {
test('returns Response with JSON body and correct Content-Type', async () => {
const resp = json({ ok: true });
expect(resp.status).toBe(200);
expect(resp.headers.get('Content-Type')).toBe('application/json');
const body = await resp.json();
expect(body).toEqual({ ok: true });
});
test('uses custom status code', async () => {
const resp = json({ error: 'not found' }, 404);
expect(resp.status).toBe(404);
const body = await resp.json();
expect(body).toEqual({ error: 'not found' });
});
});