use std::fs;
use std::path::{Path, PathBuf};
use docgen_build::{build_site, BuildMode, BuildOptions};
fn copy_tree(src: &Path, dst: &Path) {
fs::create_dir_all(dst).unwrap();
for entry in fs::read_dir(src).unwrap() {
let entry = entry.unwrap();
let from = entry.path();
let to = dst.join(entry.file_name());
if from.is_dir() {
copy_tree(&from, &to);
} else {
fs::copy(&from, &to).unwrap();
}
}
}
#[test]
fn checked_in_fixture_exercises_directives() {
let manifest = PathBuf::from(env!("CARGO_MANIFEST_DIR")); let workspace = manifest.parent().unwrap().parent().unwrap(); let fixture = workspace.join("fixtures/site-basic");
let root = tempfile::tempdir().unwrap();
copy_tree(&fixture.join("docs"), &root.path().join("docs"));
copy_tree(&fixture.join("components"), &root.path().join("components"));
let out = tempfile::tempdir().unwrap();
build_site(&BuildOptions {
project_root: root.path(),
out_dir: out.path(),
mode: BuildMode::Production,
})
.unwrap();
let page = fs::read_to_string(out.path().join("directives/index.html")).unwrap();
assert!(page.contains("docgen-callout--warning"));
assert!(page.contains("Back up first"));
assert!(page.contains("docgen-callout--note"));
assert!(page.contains("wikilink"));
assert!(page.contains("docgen-note"));
assert!(page.contains("a project component"));
assert!(page.contains("docgen-directive-error"));
assert!(page.contains("unknown directive"));
assert!(page.contains(r#"href="/components.css""#));
let css = fs::read_to_string(out.path().join("components.css")).unwrap();
assert!(css.contains("docgen-callout"));
assert!(css.contains("docgen-note"));
assert!(!out.path().join("components.js").exists());
}
#[test]
fn build_renders_builtin_callout_and_project_component() {
let root = tempfile::tempdir().unwrap();
fs::create_dir_all(root.path().join("docs")).unwrap();
fs::write(
root.path().join("docs/index.md"),
"# Home\n\n:::callout{type=warning title=\"Heads up\"}\nBe **careful**.\n:::\n\n:note[hi]{}\n",
)
.unwrap();
let nd = root.path().join("components/note");
fs::create_dir_all(&nd).unwrap();
fs::write(
nd.join("template.html"),
"<span class=\"note\">{{ label }}</span>",
)
.unwrap();
fs::write(nd.join("style.css"), ".note{color:teal}").unwrap();
let out = tempfile::tempdir().unwrap();
build_site(&BuildOptions {
project_root: root.path(),
out_dir: out.path(),
mode: BuildMode::Production,
})
.unwrap();
let home = fs::read_to_string(out.path().join("index.html")).unwrap();
assert!(home.contains("docgen-callout--warning")); assert!(home.contains("Heads up"));
assert!(home.contains("<strong>careful</strong>")); assert!(home.contains("class=\"note\">hi")); assert!(home.contains(r#"href="/components.css""#));
assert!(!out.path().join("components.js").exists());
let css = fs::read_to_string(out.path().join("components.css")).unwrap();
assert!(css.contains("docgen-callout")); assert!(css.contains(".note")); }
#[test]
fn project_component_overrides_builtin_callout_in_build() {
let root = tempfile::tempdir().unwrap();
fs::create_dir_all(root.path().join("docs")).unwrap();
fs::write(
root.path().join("docs/index.md"),
"# Home\n\n:::callout{}\nx\n:::\n",
)
.unwrap();
let cd = root.path().join("components/callout");
fs::create_dir_all(&cd).unwrap();
fs::write(
cd.join("template.html"),
"<div class=\"my-callout\">{{ content | safe }}</div>",
)
.unwrap();
let out = tempfile::tempdir().unwrap();
build_site(&BuildOptions {
project_root: root.path(),
out_dir: out.path(),
mode: BuildMode::Production,
})
.unwrap();
let home = fs::read_to_string(out.path().join("index.html")).unwrap();
assert!(home.contains("my-callout"));
assert!(!home.contains("docgen-callout--note")); }
#[test]
fn island_component_emits_components_js_only_on_pages_that_use_it() {
let root = tempfile::tempdir().unwrap();
fs::create_dir_all(root.path().join("docs")).unwrap();
fs::write(
root.path().join("docs/index.md"),
"# Home\n\n:::rating{id=p max=5}\n:::\n",
)
.unwrap();
fs::write(root.path().join("docs/plain.md"), "# Plain\nno directive\n").unwrap();
let rd = root.path().join("components/rating");
fs::create_dir_all(&rd).unwrap();
fs::write(
rd.join("template.html"),
"<div x-data=\"docgenRating()\" data-id=\"{{ attrs.id }}\"></div>",
)
.unwrap();
fs::write(rd.join("island.js"), "Alpine.data('docgenRating',()=>({}))").unwrap();
let out = tempfile::tempdir().unwrap();
build_site(&BuildOptions {
project_root: root.path(),
out_dir: out.path(),
mode: BuildMode::Production,
})
.unwrap();
assert!(out.path().join("components.js").is_file());
let home = fs::read_to_string(out.path().join("index.html")).unwrap();
let plain = fs::read_to_string(out.path().join("plain/index.html")).unwrap();
assert!(home.contains(r#"src="/components.js""#));
assert!(!plain.contains(r#"src="/components.js""#)); }
fn build_files(files: &[(&str, &str)]) -> tempfile::TempDir {
let root = tempfile::tempdir().unwrap();
for (rel, content) in files {
let p = root.path().join(rel);
fs::create_dir_all(p.parent().unwrap()).unwrap();
fs::write(p, content).unwrap();
}
let out = tempfile::tempdir().unwrap();
build_site(&BuildOptions {
project_root: root.path(),
out_dir: out.path(),
mode: BuildMode::Production,
})
.unwrap();
out
}
#[test]
fn include_directive_transcludes_partial_and_excludes_it_as_page() {
let out = build_files(&[
(
"docs/guide/index.md",
"# Guide\n\n:include{src=\"./_facts.gen.md\"}\n",
),
("docs/guide/_facts.gen.md", "## Facts\n\n- alpha\n- beta\n"),
]);
let host = fs::read_to_string(out.path().join("guide/index/index.html")).unwrap();
assert!(host.contains("Facts"), "partial heading missing: {host}");
assert!(host.contains("alpha"), "partial list missing");
assert!(
!out.path().join("guide/_facts.gen/index.html").exists(),
"partial leaked as a page"
);
}
#[test]
fn include_missing_src_degrades_to_error_span() {
let out = build_files(&[("docs/index.md", "# Home\n\n:include{src=\"./_nope.md\"}\n")]);
let html = fs::read_to_string(out.path().join("index/index.html")).unwrap();
assert!(
html.contains("docgen-directive-error"),
"expected inert error span: {html}"
);
}