Files
repomix-mirror/tests/core/treeSitter/LanguageParser.test.ts
Kazuki Yamada 7ff8c8b155 test: Address PR review feedback (RepomixError instances + mock isolation)
- outputGenerate: tests titled "throws RepomixError…" / "wraps … in
  RepomixError" now assert the rejection is an instance of RepomixError
  in addition to the message regex, matching the test names.
- LanguageParser: collapse the duplicate getParserForLang('javascript')
  rejection assertions into a single .catch capture that checks both
  type and message.
- calculateMetrics: vi.mocked(initTaskRunner).mockReset() before
  mockReturnValueOnce so a future test that omits taskRunner can't
  silently consume the override.
- packager: pre-attach a no-op .catch on the rejected warmupPromise so
  vitest's unhandled-rejection detection doesn't fire before pack
  awaits it. Production code mirrors this pattern in packager.ts:262.
2026-04-26 22:29:06 +09:00

80 lines
2.7 KiB
TypeScript

import { afterEach, beforeAll, describe, expect, it, vi } from 'vitest';
import { Parser } from 'web-tree-sitter';
import { LanguageParser } from '../../../src/core/treeSitter/languageParser.js';
import { RepomixError } from '../../../src/shared/errorHandle.js';
describe('LanguageParser', () => {
let parser: LanguageParser;
beforeAll(() => {
parser = new LanguageParser();
});
describe('guessTheLang', () => {
it('should return the correct language based on file extension', () => {
const testCases = [
{ filePath: 'file.js', expected: 'javascript' },
{ filePath: 'file.ts', expected: 'typescript' },
{ filePath: 'file.sol', expected: 'solidity' },
{ filePath: 'Contract.sol', expected: 'solidity' },
{ filePath: 'path/to/MyContract.sol', expected: 'solidity' },
];
for (const { filePath, expected } of testCases) {
const lang = parser.guessTheLang(filePath);
expect(lang).toBe(expected);
}
});
it('should return undefined for unsupported extensions', () => {
const filePath = 'file.txt';
const lang = parser.guessTheLang(filePath);
expect(lang).toBeUndefined();
});
});
describe('init / dispose', () => {
afterEach(() => {
vi.restoreAllMocks();
});
it('throws RepomixError when used before init', async () => {
const fresh = new LanguageParser();
const error = await fresh.getParserForLang('javascript').catch((e) => e);
expect(error).toBeInstanceOf(RepomixError);
expect((error as Error).message).toMatch(/not initialized/);
});
it('init() is idempotent — second call short-circuits', async () => {
const initSpy = vi.spyOn(Parser, 'init').mockResolvedValue(undefined);
const target = new LanguageParser();
await target.init();
await target.init();
expect(initSpy).toHaveBeenCalledTimes(1);
await target.dispose();
});
it('wraps Parser.init() failures as RepomixError', async () => {
vi.spyOn(Parser, 'init').mockRejectedValue(new Error('wasm load failed'));
const target = new LanguageParser();
await expect(target.init()).rejects.toBeInstanceOf(RepomixError);
await expect(target.init()).rejects.toThrow(/Failed to initialize parser.*wasm load failed/);
});
it('dispose() resets state so subsequent calls require re-init', async () => {
vi.spyOn(Parser, 'init').mockResolvedValue(undefined);
const target = new LanguageParser();
await target.init();
await target.dispose();
// After dispose, the parser should look fresh again.
await expect(target.getParserForLang('javascript')).rejects.toThrow(/not initialized/);
});
});
});