use std::path::Path;
use std::sync::Arc;
use std::time::Duration;
use super::page_script::{open, text, widget_folder};
use crate::drive::pdf::print;
use devpage_core::document::{Document, Kind};
use devpage_core::folder::ServedFolder;
fn pages(pdf: &[u8]) -> Vec<(f64, f64)> {
let text = String::from_utf8_lossy(pdf);
text.match_indices("/MediaBox [")
.map(|(at, _)| {
let numbers: Vec<f64> = text[at + 11..]
.split(']')
.next()
.unwrap()
.split_whitespace()
.map(|n| n.parse().unwrap())
.collect();
(numbers[2] - numbers[0], numbers[3] - numbers[1])
})
.collect()
}
#[tokio::test]
#[ignore]
async fn a_design_with_problems_does_not_delay_a_pdf() {
let dir = std::env::temp_dir().join(format!("devpage-pdf-problems-{}", std::process::id()));
let _ = std::fs::remove_dir_all(&dir);
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("broken.design"), "<Frame width={400} height={300}").unwrap();
std::fs::write(dir.join("doc.md"), "# Doc\n\n\n").unwrap();
let dir = dir.canonicalize().unwrap();
let document =
Arc::new(Document::load(&dir.join("doc.md"), &ServedFolder::new(&dir).unwrap()).unwrap());
let started = std::time::Instant::now();
let pdf = print(document).await.unwrap();
assert!(
started.elapsed() < Duration::from_secs(5),
"{:?}",
started.elapsed()
);
assert!(!pages(&pdf).is_empty());
}
#[tokio::test]
#[ignore]
async fn the_fixture_doc_prints_on_a4() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let document = Arc::new(
Document::load(
&root.join("tests/fixtures/sync-design"),
&ServedFolder::new(root).unwrap(),
)
.unwrap(),
);
let pages = pages(&print(document).await.unwrap());
assert!(!pages.is_empty());
for (width, height) in pages {
assert!(
(width - 595.0).abs() < 2.0 && (height - 842.0).abs() < 2.0,
"{width} × {height}"
);
}
}
#[tokio::test]
#[ignore]
async fn the_talk_prints_one_16_by_9_page_per_slide() {
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
let document = Arc::new(
Document::load(
&root.join("docs/talks/devpage"),
&ServedFolder::new(root).unwrap(),
)
.unwrap(),
);
let Kind::Slides { slides, .. } = &document.kind else {
panic!()
};
let count = slides.len();
let pages = pages(&print(document).await.unwrap());
assert_eq!(pages.len(), count, "{pages:?}");
for (width, height) in pages {
assert!(
(width / height - 16.0 / 9.0).abs() < 0.01,
"{width} × {height}"
);
}
}
#[tokio::test]
#[ignore]
async fn a_printed_doc_shows_each_widgets_first_render() {
let dir = widget_folder(
"print",
"# W\n",
&[
(
"docs/design/devpage.yml",
"kind: doc\ntitle: D\nchapters: [one.md]\n",
),
(
"docs/design/one.md",
"# One\n\n<Tabs>\n<Tab title=\"First\">\n\nshown on paper\n\n</Tab>\n<Tab title=\"Second\">\n\nonly on screen\n\n</Tab>\n</Tabs>\n\n<Terminal>\n\n```\n$ echo a long line\n```\n\n</Terminal>\n\n```mermaid\nflowchart LR\n paper[On paper] --> web\n click paper href \"https://example.com/drawn-on-the-server\"\n```\n",
),
],
);
let (mut browser, page) = open(&dir, "/docs/design/devpage.yml?print").await;
assert_eq!(
text(&page, "document.documentElement.dataset.ready + ':' + document.querySelector('.tabs-panel').textContent.trim() + ':' + document.body.textContent.includes('only on screen')").await,
"true:shown on paper:false"
);
page.execute(
chromiumoxide::cdp::browser_protocol::emulation::SetEmulatedMediaParams::builder()
.media("print")
.build(),
)
.await
.unwrap();
assert_eq!(
text(
&page,
"getComputedStyle(document.querySelector('.terminal pre')).whiteSpace"
)
.await,
"pre-wrap"
);
assert_eq!(
text(
&page,
"String(document.querySelector('.diagram svg')?.getBoundingClientRect().width > 0)"
)
.await,
"true"
);
browser.close().await.ok();
let document = Arc::new(
Document::load(&dir.join("docs/design"), &ServedFolder::new(&dir).unwrap()).unwrap(),
);
let pdf = print(document).await.unwrap();
assert!(!pages(&pdf).is_empty());
assert!(
String::from_utf8_lossy(&pdf).contains("https://example.com/drawn-on-the-server"),
"the diagram's link in the PDF"
);
std::fs::remove_dir_all(&dir).ok();
}