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