use std::fs;
use serde_json::Value;
use super::{build_app, scratch, write_files};
#[tokio::test]
async fn manifest_lists_non_entry_chunks_and_references_them_by_key() {
let root = scratch("manifest-chunks");
write_files(
&root,
&[
(
"package.json",
r#"{"name":"m","private":true,"dependencies":{"mylib":"1.0.0"}}"#,
),
(
"node_modules/mylib/package.json",
r#"{"name":"mylib","version":"1.0.0","type":"module","main":"index.js"}"#,
),
(
"node_modules/mylib/index.js",
"export const hello = 'hi from mylib';\nexport function greet(name) { return hello + ' ' + name.toUpperCase(); }\nexport const data = Array.from({ length: 64 }, (_, i) => ({ i, sq: i * i }));\n",
),
(
"index.html",
r#"<!doctype html><html><head></head><body><script type="module" src="/src/main.tsx"></script></body></html>"#,
),
(
"src/main.tsx",
"import { greet, data } from \"mylib\";\nwindow.__h = greet(\"world\") + data.length;\n",
),
(
"oj.config.mjs",
"export default { build: { manifest: true, rollupOptions: { output: { manualChunks: { vendor: [\"mylib\"] } } } } };\n",
),
],
);
build_app(&root).await.expect("the manifest app builds");
let raw = fs::read_to_string(root.join("dist/.vite/manifest.json")).expect("manifest written");
let manifest: Value = serde_json::from_str(&raw).expect("manifest is JSON");
let m = manifest.as_object().expect("manifest is an object");
let keys: Vec<&String> = m.keys().collect();
let entry = m
.get("src/main.tsx")
.unwrap_or_else(|| panic!("entry keyed by its source path: {keys:?}"));
assert_eq!(entry["isEntry"], true, "entry row is isEntry:\n{raw}");
let vendor_re = regex::Regex::new(r"^_vendor-.*\.js$").unwrap();
let vendor_key = keys
.iter()
.find(|k| vendor_re.is_match(k))
.unwrap_or_else(|| panic!("non-entry vendor chunk keyed _<file>: {keys:?}"));
let vendor = &m[vendor_key.as_str()];
assert!(
vendor.get("src").is_none(),
"non-entry chunk has no src:\n{raw}"
);
assert!(
vendor.get("isEntry").is_none() || vendor["isEntry"] == false,
"non-entry chunk is not isEntry:\n{raw}"
);
let imports: Vec<&str> = entry["imports"]
.as_array()
.map(|a| a.iter().filter_map(Value::as_str).collect())
.unwrap_or_default();
assert!(
imports.contains(&vendor_key.as_str()),
"entry.imports references the vendor KEY {vendor_key}, not a file name: {imports:?}"
);
for (key, row) in m {
for field in ["imports", "dynamicImports"] {
for r in row[field].as_array().into_iter().flatten() {
let r = r.as_str().expect("references are strings");
assert!(
m.contains_key(r),
"{key}.{field} references missing manifest key {r}:\n{raw}"
);
}
}
}
}