sourcesailor
Version:
A CLI tool for analyzing and documenting codebases
147 lines (146 loc) • 7.17 kB
JavaScript
/* eslint-disable @typescript-eslint/no-explicit-any */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import yargs from 'yargs';
import { hideBin } from "yargs/helpers";
import { command, describe as commandDescribe, builder, handler } from '../commands/getDirStructure.mjs';
import * as directoryProcessor from '../directoryProcessor.mjs';
import * as utils from '../utils.mjs';
import * as inquirer from '@inquirer/prompts';
import * as setExpertise from '../commands/setExpertise.mjs';
const yargsSetup = yargs(hideBin(process.argv));
describe("Get Directory Structure Command Tests", () => {
const mockProjectPath = '/mock/project/path';
const mockFileStructure = {
name: 'root',
type: 'directory',
children: [
{ name: 'file1.txt', type: 'file', content: 'File 1 content' },
{
name: 'dir1', type: 'directory', children: [
{ name: 'file2.txt', type: 'file', content: 'File 2 content' }
]
}
]
};
beforeEach(() => {
vi.mock('fs');
vi.mock('../directoryProcessor.mjs');
vi.mock('../utils.mjs');
vi.mock('@inquirer/prompts');
vi.mock('../commands/setExpertise.mjs');
vi.spyOn(console, 'log').mockImplementation(() => { });
vi.spyOn(console, 'error').mockImplementation(() => { });
directoryProcessor.getDirStructure.mockResolvedValue(mockFileStructure);
vi.mocked(utils.readConfig).mockReturnValue({ ANALYSIS_DIR: '/test', userExpertise: 'intermediate' });
vi.mocked(inquirer.confirm).mockResolvedValue(false);
vi.mocked(setExpertise.handler).mockResolvedValue(undefined);
});
afterEach(() => {
vi.restoreAllMocks();
});
it("returns help output", async () => {
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler }).help();
const output = await new Promise((resolve) => {
parser.parse("dirStructure --help", (_err, _argv, output) => {
resolve(output);
});
});
expect(output).toContain("Get Directory Structure");
expect(output).toContain("--verbose");
expect(output).toContain("--withContent");
expect(output).toContain("--ignore");
});
it("calls getDirStructure with correct parameters", async () => {
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath} --verbose --withContent --ignore node_modules dist`, (_err, argv) => {
resolve(argv);
});
});
expect(directoryProcessor.getDirStructure).toHaveBeenCalledWith(mockProjectPath, ['node_modules', 'dist'], true);
});
it("logs directory structure with content when withContent is true", async () => {
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath} --withContent`, (_err, argv) => {
resolve(argv);
});
});
expect(console.log).toHaveBeenCalledWith(JSON.stringify(mockFileStructure));
});
it("logs directory structure without content when withContent is false", async () => {
const expectedStructureWithoutContent = JSON.parse(JSON.stringify(mockFileStructure));
const removeContent = (node) => {
delete node.content;
if (node.children) {
node.children.forEach(removeContent);
}
};
removeContent(expectedStructureWithoutContent);
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath} --withContent false`, (_err, argv) => {
resolve(argv);
});
});
expect(console.log).toHaveBeenCalledWith(JSON.stringify(expectedStructureWithoutContent));
});
it("uses default values when not provided", async () => {
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath}`, (_err, argv) => {
resolve(argv);
});
});
expect(directoryProcessor.getDirStructure).toHaveBeenCalledWith(mockProjectPath, [], false);
});
it("handles errors from getDirStructure", async () => {
const mockError = new Error("Mock error");
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
directoryProcessor.getDirStructure.mockRejectedValue(mockError);
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath}`, (_err, argv) => {
resolve(argv);
});
});
expect(consoleSpy).toHaveBeenCalledWith("Error analyzing directory structure:", mockError);
});
// it("handles invalid project path", async () => {
// const parser = yargsSetup.command({command, describe: commandDescribe, builder, handler})
// const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { })
// await new Promise((resolve) => {
// parser.parse(`dirStructure`, (_err: any, argv: unknown) => {
// console.log({argv})
// resolve(argv)
// })
// })
// expect(consoleSpy).toHaveBeenCalledWith("Error: Project path is required")
// })
it('should prompt for user expertise if not set', async () => {
vi.mocked(utils.readConfig).mockReturnValue({ ANALYSIS_DIR: '/test' });
vi.mocked(inquirer.confirm).mockResolvedValue(true);
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath}`, (_err, argv) => {
resolve(argv);
});
});
expect(inquirer.confirm).toHaveBeenCalledWith({
message: "Would you like to set your expertise now?",
default: true
});
expect(setExpertise.handler).toHaveBeenCalled();
});
it('should not prompt for user expertise if already set', async () => {
vi.mocked(utils.readConfig).mockReturnValue({ ANALYSIS_DIR: '/test', userExpertise: 'intermediate' });
const parser = yargsSetup.command({ command, describe: commandDescribe, builder, handler });
await new Promise((resolve) => {
parser.parse(`dirStructure ${mockProjectPath}`, (_err, argv) => {
resolve(argv);
});
});
expect(inquirer.confirm).not.toHaveBeenCalled();
expect(setExpertise.handler).not.toHaveBeenCalled();
});
});