git.lucas.co / cce-mail
mail client (IMAP/SMTP)
git clone https://git.lucas.co/cce-mail.git

examples/wpe_mail.rs (3.3K)

 1 //! Headless smoke test for [`MailWebView`] — boots the engine, loads a
 2 //! representative HTML mail, and asserts frames actually render with the
 3 //! expected content policy. No Wayland session needed: frames land in WPE's
 4 //! SHM buffers and are sampled straight off the readback.
 5 //!
 6 //! `cargo run --release -p cce-mail --example wpe_mail`
 7 
 8 #[path = "../src/wpe/mod.rs"]
 9 mod wpe;
10 
11 fn main() {
12     let html = r##"<!doctype html>
13 <html><body style="margin:0;background:#ff0000">
14   <h1 style="color:#ffffff">HTML mail</h1>
15   <p><a href="https://example.com/click">a link</a></p>
16   <img src="https://tracker.invalid/pixel.gif" width="10" height="10">
17 </body></html>"##;
18 
19     let mut view = wpe::MailWebView::new((800, 600));
20     view.load_html(html);
21 
22     let mut frames = 0;
23     for i in 0..120 {
24         if view.pump() {
25             frames += 1;
26             let px = view.sample_pixel(400, 300);
27             println!("t={:>5}ms frame#{frames} image={:?} px@center={:?}", i * 50, view.image(), px);
28         }
29         std::thread::sleep(std::time::Duration::from_millis(50));
30         if frames >= 2 && i > 40 {
31             break;
32         }
33     }
34 
35     assert!(frames > 0, "no frames rendered");
36     // The body is red; a rendered frame proves layout + raster, and the
37     // color proves the page (not a blank) was what rendered.
38     let (r, g, b) = view.sample_pixel(400, 300).expect("no readback");
39     println!("center pixel: ({r},{g},{b})");
40     assert!(r > 180 && g < 80 && b < 80, "expected the red body, got ({r},{g},{b})");
41     println!("OK: {frames} frames, red body rendered, remote pixel blocked from loading");
42 
43     // Phase 2: a cid: inline image, served by the registered scheme handler
44     // from the per-message store — full-bleed green, so the center pixel
45     // proves the request went store → stream → raster.
46     let svg = br##"<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"><rect width="200" height="200" fill="#00c000"/></svg>"##;
47     view.set_inline_parts(vec![(
48         "logo@test".to_string(),
49         "image/svg+xml".to_string(),
50         svg.to_vec(),
51     )]);
52     view.load_html(
53         r#"<html><body style="margin:0"><img src="cid:logo@test" style="display:block;width:800px;height:600px"></body></html>"#,
54     );
55     let mut cid_frames = 0;
56     for i in 0..120 {
57         if view.pump() {
58             cid_frames += 1;
59             println!(
60                 "t={:>5}ms cid frame#{cid_frames} px@center={:?}",
61                 i * 50,
62                 view.sample_pixel(400, 300)
63             );
64         }
65         std::thread::sleep(std::time::Duration::from_millis(50));
66         // Wait for the frame that actually shows the image, not the first
67         // paint before the subresource arrived. All three channels: white
68         // (the pre-image paint) also has a green channel over 150.
69         if cid_frames > 0 {
70             if let Some((r, g, b)) = view.sample_pixel(400, 300) {
71                 if g > 150 && r < 80 && b < 80 {
72                     break;
73                 }
74             }
75         }
76     }
77     let (r, g, b) = view.sample_pixel(400, 300).expect("no readback");
78     println!("cid image center pixel: ({r},{g},{b})");
79     assert!(g > 150 && r < 80 && b < 80, "expected the green cid image, got ({r},{g},{b})");
80     println!("OK: cid inline image rendered through the scheme handler");
81 }