Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nervous-donkeys-hammer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fixture-kit/core": patch
---

Keep relative symlinks inside the copy in `Fixture.fromDirectory`. `fs.cp` rewrites relative symlink targets to absolute paths unless `verbatimSymlinks` is set, so a link in the source directory pointed back at the source after the copy.
24 changes: 24 additions & 0 deletions src/fixture.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Fixture } from "./fixture.js";
import path from "node:path";
import { fileURLToPath } from "node:url";
import fs from "node:fs/promises";
import os from "node:os";

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const testFixture = (name: string) => path.join(__dirname, "..", "fixtures", name);
Expand Down Expand Up @@ -34,6 +35,29 @@ describe("Fixture", () => {
await fs.readFile(path.join(testFixture("basic"), "src/index.ts"), "utf-8"),
);
});

// Windows needs an elevated process to create symlinks, so this runs on POSIX only.
it.skipIf(process.platform === "win32")(
"should keep a relative symlink pointing inside the copy",
async () => {
const source = await fs.mkdtemp(path.join(os.tmpdir(), "fixture-kit-source-"));

try {
await fs.writeFile(path.join(source, "target.txt"), "original");
await fs.symlink("target.txt", path.join(source, "link.txt"));

await using fixture = await Fixture.fromDirectory(source);
await fs.writeFile(path.join(fixture.root, "link.txt"), "written through the link");

expect(await fs.readFile(path.join(fixture.root, "target.txt"), "utf-8")).toBe(
"written through the link",
);
expect(await fs.readFile(path.join(source, "target.txt"), "utf-8")).toBe("original");
} finally {
await fs.rm(source, { recursive: true, force: true });
}
},
);
});

describe("create", () => {
Expand Down
2 changes: 1 addition & 1 deletion src/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export class Fixture implements AsyncDisposable {
throw new Error(`source must be a directory: ${sourcePath}`);
}

await fs.cp(sourcePath, fixture.root, { recursive: true });
await fs.cp(sourcePath, fixture.root, { recursive: true, verbatimSymlinks: true });

return fixture;
} catch (error) {
Expand Down
Loading