155 lines
5.0 KiB
Rust
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(())
|
|
}
|