From fa6bddaa1158c0359a1502d8b932b8b06cafdcbe Mon Sep 17 00:00:00 2001 From: Jason Nathan Date: Sat, 12 Oct 2024 16:34:59 +0800 Subject: [PATCH] Added more tests --- skeletor.mjs | 19 ++++-- skeletor.test.mjs | 148 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 153 insertions(+), 14 deletions(-) diff --git a/skeletor.mjs b/skeletor.mjs index b8c967f..eb0720a 100755 --- a/skeletor.mjs +++ b/skeletor.mjs @@ -158,23 +158,28 @@ export async function printUsage() { } } -function parseArguments() { - const args = Bun.argv.slice(2); - const options = { overwrite: false }; // default to not overwriting files +export function parseArguments(args = Bun.argv.slice(2)) { + const options = { overwrite: false }; // Default to not overwriting files for (let i = 0; i < args.length; i++) { const arg = args[i]; - if (arg === "--input" || (arg === "-i" && args[i + 1])) { + if ((arg === "--input" || arg === "-i") && args[i + 1]) { options.inputFilePath = path.resolve(args[i + 1]); - i++; + i++; // Skip the next argument as it’s the file path } else if (arg === "--help" || arg === "-h") { options.help = true; } else if (arg === "--overwrite" || arg === "-o") { options.overwrite = true; } else { - logError(`Unknown argument: ${args[i]}`); + logError(`Unknown argument: ${arg}`); options.help = true; } } + + // Set default inputFilePath if not provided + if (!options.inputFilePath) { + options.inputFilePath = path.resolve(".skeletorrc"); + } + return options; } @@ -240,3 +245,5 @@ if (import.meta.url === `file://${process.argv[1]}`) { } }); } + + diff --git a/skeletor.test.mjs b/skeletor.test.mjs index f0ecb34..0998935 100644 --- a/skeletor.test.mjs +++ b/skeletor.test.mjs @@ -6,7 +6,8 @@ import { traverseStructure, countTotalTasks, createFilesAndDirectories, - printUsage + printUsage , + parseArguments } from "./skeletor.mjs"; // Import the functions // Test directory where Skeletor will generate files and directories @@ -51,27 +52,34 @@ it("should create file with directories and respect overwrite option", (done) => it("should traverse directory structure correctly", () => { const structure = { - "src": { + src: { "index.js": "console.log('Hello, world!');", - "components": { - "Header.js": "// Header component" + components: { + "Header.js": "// Header component", + "Footer.js": "// Footer component" } } }; + // Traverse the directory structure const paths = Array.from(traverseStructure(testDir, structure)); - // Expected paths (unordered) + // Define the expected paths const expectedPaths = [ { type: "dir", path: path.join(testDir, "src") }, { type: "dir", path: path.join(testDir, "src", "components") }, { type: "file", path: path.join(testDir, "src", "index.js"), content: "console.log('Hello, world!');" }, - { type: "file", path: path.join(testDir, "src", "components", "Header.js"), content: "// Header component" } + { type: "file", path: path.join(testDir, "src", "components", "Header.js"), content: "// Header component" }, + { type: "file", path: path.join(testDir, "src", "components", "Footer.js"), content: "// Footer component" } ]; - // Check that paths match expectedPaths (regardless of order) + // Verify that each expected path exists in the generated paths array expectedPaths.forEach(expected => { - expect(paths).toEqual(expect.arrayContaining([expected])); + const found = paths.find(p => p.path === expected.path && p.type === expected.type); + expect(found).toBeTruthy(); + if (expected.content) { + expect(found.content).toBe(expected.content); + } }); }); @@ -126,3 +134,127 @@ it("should display help information when --help argument is passed", async () => // Restore the original console.log console.log = originalConsoleLog; }); + +it("should parse command-line arguments correctly", () => { + const options = parseArguments(["--input", "structure.yaml", "--overwrite"]); + + expect(options.inputFilePath).toBe(path.resolve("structure.yaml")); + expect(options.overwrite).toBe(true); +}); + +it("should set default options when no arguments are provided", () => { + const options = parseArguments([]); + + expect(options.inputFilePath).toBe(path.resolve(".skeletorrc")); + expect(options.overwrite).toBe(false); +}); + +it("should handle file creation errors", (done) => { + const faultyPath = "/invalid/path/to/file.txt"; + writeFileWithDirs(faultyPath, "content", false, (err) => { + expect(err).not.toBeNull(); // Expect an error to be returned + done(); + }); +}); + +it("should handle invalid YAML input", (done) => { + const invalidYaml = "invalid: yaml: data"; // Invalid YAML format + + fs.writeFileSync(path.join(testDir, ".skeletorrc"), invalidYaml); + fs.readFile(path.join(testDir, ".skeletorrc"), "utf8", (err, data) => { + expect(() => yaml.parse(data)).toThrow(); // Expect YAML parsing to fail + done(); + }); +}); + +it("should create directories and display progress", (done) => { + const structure = { + "src": { + "index.js": "console.log('Hello, world!');", + "components": { + "Header.js": "// Header component" + } + } + }; + + // Mock console.clear and process.stdout.write to capture progress output + const originalConsoleClear = console.clear; + const originalProcessWrite = process.stdout.write; + let progressOutput = ""; + + console.clear = () => {}; // No-op + process.stdout.write = (chunk) => { progressOutput += chunk; }; + + createFilesAndDirectories(testDir, structure, false, (err, stats) => { + expect(err).toBeNull(); + expect(progressOutput).toContain("Progress: 100.00%"); // Verify progress + console.clear = originalConsoleClear; + process.stdout.write = originalProcessWrite; + done(); + }); +}); + +it("should handle empty directory structure", () => { + const structure = {}; // No directories or files + const paths = Array.from(traverseStructure(testDir, structure)); + + expect(paths.length).toBe(0); // No paths should be generated +}); + +it("should handle missing .skeletorrc file", (done) => { + const missingFilePath = path.join(testDir, ".skeletorrc"); + + fs.rmSync(missingFilePath, { force: true }); // Ensure file is missing + fs.readFile(missingFilePath, "utf8", (err) => { + expect(err).not.toBeNull(); // Expect an error when reading a non-existent file + done(); + }); +}); + +it("should handle error reading usage file in printUsage", async () => { + const originalReadFileSync = fs.readFileSync; + fs.readFileSync = () => { throw new Error("File read error"); }; // Simulate file read error + + const originalConsoleError = console.error; + let errorOutput = ""; + console.error = (output) => { errorOutput += output; }; // Capture console.error + + await printUsage(); + expect(errorOutput).toContain("\u001B[31m"); + + fs.readFileSync = originalReadFileSync; // Restore original function + console.error = originalConsoleError; // Restore console.error +}); + +it("should correctly count the total number of tasks (directories and files)", () => { + const structure = { + src: { + "index.js": "console.log('Hello, world!');", + components: { + "Header.js": "// Header component", + "Footer.js": "// Footer component" + } + }, + config: { + "app.config": "config content", + } + }; + + const totalTasks = countTotalTasks(structure); + + // We expect 6 tasks in total: + // 2 directories (src, components) + // 4 files (index.js, Header.js, Footer.js, app.config) + expect(totalTasks).toBe(7); +}); + +it("should handle file write errors gracefully", (done) => { + const filePath = path.join(testDir, "testfile.txt"); + + // Simulate a file system write error by providing an invalid path + writeFileWithDirs("/invalid/path/to/file.txt", "content", false, (err) => { + expect(err).not.toBeNull(); + done(); + }); +}); +