diff --git a/crates/socket-patch-cli/tests/e2e_redirect_npm_build.rs b/crates/socket-patch-cli/tests/e2e_redirect_npm_build.rs index 9529ae9f5..7a44c658d 100644 --- a/crates/socket-patch-cli/tests/e2e_redirect_npm_build.rs +++ b/crates/socket-patch-cli/tests/e2e_redirect_npm_build.rs @@ -1357,10 +1357,12 @@ async fn npm_agent_recovers_crlf_bin_left_by_raw_write() { /// Regression (#1804): npm rewrites the shebang only of bins it links. /// With `--no-bin-links`, or for a `directories.bin`-only package -/// installed from a `file:` tarball (npm doesn't expand that field from a -/// tarball's `package.json`), the installed bin keeps its CRLF shebang. +/// installed from a `file:` tarball (npm 10 doesn't expand that field from +/// a tarball's `package.json`), the installed bin keeps its CRLF shebang. /// `apply` writes the patch's recorded bytes, `apply --check` agrees, and -/// `rollback` restores what `npm install` wrote, byte for byte. +/// `rollback` restores what `npm install` wrote, byte for byte. npm 11 +/// does link the `directories.bin` file and rewrites its shebang; there +/// the same steps must round-trip npm's bytes instead. #[cfg(unix)] #[tokio::test(flavor = "multi_thread")] #[ignore = "wall-bound real-npm install; runs on the e2e CI matrix leg"] @@ -1370,25 +1372,40 @@ async fn npm_agent_keeps_crlf_shebang_of_bin_npm_did_not_link() { npm_e2e_common::skip(SUITE, "npm not on PATH"); return; } - for (manifest, rel, flags) in [ + // The link name npm would create: the `bin` key for a `bin` map, the + // file name for a `directories.bin` entry. + for (manifest, rel, link_name, flags) in [ ( r#"{"name":"crlfbin","version":"1.0.0","bin":{"crlfbin":"cli.js"}}"#, "cli.js", + "crlfbin", &["--no-bin-links"][..], ), ( r#"{"name":"crlfbin","version":"1.0.0","directories":{"bin":"bin"}}"#, "bin/cli.js", + "cli.js", &[][..], ), ] { let tmp = tempfile::tempdir().unwrap(); let proj = crlf_bin_project_with(tmp.path(), manifest, rel, flags); let cli = proj.join("node_modules/crlfbin").join(rel); + let link = proj.join("node_modules/.bin").join(link_name); + let linked = link.symlink_metadata().is_ok(); + assert!( + !(linked && flags.contains(&"--no-bin-links")), + "{rel}: npm linked a bin under --no-bin-links" + ); + let (before, after) = if linked { + (NPM_BIN_BEFORE, NPM_BIN_AFTER) + } else { + (CRLF_BIN_BEFORE, CRLF_BIN_AFTER) + }; assert_eq!( std::fs::read(&cli).unwrap(), - CRLF_BIN_BEFORE, - "{rel}: npm left the shebang alone" + before, + "{rel}: npm rewrites the shebang only if it linked the bin (linked: {linked})" ); let (code, stdout, stderr) = run_socket(&proj, &["apply", "--offline"]); @@ -1396,7 +1413,7 @@ async fn npm_agent_keeps_crlf_shebang_of_bin_npm_did_not_link() { code, 0, "{rel}: apply\nstdout:\n{stdout}\nstderr:\n{stderr}" ); - assert_eq!(std::fs::read(&cli).unwrap(), CRLF_BIN_AFTER, "{rel}: apply"); + assert_eq!(std::fs::read(&cli).unwrap(), after, "{rel}: apply"); let (code, stdout, stderr) = run_socket(&proj, &["apply", "--check", "--offline"]); assert_eq!( @@ -1411,7 +1428,7 @@ async fn npm_agent_keeps_crlf_shebang_of_bin_npm_did_not_link() { ); assert_eq!( std::fs::read(&cli).unwrap(), - CRLF_BIN_BEFORE, + before, "{rel}: rollback is byte-exact" ); }