use rustc_hash::FxHashSet;
use crate::{EnforceExtension, Resolution, ResolveContext, ResolveError, ResolveOptions, Resolver};
#[tokio::test]
async fn extensions() {
let f = super::fixture().join("extensions");
let resolver = Resolver::new(ResolveOptions {
extensions: vec![".ts".into(), ".js".into()],
..ResolveOptions::default()
});
#[rustfmt::skip]
let pass = [
("should resolve according to order of provided extensions", "./foo", "foo.ts"),
("should resolve according to order of provided extensions (dir index)", "./dir", "dir/index.ts"),
("should resolve according to main field in module root", ".", "index.js"),
("should resolve trailing slash directory before single file", "module/", "node_modules/module/index.ts"),
];
for (comment, request, expected_path) in pass {
let resolved_path = resolver.resolve(&f, request).await.map(|r| r.full_path());
let expected = f.join(expected_path);
assert_eq!(
resolved_path,
Ok(expected),
"{comment} {request} {expected_path}"
);
}
#[rustfmt::skip]
let fail = [
("not resolve to file when request has a trailing slash (relative)", "./foo.js/", "./foo.js/".into())
];
for (comment, request, expected_error) in fail {
let resolution = resolver.resolve(&f, request).await;
let error = ResolveError::NotFound(expected_error);
assert_eq!(resolution, Err(error), "{comment} {request} {resolution:?}");
}
}
#[tokio::test]
async fn default_enforce_extension() {
let f = super::fixture().join("extensions");
let mut ctx = ResolveContext::default();
let resolved = Resolver::new(ResolveOptions {
extensions: vec![".ts".into(), String::new(), ".js".into()],
..ResolveOptions::default()
})
.resolve_with_context(&f, "./foo", &mut ctx)
.await;
assert_eq!(
resolved.map(Resolution::into_path_buf),
Ok(f.join("foo.ts"))
);
assert_eq!(
ctx.file_dependencies,
FxHashSet::from_iter([f.join("foo.ts"), f.join("package.json")])
);
assert!(ctx.missing_dependencies.is_empty());
}
#[tokio::test]
async fn respect_enforce_extension() {
let f = super::fixture().join("extensions");
let mut ctx = ResolveContext::default();
let resolved = Resolver::new(ResolveOptions {
enforce_extension: EnforceExtension::Disabled,
extensions: vec![".ts".into(), String::new(), ".js".into()],
..ResolveOptions::default()
})
.resolve_with_context(&f, "./foo", &mut ctx)
.await;
assert_eq!(
resolved.map(Resolution::into_path_buf),
Ok(f.join("foo.ts"))
);
assert_eq!(
ctx.file_dependencies,
FxHashSet::from_iter([f.join("foo.ts"), f.join("package.json")])
);
assert_eq!(
ctx.missing_dependencies,
FxHashSet::from_iter([f.join("foo")])
);
}
#[tokio::test]
async fn multi_dot_extension() {
let f = super::fixture().join("extensions");
let resolver = Resolver::new(ResolveOptions {
extensions: vec![".a.b.c".into(), ".d.ts".into(), ".ts".into(), ".js".into()],
..ResolveOptions::default()
});
#[rustfmt::skip]
let pass = [
("should resolve according to order of provided extensions", "./foo", "foo.ts"),
("should resolve file with extension", "./app.module", "app.module.js")
];
for (comment, request, expected_path) in pass {
let resolved_path = resolver.resolve(&f, request).await.map(|r| r.full_path());
let expected = f.join(expected_path);
assert_eq!(
resolved_path,
Ok(expected),
"{comment} {request} {expected_path}"
);
}
#[rustfmt::skip]
let fail = [
("not resolve to file", "./index.", "./index.".into())
];
for (comment, request, expected_error) in fail {
let resolution = resolver.resolve(&f, request).await;
let error = ResolveError::NotFound(expected_error);
assert_eq!(resolution, Err(error), "{comment} {request} {resolution:?}");
}
}
#[test]
#[should_panic = "All extensions must start with a leading dot"]
fn without_leading_dot() {
Resolver::new(ResolveOptions {
extensions: vec!["ts".into(), "js".into()],
..ResolveOptions::default()
});
}