use std::path::Path;
use serde::Deserialize;
use crate::{Manifest, Resolution};
#[derive(Deserialize)]
struct Test {
it: String,
imported: String,
importer: String,
expected: String,
}
#[derive(Deserialize)]
struct TestSuite {
manifest: Manifest,
tests: Vec<Test>,
}
#[cfg(test)]
mod tests {
use std::{env, fs, path::PathBuf};
use super::*;
use crate::{
ResolutionConfig, ResolutionHost, init_pnp_manifest, load_pnp_manifest,
parse_bare_identifier, resolve_to_unqualified, resolve_to_unqualified_via_manifest, util,
};
#[test]
fn example() {
let manifest = load_pnp_manifest(Path::new("data/pnp-yarn-v3.cjs")).unwrap();
let host =
ResolutionHost { find_pnp_manifest: Box::new(move |_| Ok(Some(manifest.clone()))) };
let config = ResolutionConfig { host };
let resolution =
resolve_to_unqualified("lodash/cloneDeep", Path::new("/path/to/file"), &config);
match resolution {
Ok(Resolution::Resolved(_path, _subpath)) => {
}
Ok(Resolution::Skipped) => {
}
Err(_err) => {
}
};
}
#[test]
fn test_load_pnp_manifest() {
load_pnp_manifest(Path::new("data/pnp-yarn-v3.cjs"))
.expect("Assertion failed: Expected to load the .pnp.cjs file generated by Yarn 3");
load_pnp_manifest(Path::new("data/pnp-yarn-v4.cjs"))
.expect("Assertion failed: Expected to load the .pnp.cjs file generated by Yarn 4");
}
#[test]
fn test_resolve_unqualified() {
let expectations_path = std::env::current_dir()
.expect("Assertion failed: Expected a valid current working directory")
.join("data/test-expectations.json");
let manifest_content = fs::read_to_string(&expectations_path)
.expect("Assertion failed: Expected the expectations to be found");
let mut test_suites: Vec<TestSuite> = serde_json::from_str(&manifest_content)
.expect("Assertion failed: Expected the expectations to be loaded");
for test_suite in test_suites.iter_mut() {
let manifest = &mut test_suite.manifest;
init_pnp_manifest(manifest, Path::new("/path/to/project/.pnp.cjs"));
for test in test_suite.tests.iter() {
let specifier = &test.imported;
let parent = &PathBuf::from(&test.importer).join("fooo");
let manifest_copy = manifest.clone();
let host = ResolutionHost {
find_pnp_manifest: Box::new(move |_| Ok(Some(manifest_copy.clone()))),
};
let config = ResolutionConfig { host };
let resolution = resolve_to_unqualified(specifier, parent, &config);
match resolution {
Ok(Resolution::Resolved(path, _subpath)) => {
assert_eq!(path.to_string_lossy(), test.expected, "{}", test.it);
}
Ok(Resolution::Skipped) => {
assert_eq!(specifier, &test.expected, "{}", test.it);
}
Err(err) => {
assert_eq!(test.expected, "error!", "{}: {err}", test.it);
}
}
}
}
}
#[test]
fn test_edge_case_one_pkg_cached_and_unplugged() {
let manifest = {
let manifest_json_path =
std::env::current_dir().unwrap().join("./data/edge_case_manifest_state.json");
let manifest_content = fs::read_to_string(&manifest_json_path).unwrap();
let mut manifest = serde_json::from_str::<Manifest>(&manifest_content).unwrap();
init_pnp_manifest(&mut manifest, &manifest_json_path);
manifest
};
let issuer = std::env::current_dir().unwrap().
join("data/.yarn/unplugged/@carbon-icons-react-virtual-379302d360/node_modules/@carbon/icons-react/es/");
let resolution =
resolve_to_unqualified_via_manifest(&manifest, "@carbon/icon-helpers", &issuer)
.unwrap();
match resolution {
Resolution::Resolved(resolved, _) => {
assert!(resolved.ends_with(".yarn/unplugged/@carbon-icon-helpers-npm-10.54.0-a58f8b7b6c/node_modules/@carbon/icon-helpers"))
}
_ => {
panic!("Unexpected resolve failed");
}
}
}
#[test]
fn test_parse_single_package_name() {
let parsed = parse_bare_identifier("pkg");
assert_eq!(parsed, Ok(("pkg".to_string(), None)));
}
#[test]
fn test_parse_scoped_package_name() {
let parsed = parse_bare_identifier("@scope/pkg");
assert_eq!(parsed, Ok(("@scope/pkg".to_string(), None)));
}
#[test]
fn test_parse_package_name_with_long_subpath() {
let parsed = parse_bare_identifier("pkg/a/b/c/index.js");
assert_eq!(parsed, Ok(("pkg".to_string(), Some("a/b/c/index.js".to_string()))));
}
#[test]
fn test_parse_scoped_package_with_long_subpath() {
let parsed = parse_bare_identifier("@scope/pkg/a/b/c/index.js");
assert_eq!(parsed, Ok(("@scope/pkg".to_string(), Some("a/b/c/index.js".to_string()))));
}
#[test]
fn test_global_cache() {
let manifest = load_pnp_manifest(
env::current_dir()
.unwrap()
.join("fixtures")
.join("global-cache")
.join(".pnp.cjs")
.as_path(),
)
.unwrap();
let home_dir = dirs_next::home_dir().unwrap();
#[cfg(windows)]
let global_cache = home_dir.join("AppData\\Local\\Yarn\\Berry\\cache");
#[cfg(not(windows))]
let global_cache = home_dir.join(".yarn/berry/cache");
let result = resolve_to_unqualified_via_manifest(
&manifest,
"source-map",
global_cache
.join("source-map-support-npm-0.5.21-09ca99e250-10c0.zip")
.join("node_modules")
.join("source-map-support")
.join("")
.as_path(),
);
match result {
Ok(Resolution::Resolved(path, subpath)) => {
assert_eq!(
path.to_string_lossy(),
util::normalize_path(
global_cache
.join("source-map-npm-0.6.1-1a3621db16-10c0.zip")
.join("node_modules")
.join("source-map")
.join("")
.to_string_lossy()
)
);
assert_eq!(subpath, None);
}
_ => {
panic!("Unexpected resolve failed");
}
}
}
#[test]
fn test_preserve_package_registry_data_order() {
let base_path = std::env::current_dir().unwrap().join("data");
let manifest =
load_pnp_manifest(base_path.join("pnp-yarn-v4-registry-data-order.cjs").as_path())
.unwrap();
let result = resolve_to_unqualified_via_manifest(
&manifest,
"inner-package",
base_path.join(".yarn/unplugged/lib-virtual-35bde7b160/node_modules/lib").as_path(),
);
match result {
Ok(Resolution::Resolved(path, subpath)) => {
assert_eq!(
path.to_string_lossy(),
util::normalize_path(
base_path
.join("path")
.join("to")
.join("inner-package")
.join("")
.to_string_lossy()
)
);
assert_eq!(subpath, None);
}
_ => {
panic!("Unexpected resolve failed");
}
}
}
}