This is unreleased documentation for Yew Next version.
For up-to-date documentation, see the latest version on docs.rs.

yew/tests/
layout_tests.rs

1//! Snapshot testing of Yew components
2//!
3//! This tests must be run in browser and thus require the `csr` feature to be enabled
4use gloo::console::log;
5
6use crate::dom_bundle::{BSubtree, Bundle, DomSlot};
7use crate::html::AnyScope;
8use crate::virtual_dom::VNode;
9use crate::{scheduler, Component, Context, Html};
10
11#[allow(dead_code)]
12struct Comp;
13impl Component for Comp {
14    type Message = ();
15    type Properties = ();
16
17    fn create(_: &Context<Self>) -> Self {
18        unimplemented!()
19    }
20
21    fn update(&mut self, _ctx: &Context<Self>, _: Self::Message) -> bool {
22        unimplemented!();
23    }
24
25    fn changed(&mut self, _ctx: &Context<Self>, _: &Self::Properties) -> bool {
26        unimplemented!()
27    }
28
29    fn view(&self, _ctx: &Context<Self>) -> Html {
30        unimplemented!()
31    }
32}
33
34#[derive(Debug)]
35#[allow(missing_docs)]
36pub struct TestLayout<'a> {
37    pub name: &'a str,
38    pub node: VNode,
39    pub expected: &'a str,
40}
41
42#[allow(missing_docs)]
43pub fn diff_layouts(layouts: Vec<TestLayout<'_>>) {
44    let document = gloo::utils::document();
45    let scope: AnyScope = AnyScope::test();
46    let parent_element = document.create_element("div").unwrap();
47    let root = BSubtree::create_root(&parent_element);
48
49    let end_node = document.create_text_node("END");
50    parent_element.append_child(&end_node).unwrap();
51
52    // Tests each layout independently
53    let slot = DomSlot::at(end_node.into());
54    for layout in layouts.iter() {
55        // Apply the layout
56        let vnode = layout.node.clone();
57        log!("Independently apply layout '{}'", layout.name);
58
59        let mut bundle = Bundle::new();
60        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), vnode);
61        scheduler::start_now();
62        assert_eq!(
63            parent_element.inner_html(),
64            format!("{}END", layout.expected),
65            "Independent apply failed for layout '{}'",
66            layout.name,
67        );
68
69        // Diff with no changes
70        let vnode = layout.node.clone();
71
72        log!("Independently reapply layout '{}'", layout.name);
73
74        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), vnode);
75        scheduler::start_now();
76        assert_eq!(
77            parent_element.inner_html(),
78            format!("{}END", layout.expected),
79            "Independent reapply failed for layout '{}'",
80            layout.name,
81        );
82
83        // Detach
84        bundle.detach(&root, &parent_element, false);
85        scheduler::start_now();
86        assert_eq!(
87            parent_element.inner_html(),
88            "END",
89            "Independent detach failed for layout '{}'",
90            layout.name,
91        );
92    }
93
94    // Sequentially apply each layout
95    let mut bundle = Bundle::new();
96    for layout in layouts.iter() {
97        let next_vnode = layout.node.clone();
98
99        log!("Sequentially apply layout '{}'", layout.name);
100        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), next_vnode);
101
102        scheduler::start_now();
103        assert_eq!(
104            parent_element.inner_html(),
105            format!("{}END", layout.expected),
106            "Sequential apply failed for layout '{}'",
107            layout.name,
108        );
109    }
110
111    // Sequentially detach each layout
112    for layout in layouts.into_iter().rev() {
113        let next_vnode = layout.node.clone();
114
115        log!("Sequentially detach layout '{}'", layout.name);
116        bundle.reconcile(&root, &scope, &parent_element, slot.clone(), next_vnode);
117
118        scheduler::start_now();
119        assert_eq!(
120            parent_element.inner_html(),
121            format!("{}END", layout.expected),
122            "Sequential detach failed for layout '{}'",
123            layout.name,
124        );
125    }
126
127    // Detach last layout
128    bundle.detach(&root, &parent_element, false);
129    scheduler::start_now();
130    assert_eq!(
131        parent_element.inner_html(),
132        "END",
133        "Failed to detach last layout"
134    );
135}