use std::fs;
use std::path::{Path, PathBuf};
use super::{build_app, scratch, write_files};
fn lifecycle_app(root: &Path, marks: &Path, main_js: &str) -> PathBuf {
let events = marks.join("events");
let plugins = format!(
r#"import fs from "node:fs";
const log = (line) => fs.appendFileSync({events}, line + "\n");
export default [{{
name: "lifecycle",
buildEnd(err) {{ log("buildEnd:" + (err ? err.message.split("\n")[0] : "ok")); }},
closeBundle() {{ log("closeBundle"); }},
}}];
"#,
events = serde_json::to_string(&events.display().to_string()).unwrap(),
);
write_files(
root,
&[
("package.json", r#"{"name":"closehooks","version":"1.0.0"}"#),
("src/main.js", main_js),
(
"index.html",
r#"<!doctype html><html><head><title>t</title></head><body><script type="module" src="/src/main.js"></script></body></html>"#,
),
("oj.plugins.mjs", &plugins),
],
);
events
}
fn events(path: &Path) -> Vec<String> {
fs::read_to_string(path)
.unwrap_or_default()
.lines()
.filter(|l| !l.is_empty())
.map(str::to_string)
.collect()
}
#[tokio::test]
async fn a_failed_build_still_runs_build_end_with_the_error_and_close_bundle_once() {
let root = scratch("close-hooks-fail");
let marks = scratch("close-hooks-fail-marks");
let log = lifecycle_app(&root, &marks, "export const = ;\n");
assert!(build_app(&root).await.is_err(), "the broken build fails");
let ev = events(&log);
let build_ends: Vec<&str> = ev
.iter()
.map(String::as_str)
.filter(|e| e.starts_with("buildEnd:"))
.collect();
assert_eq!(
build_ends.len(),
1,
"buildEnd ran once after the failure:\n{}",
ev.join("\n")
);
assert!(
!build_ends[0].starts_with("buildEnd:ok"),
"buildEnd received the error:\n{}",
ev.join("\n")
);
assert_eq!(
ev.iter().filter(|e| *e == "closeBundle").count(),
1,
"closeBundle ran once after the failure:\n{}",
ev.join("\n")
);
}
#[tokio::test]
async fn a_successful_build_runs_build_end_without_error_and_close_bundle_once() {
let root = scratch("close-hooks-ok");
let marks = scratch("close-hooks-ok-marks");
let log = lifecycle_app(&root, &marks, "document.body.dataset.ok = \"1\";\n");
if let Err(err) = build_app(&root).await {
panic!("the build succeeds:\n{err:#}");
}
let ev = events(&log);
let build_ends: Vec<&str> = ev
.iter()
.map(String::as_str)
.filter(|e| e.starts_with("buildEnd:"))
.collect();
assert_eq!(
build_ends,
["buildEnd:ok"],
"buildEnd(undefined) on success:\n{}",
ev.join("\n")
);
assert_eq!(
ev.iter().filter(|e| *e == "closeBundle").count(),
1,
"closeBundle once on success:\n{}",
ev.join("\n")
);
}