22 * Integration tests for global install / symlink invocation
33 * Verifies the built binary works when invoked through a symlink,
44 * as happens with `npm install -g` or `npm link`.
5+ *
6+ * npm creates a symlink from the global bin directory to the package's
7+ * dist/index.js. Node resolves the symlink, so process.argv[1] is the
8+ * symlink path while import.meta.url resolves to the real file. The
9+ * entry guard in index.ts must handle this via realpathSync.
510 */
611
712import { test , describe , beforeEach , afterEach } from 'node:test' ;
@@ -20,7 +25,7 @@ describe('Global Install (symlink) Integration Tests', () => {
2025 beforeEach ( ( ) => {
2126 tempBinDir = join ( tmpdir ( ) , `c8ctl-global-test-${ Date . now ( ) } ` ) ;
2227 mkdirSync ( tempBinDir , { recursive : true } ) ;
23- symlinkPath = join ( tempBinDir , 'c8ctl' ) ;
28+ symlinkPath = join ( tempBinDir , 'c8ctl.js ' ) ;
2429 } ) ;
2530
2631 afterEach ( ( ) => {
@@ -47,10 +52,12 @@ describe('Global Install (symlink) Integration Tests', () => {
4752 assert . ok ( result . stdout . includes ( 'Usage:' ) , 'help output should contain Usage' ) ;
4853 } ) ;
4954
50- test ( 'binary works when invoked through a symlink (simulates npm link / npm install -g)' , ( ) => {
55+ test ( 'binary works when node receives a symlink as argv[1] (simulates npm link / npm install -g)' , ( ) => {
5156 symlinkSync ( distEntry , symlinkPath ) ;
5257
53- const result = spawnSync ( symlinkPath , [ 'help' ] , {
58+ // Use `node <symlink>` — this is how npm global installs work:
59+ // the shebang causes node to be invoked with the symlink path as argv[1]
60+ const result = spawnSync ( 'node' , [ symlinkPath , 'help' ] , {
5461 encoding : 'utf-8' ,
5562 timeout : 10_000 ,
5663 } ) ;
@@ -63,7 +70,7 @@ describe('Global Install (symlink) Integration Tests', () => {
6370 test ( 'binary shows version when invoked through a symlink' , ( ) => {
6471 symlinkSync ( distEntry , symlinkPath ) ;
6572
66- const result = spawnSync ( symlinkPath , [ 'help' ] , {
73+ const result = spawnSync ( 'node' , [ symlinkPath , 'help' ] , {
6774 encoding : 'utf-8' ,
6875 timeout : 10_000 ,
6976 } ) ;
@@ -73,18 +80,18 @@ describe('Global Install (symlink) Integration Tests', () => {
7380 assert . match ( result . stdout , / v \d + \. \d + \. \d + / , 'output should contain a version string' ) ;
7481 } ) ;
7582
76- test ( 'binary works through a double symlink (symlink → symlink → dist/index.js)' , ( ) => {
77- // Simulates npm global bin → node_modules symlink → project dist
83+ test ( 'binary works through a double symlink (symlink -> symlink -> dist/index.js)' , ( ) => {
84+ // Simulates npm global bin -> node_modules symlink -> project dist
7885 const intermediateDir = join ( tempBinDir , 'node_modules' ) ;
7986 mkdirSync ( intermediateDir , { recursive : true } ) ;
8087 const intermediatePath = join ( intermediateDir , 'index.js' ) ;
8188
82- // First symlink: intermediate → real file
89+ // First symlink: intermediate -> real file
8390 symlinkSync ( distEntry , intermediatePath ) ;
84- // Second symlink: bin entry → intermediate
91+ // Second symlink: bin entry -> intermediate
8592 symlinkSync ( intermediatePath , symlinkPath ) ;
8693
87- const result = spawnSync ( symlinkPath , [ 'help' ] , {
94+ const result = spawnSync ( 'node' , [ symlinkPath , 'help' ] , {
8895 encoding : 'utf-8' ,
8996 timeout : 10_000 ,
9097 } ) ;
0 commit comments