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
15 changes: 13 additions & 2 deletions scripts/stability/compare-baseline.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ function removeNodeModulesLink(worktreePath) {
return;
}
if (stats.isSymbolicLink()) {
fs.rmdirSync(linkPath);
// symlinkSync only honours the 'junction' type on Windows. Elsewhere the
// link is a plain symlink, which rmdirSync rejects with ENOTDIR; unlinkSync
// removes the link itself and likewise never touches the target.
if (process.platform === 'win32') {
fs.rmdirSync(linkPath);
} else {
fs.unlinkSync(linkPath);
}
}
}

Expand Down Expand Up @@ -222,4 +229,8 @@ function main() {
console.log(`\nStability comparison complete: ${outputPath}`);
}

main();
if (require.main === module) {
main();
}

module.exports = { removeNodeModulesLink };
63 changes: 63 additions & 0 deletions test/compareBaseline.removeNodeModulesLink.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @jest-environment node
*
* compare-baseline links the main repo's node_modules into each stability
* worktree and must detach that link before removing the worktree, without
* ever deleting the main repo's real dependencies through it.
*
* Runs on the real filesystem: the global memfs mock has no Windows junctions,
* so it would reject the rmdir that a real junction accepts.
*/

jest.unmock('fs');
jest.unmock('fs/promises');
jest.unmock('os');

const fs = require('fs');
const os = require('os');
const path = require('path');
const { removeNodeModulesLink } = require('../scripts/stability/compare-baseline');

describe('compare-baseline removeNodeModulesLink', () => {
let root;

beforeEach(() => {
root = fs.mkdtempSync(path.join(os.tmpdir(), 'stability-link-'));
});

afterEach(() => {
fs.rmSync(root, { recursive: true, force: true });
});

test('removes the linked node_modules and leaves its target intact', () => {
const mainModules = path.join(root, 'main', 'node_modules');
fs.mkdirSync(path.join(mainModules, 'jest'), { recursive: true });
fs.writeFileSync(path.join(mainModules, 'jest', 'package.json'), '{}');
const worktree = path.join(root, 'worktree');
fs.mkdirSync(worktree);
// Same call as ensureWorktreeDependencies: a junction on Windows, a plain
// symlink elsewhere.
fs.symlinkSync(mainModules, path.join(worktree, 'node_modules'), 'junction');

removeNodeModulesLink(worktree);

expect(fs.existsSync(path.join(worktree, 'node_modules'))).toBe(false);
expect(fs.existsSync(path.join(mainModules, 'jest', 'package.json'))).toBe(true);
});

test('leaves a real node_modules directory alone', () => {
const worktree = path.join(root, 'worktree');
fs.mkdirSync(path.join(worktree, 'node_modules', 'pkg'), { recursive: true });

removeNodeModulesLink(worktree);

expect(fs.existsSync(path.join(worktree, 'node_modules', 'pkg'))).toBe(true);
});

test('does nothing when the worktree has no node_modules', () => {
const worktree = path.join(root, 'worktree');
fs.mkdirSync(worktree);

expect(() => removeNodeModulesLink(worktree)).not.toThrow();
});
});
Loading