Files
jsoncanvas-desktop/src/app/tests.rs
T
2026-09-11 08:43:33 +02:00

155 lines
5.0 KiB
Rust

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<dyn std::error::Error>> {
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(())
}