use super::*; use crate::model::{Node, NodeKind}; use egui_kittest::{Harness, kittest::Queryable}; #[test] fn the_welcome_canvas_is_valid_and_connected() { let canvas = welcome_canvas(); assert_eq!(canvas.nodes.len(), 4); assert_eq!(canvas.edges.len(), 3); let mut copy = canvas.clone(); assert_eq!(copy.drop_dangling_edges(), 0); // And it round-trips through the file format. assert_eq!(Canvas::from_json(&canvas.to_json()).unwrap(), canvas); } // -- the whole application, driven the way a user drives it: real widgets, // found by the label on them and clicked, with no window, compositor or // pointer in the way. /// Whether a harness can draw. Only the tests that look at a frame ask /// for a renderer, so that the rest have nothing to say about the graphics /// stack of the machine they run on. enum Renderer { None, Wgpu, } /// The app on a canvas holding one note, with `text` in it. fn harness_with_a_note(text: &str, renderer: Renderer) -> Harness<'static, App> { let mut canvas = Canvas::default(); canvas.nodes.push(Node::new( "n", NodeKind::Text { text: text.to_owned(), }, 0, 0, 300, 200, )); let builder = Harness::builder().with_size(egui::vec2(1200.0, 900.0)); let builder = match renderer { Renderer::None => builder, Renderer::Wgpu => builder.wgpu(), }; let mut harness = builder.build_eframe(|cc| App::new(cc, None)); harness.state_mut().doc = Document::new(); harness.state_mut().doc.canvas = canvas; harness.run(); harness } /// The shell is real widgets too, found by the label on them. #[test] fn the_toolbar_adds_a_note_to_the_canvas() { let mut harness = harness_with_a_note("the only one", Renderer::None); assert_eq!(harness.state().doc.canvas.nodes.len(), 1); harness.get_by_label("Note").click(); harness.run(); assert_eq!(harness.state().doc.canvas.nodes.len(), 2); } /// The editor window as it is drawn: the text filling it, the ways out /// along the bottom. Run `UPDATE_SNAPSHOTS=1 cargo test` after changing it /// on purpose, and look at `tests/snapshots/*.diff.png` when it fails. #[test] fn the_editor_window_is_drawn_as_it_should_be() { let mut harness = harness_with_a_note("## A note\n\nWith text in it.", Renderer::Wgpu); harness.state_mut().view.edit_node("n"); harness.run(); harness.snapshot("editor-window"); } #[test] fn close_and_fit_sizes_the_card_and_closes_the_editor() { // More text than a 300x200 card can show. let mut harness = harness_with_a_note(&"word ".repeat(200), Renderer::None); harness.state_mut().view.edit_node("n"); harness.run(); harness.get_by_label("Close & Fit").click(); harness.run(); let app = harness.state(); assert_eq!(app.view.editing(), None, "the editor stayed open"); assert!( app.doc.canvas.node("n").unwrap().height > 200, "the card was not grown to its text" ); assert_eq!(app.doc.undo_label(), Some("Fit to text")); } /// A file node follows its file when something else writes it. #[test] fn a_card_follows_a_file_changed_outside_the_editor() -> Result<(), Box> { let dir = std::env::temp_dir().join(format!("jsoncanvas-outside-{}", crate::model::random_id())); std::fs::create_dir_all(&dir)?; let path = dir.join("note.md"); std::fs::write(&path, "before the change\n")?; let mut canvas = Canvas::default(); canvas.nodes.push(Node::new( "f", NodeKind::File { file: path.display().to_string(), subpath: None, }, 0, 0, 400, 300, )); let mut harness = Harness::builder() .with_size(egui::vec2(1200.0, 900.0)) .build_eframe(|cc| App::new(cc, None)); harness.state_mut().doc = Document::new(); harness.state_mut().doc.canvas = canvas; harness.run(); assert!(harness.query_by_label("before the change").is_some()); // Another program writes the file while the canvas is open. std::fs::write(&path, "after the change\n")?; // The check is on a timer; this is the same as waiting for it to come up. harness.state_mut().last_file_check = f64::MIN; harness.run(); assert!(harness.query_by_label("after the change").is_some()); assert!( harness.query_by_label("before the change").is_none(), "the card kept showing the text the file no longer holds" ); // With an edit made here the card keeps it, and says the file moved on. harness .state_mut() .view .files .set(&path, "edited here\n".to_owned()); std::fs::write(&path, "changed again, elsewhere\n")?; harness.state_mut().last_file_check = f64::MIN; harness.run(); assert!(harness.query_by_label("edited here").is_some()); assert!( harness.query_by_label("\u{26a0}").is_some(), "the card said nothing about the file changing under the edit" ); std::fs::remove_dir_all(&dir)?; Ok(()) }