paperclip/scripts/link-plugin-dev-sdk.test.js

90 lines
3.3 KiB
JavaScript

import assert from "node:assert/strict";
import { existsSync, lstatSync, mkdirSync, mkdtempSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { after, before, test } from "node:test";
import { linkSdkInto, readPluginsUnder } from "./link-plugin-dev-sdk.mjs";
let workDir;
before(() => {
workDir = mkdtempSync(join(tmpdir(), "link-plugin-dev-sdk-"));
});
after(() => {
rmSync(workDir, { force: true, recursive: true });
});
function makePackage(dir) {
mkdirSync(dir, { recursive: true });
writeFileSync(join(dir, "package.json"), "{}\n");
return dir;
}
test("readPluginsUnder returns [] for a missing directory", () => {
assert.deepEqual(readPluginsUnder(join(workDir, "does-not-exist")), []);
});
test("readPluginsUnder finds first-level package directories", () => {
const parent = join(workDir, "first-level");
const a = makePackage(join(parent, "a"));
const b = makePackage(join(parent, "b"));
assert.deepEqual(readPluginsUnder(parent).sort(), [a, b].sort());
});
test("readPluginsUnder recurses into directories that are not themselves packages", () => {
// Mirrors the recursive pnpm-workspace exclusion glob: a provider nested
// deeper than one level must still be discovered.
const parent = join(workDir, "nested");
const nested = makePackage(join(parent, "vendor", "my-plugin"));
assert.deepEqual(readPluginsUnder(parent), [nested]);
});
test("readPluginsUnder stops descending once a package.json is found and skips node_modules", () => {
const parent = join(workDir, "boundaries");
const pkg = makePackage(join(parent, "plugin"));
// A nested package inside an already-matched package must not be returned.
makePackage(join(pkg, "sub-package"));
// node_modules must be ignored entirely.
makePackage(join(parent, "node_modules", "some-dep"));
assert.deepEqual(readPluginsUnder(parent), [pkg]);
});
test("linkSdkInto creates the plugin-sdk symlink and is idempotent", () => {
const pkg = makePackage(join(workDir, "link-target"));
assert.equal(linkSdkInto(pkg), true);
const link = join(pkg, "node_modules", "@paperclipai", "plugin-sdk");
assert.ok(lstatSync(link).isSymbolicLink());
// Second call is a no-op because the link already points at the in-repo SDK.
assert.equal(linkSdkInto(pkg), false);
});
test("linkSdkInto leaves a real (non-symlink) install in place", () => {
const pkg = makePackage(join(workDir, "real-install"));
const scopeDir = join(pkg, "node_modules", "@paperclipai");
mkdirSync(scopeDir, { recursive: true });
// Simulate a published-tarball install: a real directory, not a symlink.
makePackage(join(scopeDir, "plugin-sdk"));
assert.equal(linkSdkInto(pkg), false);
assert.ok(!lstatSync(join(scopeDir, "plugin-sdk")).isSymbolicLink());
});
test("linkSdkInto replaces a symlink that points somewhere else", () => {
const pkg = makePackage(join(workDir, "stale-link"));
const scopeDir = join(pkg, "node_modules", "@paperclipai");
mkdirSync(scopeDir, { recursive: true });
symlinkSync("../somewhere-else", join(scopeDir, "plugin-sdk"), "dir");
assert.equal(linkSdkInto(pkg), true);
assert.notEqual(readlinkSync(join(scopeDir, "plugin-sdk")), "../somewhere-else");
assert.ok(existsSync(scopeDir));
});