Spaces:
Running
Running
Download scripts/doc-gardening.test.js from Felladrin/MiniSearch: direct link, hf CLI and curl.
- Browser
- Download file 6.15 kB
-
https://huggingface.co/spaces/Felladrin/MiniSearch/resolve/main/scripts/doc-gardening.test.js
- Command line
-
hf download hf://spaces/Felladrin/MiniSearch/scripts/doc-gardening.test.js
-
curl -L -o doc-gardening.test.js https://huggingface.co/spaces/Felladrin/MiniSearch/resolve/main/scripts/doc-gardening.test.js
6.15 kB
| import { execFileSync } from "node:child_process"; | |
| import fs from "node:fs"; | |
| import os from "node:os"; | |
| import path from "node:path"; | |
| import { fileURLToPath } from "node:url"; | |
| import { afterEach, beforeEach, describe, expect, it } from "vitest"; | |
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | |
| const SCRIPT_PATH = path.resolve(__dirname, "doc-gardening.cjs"); | |
| function runGarden(cwd, args = []) { | |
| try { | |
| const output = execFileSync(process.execPath, [SCRIPT_PATH, ...args], { | |
| cwd, | |
| encoding: "utf8", | |
| stdio: "pipe", | |
| }); | |
| return { exitCode: 0, stdout: output, stderr: "" }; | |
| } catch (error) { | |
| if (error.signal) throw new Error(`Killed by ${error.signal}`); | |
| return { | |
| exitCode: error.status ?? 1, | |
| stdout: error.stdout ?? "", | |
| stderr: error.stderr ?? "", | |
| }; | |
| } | |
| } | |
| function git(cwd, ...args) { | |
| return execFileSync("git", args, { | |
| cwd, | |
| encoding: "utf8", | |
| stdio: "pipe", | |
| // Keep the developer's own git config and repo out of the fixture: a global | |
| // commit.gpgsign or core.hooksPath would fail the commit below, and an | |
| // inherited GIT_DIR would point these commands at the wrong repository. | |
| env: { | |
| ...process.env, | |
| GIT_CONFIG_GLOBAL: "/dev/null", | |
| GIT_CONFIG_SYSTEM: "/dev/null", | |
| GIT_DIR: undefined, | |
| GIT_WORK_TREE: undefined, | |
| GIT_INDEX_FILE: undefined, | |
| }, | |
| }); | |
| } | |
| function writeMd(dir, relPath, content) { | |
| const fullPath = path.join(dir, relPath); | |
| fs.mkdirSync(path.dirname(fullPath), { recursive: true }); | |
| fs.writeFileSync(fullPath, content); | |
| return fullPath; | |
| } | |
| function makeStale(docPath) { | |
| const oldTime = new Date(Date.now() - 60 * 24 * 60 * 60 * 1000); | |
| fs.utimesSync(docPath, oldTime, oldTime); | |
| } | |
| describe("doc-gardening", () => { | |
| let tmpDir; | |
| beforeEach(() => { | |
| tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "doc-garden-test-")); | |
| }); | |
| afterEach(() => { | |
| fs.rmSync(tmpDir, { recursive: true, force: true }); | |
| }); | |
| it("never reaches for git", () => { | |
| expect(fs.readFileSync(SCRIPT_PATH, "utf8")).not.toMatch( | |
| /require\((["'])(node:)?child_process\1\)/, | |
| ); | |
| }); | |
| it("exits 0 when there are no errors", () => { | |
| writeMd(tmpDir, "docs/overview.md", "# Overview\n\n[Link](./api.md)\n"); | |
| writeMd(tmpDir, "docs/api.md", "# API\n"); | |
| expect(runGarden(tmpDir).exitCode).toBe(0); | |
| }); | |
| it("exits 1 naming the file and the target of a broken relative link", () => { | |
| writeMd( | |
| tmpDir, | |
| "docs/overview.md", | |
| "# Overview\n\n[Link](./nonexistent.md)\n", | |
| ); | |
| const { exitCode, stdout } = runGarden(tmpDir); | |
| expect(exitCode).toBe(1); | |
| expect(stdout).toContain("docs/overview.md"); | |
| expect(stdout).toContain("./nonexistent.md"); | |
| }); | |
| it("leaves the branch and the working tree untouched when it finds errors", () => { | |
| git(tmpDir, "init"); | |
| git(tmpDir, "config", "user.email", "test@example.com"); | |
| git(tmpDir, "config", "user.name", "Test"); | |
| writeMd( | |
| tmpDir, | |
| "docs/overview.md", | |
| "# Overview\n\n[Link](./nonexistent.md)\n", | |
| ); | |
| git(tmpDir, "add", "docs/overview.md"); | |
| git(tmpDir, "commit", "-m", "init"); | |
| fs.writeFileSync(path.join(tmpDir, "unrelated.txt"), "work in progress\n"); | |
| const branchBefore = git(tmpDir, "rev-parse", "--abbrev-ref", "HEAD"); | |
| const branchesBefore = git(tmpDir, "branch", "--list"); | |
| const statusBefore = git(tmpDir, "status", "--porcelain"); | |
| const { exitCode, stdout } = runGarden(tmpDir); | |
| expect(exitCode).toBe(1); | |
| expect(stdout).toContain("./nonexistent.md"); | |
| expect(git(tmpDir, "rev-parse", "--abbrev-ref", "HEAD")).toBe(branchBefore); | |
| expect(git(tmpDir, "branch", "--list")).toBe(branchesBefore); | |
| expect(git(tmpDir, "status", "--porcelain")).toBe(statusBefore); | |
| }); | |
| it("reports stale docs as warnings without failing", () => { | |
| makeStale(writeMd(tmpDir, "docs/old.md", "# Old\n")); | |
| const { exitCode, stdout } = runGarden(tmpDir); | |
| expect(exitCode).toBe(0); | |
| expect(stdout).toContain("hasn't been updated in"); | |
| }); | |
| it("still exits 1 when a warning accompanies an error", () => { | |
| makeStale(writeMd(tmpDir, "docs/old.md", "# Old\n\n[Link](./gone.md)\n")); | |
| const { exitCode, stdout } = runGarden(tmpDir); | |
| expect(exitCode).toBe(1); | |
| expect(stdout).toContain("Summary: 1 errors, 1 warnings"); | |
| }); | |
| it("ignores the anchor and the title of an otherwise valid link", () => { | |
| writeMd( | |
| tmpDir, | |
| "docs/overview.md", | |
| '# Overview\n\n[Section](./api.md#foo)\n[Titled](./api.md "The API")\n', | |
| ); | |
| writeMd(tmpDir, "docs/api.md", "# API\n"); | |
| expect(runGarden(tmpDir).exitCode).toBe(0); | |
| }); | |
| it("resolves a docs/-prefixed link the way a renderer does, against the linking file", () => { | |
| writeMd(tmpDir, "docs/overview.md", "# Overview\n\n[Link](docs/api.md)\n"); | |
| writeMd(tmpDir, "docs/api.md", "# API\n"); | |
| const { exitCode, stdout } = runGarden(tmpDir); | |
| expect(exitCode).toBe(1); | |
| expect(stdout).toContain(path.join("docs", "docs", "api.md")); | |
| }); | |
| it("accepts a root directory outside the current one", () => { | |
| writeMd( | |
| tmpDir, | |
| "docs/overview.md", | |
| "# Overview\n\n[Link](./nonexistent.md)\n", | |
| ); | |
| const { exitCode, stdout } = runGarden(__dirname, [tmpDir]); | |
| expect(exitCode).toBe(1); | |
| expect(stdout).toContain(path.join("docs", "overview.md")); | |
| expect(stdout).not.toContain(os.tmpdir()); | |
| }); | |
| it("rejects an unknown option instead of treating it as the root directory", () => { | |
| const { exitCode, stderr } = runGarden(tmpDir, ["--fix"]); | |
| expect(exitCode).toBe(1); | |
| expect(stderr).toContain("Unknown option"); | |
| }); | |
| it("rejects a root directory that does not exist", () => { | |
| const { exitCode, stderr } = runGarden(tmpDir, [ | |
| path.join(tmpDir, "missing"), | |
| ]); | |
| expect(exitCode).toBe(1); | |
| expect(stderr).toContain("Directory not found"); | |
| }); | |
| it("rejects extra arguments", () => { | |
| const { exitCode, stderr } = runGarden(tmpDir, [tmpDir, "--fix"]); | |
| expect(exitCode).toBe(1); | |
| expect(stderr).toContain("Too many arguments"); | |
| }); | |
| }); | |