GitNexus/gitnexus/test/unit/analyze-api.test.ts
Gergő Magyar bf09eab95b
feat: configure prettier with pre-commit hook (#563)
* feat: configure prettier with pre-commit hook integration

Add prettier, lint-staged, and prettier-plugin-tailwindcss at the repo
root with husky pre-commit hook integration. Moves husky from
gitnexus/ to root package.json for reliable hook installation.

- Root package.json with prepare/format/format:check scripts
- .prettierrc with endOfLine:lf and tailwindStylesheet for TW v4
- .prettierignore excluding fixtures, vendor, generated, *.d.ts, *.md
- .gitattributes enforcing LF line endings for Windows consistency
- Pre-commit hook uses direct node_modules/.bin/ paths (no npx)

* style: apply prettier formatting to entire codebase

One-time bulk format. No logic changes.
Use .git-blame-ignore-revs to skip this commit in git blame.

* chore: add .git-blame-ignore-revs for prettier format commit

* perf: pre-commit hook runs only tests related to staged files

Use vitest --related to scope test execution to tests that import
the changed files, instead of running the full suite on every commit.

* perf: remove vitest from pre-commit hook, keep in CI only

Pre-commit now runs lint-staged + tsc only. Tests run in CI
(ci-tests.yml) where they belong — keeps commits fast.

* ci: add prettier format check to quality workflow

PRs will now fail if code isn't formatted with prettier.
2026-03-28 14:58:04 +00:00

61 lines
2.1 KiB
TypeScript

import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { JobManager } from '../../src/server/analyze-job.js';
describe('analyze API logic', () => {
let manager: JobManager;
beforeEach(() => {
manager = new JobManager();
});
afterEach(() => {
manager.dispose();
});
it('creates a job and returns 202 shape', () => {
const job = manager.createJob({ repoUrl: 'https://github.com/user/repo' });
const response = { jobId: job.id, status: job.status };
expect(response.jobId).toBeTruthy();
expect(response.status).toBe('queued');
});
it('rejects when job already active for different repo', () => {
const job1 = manager.createJob({ repoUrl: 'https://github.com/user/repo1' });
manager.updateJob(job1.id, { status: 'analyzing' });
expect(() => manager.createJob({ repoUrl: 'https://github.com/user/repo2' })).toThrow(
/already in progress/,
);
});
it('returns existing job for same repo URL', () => {
const job1 = manager.createJob({ repoUrl: 'https://github.com/user/repo' });
manager.updateJob(job1.id, { status: 'analyzing' });
const job2 = manager.createJob({ repoUrl: 'https://github.com/user/repo' });
expect(job2.id).toBe(job1.id);
});
it('SSE progress listener receives all events including terminal', () => {
const job = manager.createJob({ repoUrl: 'https://github.com/user/sse-test' });
const events: any[] = [];
const unsub = manager.onProgress(job.id, (progress) => {
events.push(progress);
});
manager.updateJob(job.id, {
status: 'analyzing',
progress: { phase: 'parsing', percent: 30, message: 'Parsing' },
});
manager.updateJob(job.id, {
progress: { phase: 'calls', percent: 50, message: 'Tracing calls' },
});
manager.updateJob(job.id, { status: 'complete', repoName: 'sse-test' });
unsub();
expect(events.length).toBe(3);
expect(events[0].phase).toBe('parsing');
expect(events[1].phase).toBe('calls');
expect(events[2].phase).toBe('complete');
expect(events[2].percent).toBe(100);
});
});