use std::path::Path;
#[path = "common/mod.rs"]
mod common;
use common::{
assert_run_ok, envelope_error_code, envelope_error_message, json_string,
parse_json_envelope, run, write_minimal_manifest, PatchEntry,
};
fn make_yarn_berry_project(cwd: &Path) {
std::fs::write(
cwd.join("package.json"),
r#"{"name":"yarn-berry-fixture","version":"0.0.0","private":true}"#,
)
.expect("write package.json");
std::fs::write(cwd.join(".pnp.cjs"), b"// stub PnP loader\n")
.expect("write .pnp.cjs");
std::fs::create_dir_all(cwd.join(".yarn").join("cache"))
.expect("create .yarn/cache");
}
fn write_synthetic_manifest(socket_dir: &Path) {
write_minimal_manifest(
socket_dir,
"pkg:npm/dummy@1.0.0",
"11111111-1111-4111-8111-111111111111",
&[PatchEntry {
file_name: "package/index.js",
before_hash: "a".repeat(64).as_str(),
after_hash: "b".repeat(64).as_str(),
}],
);
}
#[test]
fn yarn_pnp_refuses_with_error_code() {
let dir = tempfile::tempdir().unwrap();
make_yarn_berry_project(dir.path());
write_synthetic_manifest(&dir.path().join(".socket"));
let (code, stdout, stderr) = run(dir.path(), &["apply", "--json"]);
assert_eq!(
code, 1,
"expected exit 1.\nstdout:\n{stdout}\nstderr:\n{stderr}"
);
let env = parse_json_envelope(&stdout);
assert_eq!(
envelope_error_code(&env),
Some("yarn_pnp_unsupported"),
"expected error.code=yarn_pnp_unsupported.\nenvelope: {env}"
);
assert_eq!(
json_string(&env, "status"),
Some("error"),
"expected status=error.\nenvelope: {env}"
);
let error_msg = envelope_error_message(&env).unwrap_or("");
assert!(
error_msg.contains("yarn patch"),
"error message should point at `yarn patch`, got: {error_msg}"
);
}
#[test]
fn yarn_pnp_refuses_in_human_mode() {
let dir = tempfile::tempdir().unwrap();
make_yarn_berry_project(dir.path());
write_synthetic_manifest(&dir.path().join(".socket"));
let (code, _stdout, stderr) = run(dir.path(), &["apply"]);
assert_eq!(code, 1);
assert!(
stderr.contains("yarn patch"),
"stderr should point at `yarn patch`, got:\n{stderr}"
);
}
#[test]
fn npm_layout_does_not_trigger_yarn_pnp_refusal() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name":"npm-fixture","version":"0.0.0","private":true}"#,
)
.unwrap();
std::fs::create_dir_all(dir.path().join("node_modules")).unwrap();
write_synthetic_manifest(&dir.path().join(".socket"));
let (_code, stdout, _stderr) = run(dir.path(), &["apply", "--json"]);
assert!(
!stdout.contains("yarn_pnp_unsupported"),
"npm layout should not trigger yarn-pnp refusal.\nstdout:\n{stdout}"
);
}
#[test]
fn yarn_pnp_loader_mjs_also_refuses() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name":"yarn-berry-esm","version":"0.0.0","private":true}"#,
)
.unwrap();
std::fs::write(
dir.path().join(".pnp.loader.mjs"),
b"// stub PnP ESM loader\n",
)
.unwrap();
write_synthetic_manifest(&dir.path().join(".socket"));
let (code, stdout, _stderr) = run(dir.path(), &["apply", "--json"]);
assert_eq!(code, 1);
let env = parse_json_envelope(&stdout);
assert_eq!(
envelope_error_code(&env),
Some("yarn_pnp_unsupported")
);
}
#[test]
fn synthetic_manifest_is_discovered_by_cli() {
let dir = tempfile::tempdir().unwrap();
std::fs::write(
dir.path().join("package.json"),
r#"{"name":"plain","version":"0.0.0","private":true}"#,
)
.unwrap();
write_synthetic_manifest(&dir.path().join(".socket"));
let (stdout, _stderr) = assert_run_ok(dir.path(), &["list", "--json"], "list --json");
assert!(
stdout.contains("pkg:npm/dummy@1.0.0"),
"list should surface our synthetic manifest entry, got:\n{stdout}"
);
}