Skip to content

Commit 4339089

Browse files
authored
Merge pull request #3 from hawkeyexl/tests
Refactor and enhance template validation with comprehensive tests
2 parents f38dd8a + aa81630 commit 4339089

33 files changed

+1957
-404
lines changed

.github/workflows/test.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
types: [ opened, synchronize ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Set up Node.js
17+
uses: actions/setup-node@v4
18+
19+
- name: Install dependencies
20+
run: npm ci
21+
22+
- name: Run tests
23+
run: npm test

.husky/pre-commit

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
npm test

test/artifacts/package_test.js renamed to artifacts/package_test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { lintDocument } from '../../index.js';
1+
import { lintDocument } from '../src/index.js';
22

33
const result = await lintDocument({
44
file: './test/artifacts/sample_markdown.md',
File renamed without changes.
File renamed without changes.
File renamed without changes.

package-lock.json

Lines changed: 37 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
"version": "0.0.3",
44
"description": "A tool to validate Markdown and AsciiDoc structure against a specified template",
55
"bin": {
6-
"doc-structure-lint": "index.js"
6+
"doc-structure-lint": "src/index.js"
77
},
8-
"main": "index.js",
8+
"main": "src/index.js",
99
"scripts": {
10-
"start": "node index.js",
11-
"test": "mocha 'src/**/*.test.js' 'test/**/*.test.js'"
10+
"start": "node src/index.js",
11+
"test": "mocha 'src/**/*.test.js'",
12+
"prepare": "husky"
1213
},
1314
"author": "Manny Silva",
1415
"license": "MIT",
@@ -25,6 +26,7 @@
2526
},
2627
"devDependencies": {
2728
"chai": "^5.1.2",
29+
"husky": "^9.1.7",
2830
"mocha": "^11.0.1",
2931
"sinon": "^19.0.2"
3032
},

src/cli.test.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import { expect } from "chai";
2+
import { exec } from "child_process";
3+
import fs from "fs";
4+
import path from "path";
5+
import os from "os";
6+
import { promisify } from "util";
7+
8+
const execAsync = promisify(exec);
9+
10+
describe("CLI functionality", () => {
11+
let tempDir;
12+
let templateFile;
13+
let documentFile;
14+
15+
beforeEach(() => {
16+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cli-test-'));
17+
templateFile = path.join(tempDir, 'templates.yaml');
18+
documentFile = path.join(tempDir, 'test-document.md');
19+
});
20+
21+
afterEach(() => {
22+
fs.rmSync(tempDir, { recursive: true, force: true });
23+
});
24+
25+
it("should validate document successfully via npx command", async () => {
26+
const template = `
27+
templates:
28+
test-template:
29+
sections:
30+
intro:
31+
heading:
32+
const: "Introduction"
33+
required: true`;
34+
35+
const document = "# Introduction\nSome content here.";
36+
37+
fs.writeFileSync(templateFile, template);
38+
fs.writeFileSync(documentFile, document);
39+
40+
const { stdout, stderr } = await execAsync(
41+
`npx . --file="${documentFile}" --template-path="${templateFile}" --template="test-template"`
42+
);
43+
44+
expect(stdout).to.include("Validation successful");
45+
}).timeout(5000);
46+
47+
it("should report validation errors via npx command", async () => {
48+
const template = `
49+
templates:
50+
test-template:
51+
sections:
52+
intro:
53+
heading:
54+
const: "Expected Heading"
55+
required: true`;
56+
57+
const document = "# Wrong Heading\nSome content here.";
58+
59+
fs.writeFileSync(templateFile, template);
60+
fs.writeFileSync(documentFile, document);
61+
62+
try {
63+
await execAsync(
64+
`npx . --file="${documentFile}" --template-path="${templateFile}" --template="test-template"`
65+
);
66+
expect.fail("Should have thrown an error");
67+
} catch (error) {
68+
expect(error.stdout).to.include("Expected title");
69+
}
70+
}).timeout(5000);
71+
72+
it("should show help message with --help flag", async () => {
73+
const { stdout } = await execAsync("npx . --help");
74+
75+
expect(stdout).to.include("Options:");
76+
expect(stdout).to.include("--file");
77+
expect(stdout).to.include("--template-path");
78+
expect(stdout).to.include("--template");
79+
}).timeout(5000);
80+
81+
it("should fail with meaningful error for missing arguments", async () => {
82+
try {
83+
await execAsync("npx .");
84+
expect.fail("Should have thrown an error");
85+
} catch (error) {
86+
expect(error.stderr).to.include("Options");
87+
}
88+
}).timeout(5000);
89+
90+
it("should handle invalid template path gracefully", async () => {
91+
try {
92+
await execAsync(
93+
`npx . --file="${documentFile}" --template-path="non-existent.yaml" --template="test-template"`
94+
);
95+
expect.fail("Should have thrown an error");
96+
} catch (error) {
97+
expect(error.stderr).to.include("Template file not found");
98+
expect(error.code).to.equal(1);
99+
}
100+
}).timeout(5000);
101+
102+
it("should handle malformed template file", async () => {
103+
fs.writeFileSync(templateFile, "invalid: yaml: content:");
104+
try {
105+
await execAsync(
106+
`npx . --file="${documentFile}" --template-path="${templateFile}" --template="test-template"`
107+
);
108+
expect.fail("Should have thrown an error");
109+
} catch (error) {
110+
expect(error.stderr).to.include("Failed to load and validate templates");
111+
expect(error.code).to.equal(1);
112+
}
113+
}).timeout(5000);
114+
});

0 commit comments

Comments
 (0)