1
0

status-json.test.ts 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /**
  2. * Tests for the CI/scripting fields `codegraph status --json` exposes (issue
  3. * #329): the `version`, `indexPath`, and `lastIndexed` fields, plus the
  4. * matching `CodeGraph.getLastIndexedAt()` library method.
  5. *
  6. * The CLI itself is exercised end-to-end against the built binary so the JSON
  7. * field names survive future refactors of the underlying plumbing.
  8. */
  9. import { describe, it, expect, beforeEach, afterEach } from 'vitest';
  10. import { execFileSync } from 'child_process';
  11. import * as fs from 'fs';
  12. import * as path from 'path';
  13. import * as os from 'os';
  14. import { CodeGraph } from '../src';
  15. const BIN = path.resolve(__dirname, '../dist/bin/codegraph.js');
  16. const PKG_VERSION = JSON.parse(
  17. fs.readFileSync(path.resolve(__dirname, '../package.json'), 'utf-8'),
  18. ).version as string;
  19. function runStatusJson(cwd: string): Record<string, unknown> {
  20. const stdout = execFileSync(process.execPath, [BIN, 'status', '--json'], {
  21. cwd,
  22. encoding: 'utf-8',
  23. env: { ...process.env, CODEGRAPH_NO_DAEMON: '1' },
  24. stdio: ['ignore', 'pipe', 'pipe'],
  25. });
  26. // JSON mode prints exactly one line to stdout; be defensive about any stray
  27. // leading output by parsing the last non-empty line.
  28. const line = stdout.trim().split('\n').filter(Boolean).pop()!;
  29. return JSON.parse(line);
  30. }
  31. describe('codegraph status --json — CI fields (#329)', () => {
  32. let tempDir: string;
  33. beforeEach(() => {
  34. tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'codegraph-status-json-'));
  35. });
  36. afterEach(() => {
  37. fs.rmSync(tempDir, { recursive: true, force: true });
  38. });
  39. it('getLastIndexedAt() is null before indexing and a recent ms timestamp after', async () => {
  40. const cg = CodeGraph.initSync(tempDir);
  41. expect(cg.getLastIndexedAt()).toBeNull();
  42. fs.writeFileSync(path.join(tempDir, 'a.ts'), 'export const x = 1;\n');
  43. const before = Date.now();
  44. await cg.indexAll();
  45. const after = Date.now();
  46. const last = cg.getLastIndexedAt();
  47. expect(last).not.toBeNull();
  48. expect(typeof last).toBe('number');
  49. expect(last!).toBeGreaterThanOrEqual(before - 1000);
  50. expect(last!).toBeLessThanOrEqual(after + 1000);
  51. cg.close();
  52. });
  53. it('status --json on an UNINITIALIZED project reports version + indexPath + lastIndexed:null', () => {
  54. const out = runStatusJson(tempDir);
  55. expect(out.initialized).toBe(false);
  56. expect(out.version).toBe(PKG_VERSION);
  57. expect(typeof out.indexPath).toBe('string');
  58. expect(out.indexPath as string).toContain('.codegraph');
  59. expect(out.lastIndexed).toBeNull();
  60. });
  61. it('status --json on an INDEXED project reports version + indexPath + a round-trippable lastIndexed', async () => {
  62. fs.writeFileSync(path.join(tempDir, 'a.ts'), 'export const x = 1;\n');
  63. const before = Date.now();
  64. const cg = CodeGraph.initSync(tempDir);
  65. await cg.indexAll();
  66. const after = Date.now();
  67. cg.close();
  68. const out = runStatusJson(tempDir);
  69. expect(out.initialized).toBe(true);
  70. expect(out.version).toBe(PKG_VERSION);
  71. expect(out.indexPath as string).toContain('.codegraph');
  72. expect(typeof out.lastIndexed).toBe('string');
  73. // ISO string that round-trips back into the index window.
  74. const ms = Date.parse(out.lastIndexed as string);
  75. expect(ms).toBeGreaterThanOrEqual(before - 1000);
  76. expect(ms).toBeLessThanOrEqual(after + 1000);
  77. });
  78. });