Files
ai-coding-skills/scripts/tests/safe-replace-dir.test.mjs
T
stefano 251148c3ff
check / check (ubuntu-latest) (push) Successful in 2m5s
check / check (macos-latest) (push) Has been cancelled
check-online / check-online (ubuntu-latest) (push) Successful in 1m53s
Perform code optimization and document cleanup (#1)
## Summary
- add repository-wide quality tooling and verification scaffolding, including CI workflows, pnpm workspace setup, ESLint/Prettier/markdown checks, and generated-output verification helpers
- reorganize skill sources and generation flow by introducing canonical `_source` variants, generator/manifests, reusable helper abstractions, and shared web-automation/browser utilities
- clean up and expand documentation so the root README flows into docs and skill docs, with clearer development, reviewer, installer, and workflow guidance

## Notable changes
- docs flow and consistency cleanup across `README.md`, `docs/README.md`, and related docs
- new scripts for `check`, docs verification, generated-file verification, shell portability, and safe directory replacement
- refactors in Atlassian and web-automation skill runtimes to reduce duplication and centralize reusable code
- changelog, development documentation, and CI surface updates

## Test Plan
- [ ] `pnpm run check`
- [ ] review generated/manifests and skill sync outputs
- [ ] smoke-check docs flow from `README.md` to `docs/README.md` to skill docs

## Notes
- this branch currently includes tracked `skills/web-automation/shared/node_modules` content that should be reviewed carefully as potentially noisy/accidental committed artifacts

Co-authored-by: Stefano Fiorini <stefano.fiorini@firsthorizon.com>
Reviewed-on: #1
2026-05-04 04:41:34 +00:00

140 lines
4.9 KiB
JavaScript

import assert from "node:assert/strict";
import { mkdtemp, mkdir, writeFile, readFile, readdir, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";
import test from "node:test";
import { safeReplaceDir } from "../lib/safe-replace-dir.mjs";
// ── Happy path ────────────────────────────────────────────────────────────
test("safeReplaceDir copies source content into the target", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-copy-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
const target = path.join(safetyRoot, "target");
await mkdir(source, { recursive: true });
await writeFile(path.join(source, "file.txt"), "hello");
await mkdir(safetyRoot, { recursive: true });
await safeReplaceDir(source, target, safetyRoot);
const content = await readFile(path.join(target, "file.txt"), "utf8");
assert.equal(content, "hello");
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test("safeReplaceDir removes existing content before replacing", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-stale-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
const target = path.join(safetyRoot, "target");
await mkdir(target, { recursive: true });
await writeFile(path.join(target, "old.txt"), "stale");
await mkdir(source, { recursive: true });
await writeFile(path.join(source, "new.txt"), "fresh");
await safeReplaceDir(source, target, safetyRoot);
const files = await readdir(target);
assert.deepEqual(files.sort(), ["new.txt"]);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test("safeReplaceDir creates target parent directories if they do not exist", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-mkdir-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
const target = path.join(safetyRoot, "nested", "target");
await mkdir(source, { recursive: true });
await writeFile(path.join(source, "data.txt"), "data");
await mkdir(safetyRoot, { recursive: true });
// nested parent does NOT exist yet
await safeReplaceDir(source, target, safetyRoot);
const content = await readFile(path.join(target, "data.txt"), "utf8");
assert.equal(content, "data");
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test("safeReplaceDir creates deeply nested parent directories (2+ levels missing)", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-deep-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
// two parent levels (a/b) do NOT exist under safetyRoot
const target = path.join(safetyRoot, "a", "b", "target");
await mkdir(source, { recursive: true });
await writeFile(path.join(source, "deep.txt"), "deep");
await mkdir(safetyRoot, { recursive: true });
// a/ and a/b/ intentionally NOT created
await safeReplaceDir(source, target, safetyRoot);
const content = await readFile(path.join(target, "deep.txt"), "utf8");
assert.equal(content, "deep");
} finally {
await rm(dir, { recursive: true, force: true });
}
});
// ── Safety checks ─────────────────────────────────────────────────────────
test("safeReplaceDir refuses when target is outside the safety root", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-outside-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
const outside = path.join(dir, "outside");
await mkdir(source, { recursive: true });
await mkdir(safetyRoot, { recursive: true });
await assert.rejects(
() => safeReplaceDir(source, outside, safetyRoot),
/outside safety root/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test("safeReplaceDir refuses when target equals the safety root", async () => {
const dir = await mkdtemp(path.join(tmpdir(), "safe-replace-same-"));
try {
const safetyRoot = path.join(dir, "root");
const source = path.join(dir, "source");
await mkdir(source, { recursive: true });
await mkdir(safetyRoot, { recursive: true });
await assert.rejects(
() => safeReplaceDir(source, safetyRoot, safetyRoot),
/outside safety root/,
);
} finally {
await rm(dir, { recursive: true, force: true });
}
});
test("safeReplaceDir refuses an empty target string", async () => {
await assert.rejects(
() => safeReplaceDir("/any", "", "/root"),
/unsafe target/,
);
});