update wasm-bindgen testing approaches
This commit is contained in:
parent
88ab9693db
commit
c360f0ed0d
|
@ -18,3 +18,4 @@ console_error_panic_hook = "0.1.7"
|
||||||
wasm-bindgen = "0.2"
|
wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-test = "0.3.0"
|
wasm-bindgen-test = "0.3.0"
|
||||||
web-sys = "0.3"
|
web-sys = "0.3"
|
||||||
|
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
use counter::*;
|
use counter::*;
|
||||||
use leptos::*;
|
use gloo_timers::future::TimeoutFuture;
|
||||||
|
use leptos::mount::mount_to;
|
||||||
|
use leptos::prelude::*;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn clear() {
|
async fn clear() {
|
||||||
let document = leptos::document();
|
let document = document();
|
||||||
let test_wrapper = document.create_element("section").unwrap();
|
let test_wrapper = document.create_element("section").unwrap();
|
||||||
let _ = document.body().unwrap().append_child(&test_wrapper);
|
let _ = document.body().unwrap().append_child(&test_wrapper);
|
||||||
|
|
||||||
// start by rendering our counter and mounting it to the DOM
|
// start by rendering our counter and mounting it to the DOM
|
||||||
// note that we start at the initial value of 10
|
// note that we start at the initial value of 10
|
||||||
mount_to(
|
let _dispose = mount_to(
|
||||||
test_wrapper.clone().unchecked_into(),
|
test_wrapper.clone().unchecked_into(),
|
||||||
|| view! { <SimpleCounter initial_value=10 step=1/> },
|
|| view! { <SimpleCounter initial_value=10 step=1/> },
|
||||||
);
|
);
|
||||||
|
@ -30,59 +32,63 @@ fn clear() {
|
||||||
// now let's click the `clear` button
|
// now let's click the `clear` button
|
||||||
clear.click();
|
clear.click();
|
||||||
|
|
||||||
|
// the reactive system is built on top of the async system, so changes are not reflected
|
||||||
|
// synchronously in the DOM
|
||||||
|
// in order to detect the changes here, we'll just yield for a brief time after each change,
|
||||||
|
// allowing the effects that update the view to run
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
// now let's test the <div> against the expected value
|
// now let's test the <div> against the expected value
|
||||||
// we can do this by testing its `outerHTML`
|
// we can do this by testing its `outerHTML`
|
||||||
let runtime = create_runtime();
|
assert_eq!(div.outer_html(), {
|
||||||
assert_eq!(
|
// it's as if we're creating it with a value of 0, right?
|
||||||
div.outer_html(),
|
let (value, _set_value) = signal(0);
|
||||||
// here we spawn a mini reactive system, just to render the
|
|
||||||
// test case
|
|
||||||
{
|
|
||||||
// it's as if we're creating it with a value of 0, right?
|
|
||||||
let (value, _set_value) = create_signal(0);
|
|
||||||
|
|
||||||
// we can remove the event listeners because they're not rendered to HTML
|
// we can remove the event listeners because they're not rendered to HTML
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div>
|
||||||
<button>"Clear"</button>
|
<button>"Clear"</button>
|
||||||
<button>"-1"</button>
|
<button>"-1"</button>
|
||||||
<span>"Value: " {value} "!"</span>
|
<span>"Value: " {value} "!"</span>
|
||||||
<button>"+1"</button>
|
<button>"+1"</button>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
// the view returned an HtmlElement<Div>, which is a smart pointer for
|
|
||||||
// a DOM element. So we can still just call .outer_html()
|
|
||||||
.outer_html()
|
|
||||||
}
|
}
|
||||||
);
|
// Leptos supports multiple backend renderers for HTML elements
|
||||||
|
// .into_view() here is just a convenient way of specifying "use the regular DOM renderer"
|
||||||
|
.into_view()
|
||||||
|
// views are lazy -- they describe a DOM tree but don't create it yet
|
||||||
|
// calling .build() will actually build the DOM elements
|
||||||
|
.build()
|
||||||
|
// .build() returned an ElementState, which is a smart pointer for
|
||||||
|
// a DOM element. So we can still just call .outer_html(), which access the outerHTML on
|
||||||
|
// the actual DOM element
|
||||||
|
.outer_html()
|
||||||
|
});
|
||||||
|
|
||||||
// There's actually an easier way to do this...
|
// There's actually an easier way to do this...
|
||||||
// We can just test against a <SimpleCounter/> with the initial value 0
|
// We can just test against a <SimpleCounter/> with the initial value 0
|
||||||
assert_eq!(test_wrapper.inner_html(), {
|
assert_eq!(test_wrapper.inner_html(), {
|
||||||
let comparison_wrapper = document.create_element("section").unwrap();
|
let comparison_wrapper = document.create_element("section").unwrap();
|
||||||
leptos::mount_to(
|
let _dispose = mount_to(
|
||||||
comparison_wrapper.clone().unchecked_into(),
|
comparison_wrapper.clone().unchecked_into(),
|
||||||
|| view! { <SimpleCounter initial_value=0 step=1/>},
|
|| view! { <SimpleCounter initial_value=0 step=1/>},
|
||||||
);
|
);
|
||||||
comparison_wrapper.inner_html()
|
comparison_wrapper.inner_html()
|
||||||
});
|
});
|
||||||
|
|
||||||
runtime.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn inc() {
|
async fn inc() {
|
||||||
let document = leptos::document();
|
let document = document();
|
||||||
let test_wrapper = document.create_element("section").unwrap();
|
let test_wrapper = document.create_element("section").unwrap();
|
||||||
let _ = document.body().unwrap().append_child(&test_wrapper);
|
let _ = document.body().unwrap().append_child(&test_wrapper);
|
||||||
|
|
||||||
mount_to(
|
let _dispose = mount_to(
|
||||||
test_wrapper.clone().unchecked_into(),
|
test_wrapper.clone().unchecked_into(),
|
||||||
|| view! { <SimpleCounter initial_value=0 step=1/> },
|
|| view! { <SimpleCounter initial_value=0 step=1/> },
|
||||||
);
|
);
|
||||||
|
|
||||||
// You can do testing with vanilla DOM operations
|
// You can do testing with vanilla DOM operations
|
||||||
let _document = leptos::document();
|
|
||||||
let div = test_wrapper.query_selector("div").unwrap().unwrap();
|
let div = test_wrapper.query_selector("div").unwrap().unwrap();
|
||||||
let clear = div
|
let clear = div
|
||||||
.first_child()
|
.first_child()
|
||||||
|
@ -108,6 +114,8 @@ fn inc() {
|
||||||
inc.click();
|
inc.click();
|
||||||
inc.click();
|
inc.click();
|
||||||
|
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(text.text_content(), Some("Value: 2!".to_string()));
|
assert_eq!(text.text_content(), Some("Value: 2!".to_string()));
|
||||||
|
|
||||||
dec.click();
|
dec.click();
|
||||||
|
@ -115,19 +123,21 @@ fn inc() {
|
||||||
dec.click();
|
dec.click();
|
||||||
dec.click();
|
dec.click();
|
||||||
|
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(text.text_content(), Some("Value: -2!".to_string()));
|
assert_eq!(text.text_content(), Some("Value: -2!".to_string()));
|
||||||
|
|
||||||
clear.click();
|
clear.click();
|
||||||
|
|
||||||
assert_eq!(text.text_content(), Some("Value: 0!".to_string()));
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
let runtime = create_runtime();
|
assert_eq!(text.text_content(), Some("Value: 0!".to_string()));
|
||||||
|
|
||||||
// Or you can test against a sample view!
|
// Or you can test against a sample view!
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
div.outer_html(),
|
div.outer_html(),
|
||||||
{
|
{
|
||||||
let (value, _) = create_signal(0);
|
let (value, _) = signal(0);
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div>
|
||||||
<button>"Clear"</button>
|
<button>"Clear"</button>
|
||||||
|
@ -137,16 +147,20 @@ fn inc() {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.into_view()
|
||||||
|
.build()
|
||||||
.outer_html()
|
.outer_html()
|
||||||
);
|
);
|
||||||
|
|
||||||
inc.click();
|
inc.click();
|
||||||
|
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
div.outer_html(),
|
div.outer_html(),
|
||||||
{
|
{
|
||||||
// because we've clicked, it's as if the signal is starting at 1
|
// because we've clicked, it's as if the signal is starting at 1
|
||||||
let (value, _) = create_signal(1);
|
let (value, _) = signal(1);
|
||||||
view! {
|
view! {
|
||||||
<div>
|
<div>
|
||||||
<button>"Clear"</button>
|
<button>"Clear"</button>
|
||||||
|
@ -156,8 +170,8 @@ fn inc() {
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.into_view()
|
||||||
|
.build()
|
||||||
.outer_html()
|
.outer_html()
|
||||||
);
|
);
|
||||||
|
|
||||||
runtime.dispose();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,6 @@ lto = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
leptos = { path = "../../leptos" }
|
leptos = { path = "../../leptos" }
|
||||||
console_log = "1"
|
|
||||||
log = "0.4"
|
|
||||||
console_error_panic_hook = "0.1.7"
|
console_error_panic_hook = "0.1.7"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
@ -19,6 +17,7 @@ wasm-bindgen = "0.2"
|
||||||
wasm-bindgen-test = "0.3.34"
|
wasm-bindgen-test = "0.3.34"
|
||||||
pretty_assertions = "1.3.0"
|
pretty_assertions = "1.3.0"
|
||||||
rstest = "0.17.0"
|
rstest = "0.17.0"
|
||||||
|
gloo-timers = { version = "0.3", features = ["futures"] }
|
||||||
|
|
||||||
[dev-dependencies.web-sys]
|
[dev-dependencies.web-sys]
|
||||||
features = ["HtmlElement", "XPathResult"]
|
features = ["HtmlElement", "XPathResult"]
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use counter_without_macros::counter;
|
use counter_without_macros::counter;
|
||||||
use leptos::*;
|
|
||||||
|
|
||||||
/// Show the counter
|
/// Show the counter
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
_ = console_log::init_with_level(log::Level::Debug);
|
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
mount::mount_to_body(|| counter(0, 1))
|
leptos::mount::mount_to_body(|| counter(0, 1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use counter_without_macros::counter;
|
use counter_without_macros::counter;
|
||||||
use leptos::*;
|
use gloo_timers::future::TimeoutFuture;
|
||||||
|
use leptos::prelude::*;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen_test::*;
|
use wasm_bindgen_test::*;
|
||||||
|
@ -8,27 +9,32 @@ use web_sys::HtmlElement;
|
||||||
wasm_bindgen_test_configure!(run_in_browser);
|
wasm_bindgen_test_configure!(run_in_browser);
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn should_increment_counter() {
|
async fn should_increment_counter() {
|
||||||
open_counter();
|
open_counter();
|
||||||
|
|
||||||
click_increment();
|
click_increment();
|
||||||
click_increment();
|
click_increment();
|
||||||
|
|
||||||
|
// reactive changes run asynchronously, so yield briefly before observing the DOM
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(see_text(), Some("Value: 2!".to_string()));
|
assert_eq!(see_text(), Some("Value: 2!".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn should_decrement_counter() {
|
async fn should_decrement_counter() {
|
||||||
open_counter();
|
open_counter();
|
||||||
|
|
||||||
click_decrement();
|
click_decrement();
|
||||||
click_decrement();
|
click_decrement();
|
||||||
|
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(see_text(), Some("Value: -2!".to_string()));
|
assert_eq!(see_text(), Some("Value: -2!".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen_test]
|
#[wasm_bindgen_test]
|
||||||
fn should_clear_counter() {
|
async fn should_clear_counter() {
|
||||||
open_counter();
|
open_counter();
|
||||||
|
|
||||||
click_increment();
|
click_increment();
|
||||||
|
@ -36,18 +42,18 @@ fn should_clear_counter() {
|
||||||
|
|
||||||
click_clear();
|
click_clear();
|
||||||
|
|
||||||
|
TimeoutFuture::new(10).await;
|
||||||
|
|
||||||
assert_eq!(see_text(), Some("Value: 0!".to_string()));
|
assert_eq!(see_text(), Some("Value: 0!".to_string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn open_counter() {
|
fn open_counter() {
|
||||||
remove_existing_counter();
|
remove_existing_counter();
|
||||||
mount_to_body(move || counter(0, 1));
|
leptos::mount::mount_to_body(move || counter(0, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_existing_counter() {
|
fn remove_existing_counter() {
|
||||||
if let Some(counter) =
|
if let Some(counter) = document().query_selector("body div").unwrap() {
|
||||||
leptos::document().query_selector("body div").unwrap()
|
|
||||||
{
|
|
||||||
counter.remove();
|
counter.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,7 +80,7 @@ fn see_text() -> Option<String> {
|
||||||
|
|
||||||
fn find_by_text(text: &str) -> HtmlElement {
|
fn find_by_text(text: &str) -> HtmlElement {
|
||||||
let xpath = format!("//*[text()='{}']", text);
|
let xpath = format!("//*[text()='{}']", text);
|
||||||
let document = leptos::document();
|
let document = document();
|
||||||
document
|
document
|
||||||
.evaluate(&xpath, &document)
|
.evaluate(&xpath, &document)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
|
@ -12,7 +12,7 @@ use const_str_slice_concat::{
|
||||||
const_concat, const_concat_with_prefix, str_from_buffer,
|
const_concat, const_concat_with_prefix, str_from_buffer,
|
||||||
};
|
};
|
||||||
use next_tuple::NextTuple;
|
use next_tuple::NextTuple;
|
||||||
use std::marker::PhantomData;
|
use std::{marker::PhantomData, ops::Deref};
|
||||||
|
|
||||||
mod custom;
|
mod custom;
|
||||||
mod elements;
|
mod elements;
|
||||||
|
@ -413,6 +413,14 @@ pub struct ElementState<At, Ch, R: Renderer> {
|
||||||
rndr: PhantomData<R>,
|
rndr: PhantomData<R>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<At, Ch, R: Renderer> Deref for ElementState<At, Ch, R> {
|
||||||
|
type Target = R::Element;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.el
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<At, Ch, R> Mountable<R> for ElementState<At, Ch, R>
|
impl<At, Ch, R> Mountable<R> for ElementState<At, Ch, R>
|
||||||
where
|
where
|
||||||
R: Renderer,
|
R: Renderer,
|
||||||
|
|
Loading…
Reference in New Issue