Files
shiro-neko/test/diagnostics.test.ts
asepharyana de89457cf7
ci / check (macos-latest) (push) Canceled after 0s
ci / check (ubuntu-latest) (push) Canceled after 0s
ci / check (windows-latest) (push) Canceled after 0s
feat: add diagnostics tool for live command output monitoring
- Implemented diagnostics functionality to start, stop, and monitor background check commands.
- Created a DiagnosticsPanel for real-time output display in the UI.
- Added support for auto-detecting default diagnostics commands based on project configuration.
- Introduced run_checks tool to execute project verification commands and report results.
- Enhanced tools-extra with functions to parse AGENTS.md and package.json for check commands.
- Added diff review functionality to visualize changes made in the last turn.
- Implemented tests for diagnostics and run_checks functionalities to ensure reliability.
2026-09-11 22:09:19 +07:00

106 lines
3.8 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import { diagStart, diagStop, diagStatus, bootDiagnostics, defaultDiagnosticsCommand, shutdownDiagnostics } from '../src/diagnostics';
// Diagnostics spawns real processes, so each test gets a fresh state (the module
// is a singleton — one diagnostics command at a time).
describe('diagnostics module', () => {
afterEach(() => {
shutdownDiagnostics();
});
it('starts, shows running status, and stops a command', async () => {
const started = diagStart('node -e "setInterval(()=>{}, 1000)"');
expect(started.started).toBe(true);
const status = diagStatus();
expect(status.running).toBe(true);
expect(status.command).toContain('setInterval');
const stopped = diagStop();
expect(stopped.stopped).toBe(true);
expect(diagStatus().running).toBe(false);
});
it('reports exit code once the command finishes', async () => {
diagStart('node -e "process.exit(3)"');
// Wait for the process to actually exit.
await Bun.sleep(300);
const status = diagStatus();
expect(status.running).toBe(false);
expect(status.exit).toBe(3);
});
it('captures output into the tail', async () => {
diagStart('node -e "console.log(\'hello-diag\')"');
await Bun.sleep(300);
const status = diagStatus();
expect(status.tail).toContain('hello-diag');
expect(status.exit).toBe(0);
});
it('diagStop with nothing running is a no-op', () => {
expect(diagStop().stopped).toBe(false);
expect(diagStatus().running).toBe(false);
});
it('starting replaces a running command and kills the old one', async () => {
const oldHandle = diagStart('node -e "setInterval(()=>{}, 1000)"');
expect(oldHandle.started).toBe(true);
const second = diagStart('node -e "console.log(\'second\')"');
expect(second.started).toBe(true);
const status = diagStatus();
expect(status.command).toContain('second');
// old process is gone; status.command reflects the newest start
shutdownDiagnostics();
});
it('bootDiagnostics ignores empty config and starts a real one', async () => {
bootDiagnostics(undefined);
expect(diagStatus().running).toBe(false);
bootDiagnostics('node -e "setInterval(()=>{}, 1000)"');
expect(diagStatus().running).toBe(true);
});
it('bootDiagnostics never throws on a bad command — keeps boot clean', async () => {
expect(() => bootDiagnostics('')).not.toThrow();
// A command that cannot spawn (bad binary) still must not throw synchronously.
expect(() => bootDiagnostics('/nonexistent/binary')).not.toThrow();
await Bun.sleep(50);
shutdownDiagnostics();
});
});
describe('defaultDiagnosticsCommand — auto-detection', () => {
const tmp = `${Bun.env['TMPDIR'] ?? '/tmp'}/diag-default-${process.pid}-${Math.random().toString(36).slice(2)}`;
let savedCwd: string;
const { mkdirSync, rmSync, writeFileSync } = require('node:fs') as typeof import('node:fs');
beforeEach(() => {
savedCwd = process.cwd();
rmSync(tmp, { recursive: true, force: true });
mkdirSync(tmp, { recursive: true });
process.chdir(tmp);
});
afterEach(() => {
process.chdir(savedCwd);
diagStop();
});
it('picks tsc --watch for a bun+ts project', async () => {
writeFileSync('bun.lock', '');
writeFileSync('package.json', '{}');
writeFileSync('tsconfig.json', '{}');
expect(await defaultDiagnosticsCommand(process.cwd())).toBe('bun run typecheck --watch');
});
it('falls back to bun test --watch without tsconfig', async () => {
writeFileSync('bun.lock', '');
writeFileSync('package.json', '{}');
expect(await defaultDiagnosticsCommand(process.cwd())).toBe('bun test --watch');
});
it('returns undefined for an unknown project', async () => {
expect(await defaultDiagnosticsCommand(process.cwd())).toBeUndefined();
});
});