use std::fs;
use regex::Regex;
use super::{build_app, scratch, write_files};
const NESTED: &str = ".a {\n color: red;\n .b { color: blue }\n}\n";
const LIGHTNING_SRC: &str =
".kept { color: red }\n.gone { color: blue }\n.c:hover { color: green }\n";
const LIGHTNING: &str =
r#"css: { lightningcss: { unusedSymbols: ["gone"], pseudoClasses: { hover: "is-hover" } } }"#;
async fn build_css(name: &str, config: &str, source: &str) -> String {
let root = scratch(name);
write_files(
&root,
&[
("package.json", r#"{"name":"css-options","type":"module"}"#),
("oj.config.ts", config),
(
"index.html",
r#"<!doctype html><html><head></head><body><script type="module" src="/src/main.js"></script></body></html>"#,
),
("src/main.js", "import \"./app.css\";\n"),
("src/app.css", source),
],
);
build_app(&root)
.await
.unwrap_or_else(|e| panic!("{name} builds: {e:#}"));
let assets = root.join("dist/assets");
let css: Vec<String> = fs::read_dir(&assets)
.expect("dist/assets exists")
.flatten()
.map(|e| e.file_name().to_string_lossy().into_owned())
.filter(|f| f.ends_with(".css"))
.collect();
assert_eq!(css.len(), 1, "expected one stylesheet, got {css:?}");
fs::read_to_string(assets.join(&css[0])).unwrap()
}
#[tokio::test]
async fn default_css_is_minified_and_nesting_lowered() {
let css = build_css("css-opt-default", "export default {};\n", NESTED).await;
assert!(
!Regex::new(r"\n\s+color").unwrap().is_match(&css) && css.contains(".a{color:red}"),
"default: minified: {css:?}"
);
assert!(
Regex::new(r"\.a \.b\s*\{").unwrap().is_match(&css),
"default: nesting lowered for the baseline target: {css:?}"
);
}
#[tokio::test]
async fn build_minify_false_leaves_css_unminified() {
let css = build_css(
"css-opt-nominify",
"export default { build: { minify: false } };\n",
NESTED,
)
.await;
assert!(
css.trim().contains('\n') && css.contains("color: red"),
"build.minify false leaves CSS unminified: {css:?}"
);
}
#[tokio::test]
async fn css_minify_true_minifies_with_build_minify_false() {
let css = build_css(
"css-opt-cssminify-on",
"export default { build: { minify: false, cssMinify: true } };\n",
NESTED,
)
.await;
assert!(
css.contains(".a{color:red}"),
"cssMinify true minifies even with build.minify false: {css:?}"
);
}
#[tokio::test]
async fn css_minify_false_keeps_css_readable_with_minify_on() {
let css = build_css(
"css-opt-cssminify-off",
"export default { build: { cssMinify: false } };\n",
NESTED,
)
.await;
assert!(
css.contains("color: red"),
"cssMinify false keeps CSS readable with build.minify on: {css:?}"
);
}
#[tokio::test]
async fn css_target_with_nesting_support_keeps_nesting() {
let css = build_css(
"css-opt-csstarget",
"export default { build: { cssTarget: [\"chrome120\", \"safari17.2\", \"firefox117\"] } };\n",
NESTED,
)
.await;
assert!(
!css.contains(".a .b") && css.contains(".b{"),
"cssTarget with nesting support keeps nesting: {css:?}"
);
}
#[tokio::test]
async fn css_target_defaults_to_build_target() {
let css = build_css(
"css-opt-target",
"export default { build: { target: [\"chrome120\", \"safari17.2\", \"firefox117\"] } };\n",
NESTED,
)
.await;
assert!(
!css.contains(".a .b"),
"cssTarget defaults to build.target: {css:?}"
);
}
#[tokio::test]
async fn css_lightningcss_applies_to_the_build_minify() {
let css = build_css(
"css-opt-lightning",
&format!("export default {{ {LIGHTNING} }};\n"),
LIGHTNING_SRC,
)
.await;
assert!(
css.contains(".kept{") && !css.contains(".gone") && css.contains(".c.is-hover{"),
"css.lightningcss applies to the build minify: {css:?}"
);
}
#[tokio::test]
async fn css_lightningcss_stays_out_of_an_unminified_build() {
let css = build_css(
"css-opt-lightning-nominify",
&format!("export default {{ build: {{ minify: false }}, {LIGHTNING} }};\n"),
LIGHTNING_SRC,
)
.await;
assert!(
css.contains(".gone") && css.contains(":hover"),
"css.lightningcss stays out of an unminified build: {css:?}"
);
}