Strategies for testing View
output
#2628
-
Thanks to Greg, and everyone contributing—I really love the framework. I have been creating some components that generate
Here is an example of a failing test: mod tests {
use super::*;
use leptos::create_runtime;
#[test]
fn markdown_parses_str() {
let runtime = create_runtime();
let md = r#"
# This is a title
- first point
- second point
`some code`"#;
let md_view = view! {
// The <Markdown /> component parses the markdown into a string of HTML,
// and then returns a <div> with `inner_html` set to the generated string.
<Markdown md />
}
.into_view()
.render_to_string();
let expected_view = view! {
<div>
<h1>This is a title</h1>
<ul>
<li>"first point"</li>
<li>"second point"</li>
</ul>
<p><code>"some code"</code></p>
</div>
}
.into_view()
.render_to_string();
assert_eq!(md_view, expected_view);
runtime.dispose();
}
} The test fails with the comparison (formatted by me, to make reading easier): left: "
<!--hk=0-0-0-1o|leptos-markdown-start-->
<!--leptos-view|src-components-markdown.rs-52|open-->
<div data-hk=\"0-0-0-2\">
<h1>This is a title</h1>\n
<ul>\n
<li>first point</li>\n
<li>second point</li>\n
</ul>\n
<p><code>some code</code></p>
</div>
<!--leptos-view|src-components-markdown.rs-52|close-->
<!--hk=0-0-0-1c|leptos-markdown-end-->
"
right: "
<!--leptos-view|src-components-markdown.rs-80|open-->
<div data-hk=\"0-0-0-3\">
<h1 data-hk=\"0-0-0-4\">This is a title</h1>
<ul data-hk=\"0-0-0-5\">
<li data-hk=\"0-0-0-6\">first point</li>
<li data-hk=\"0-0-0-7\">second point</li>
</ul>
<p data-hk=\"0-0-0-8\"><code data-hk=\"0-0-0-9\">some code</code></p>
</div>
<!--leptos-view|src-components-markdown.rs-80|close-->
" So I am basically happy with the output of the component, but I can't design the right test for it. Would appreciate any input on how to go about this. At the moment, it seems like a helper function stripping all HTML comments, all newlines, and all data attributes is the only way to get a meaningful comparison. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments
-
I guess the question is -- What are you actually testing here? It appears that you are testing whether the I agree that testing based on the HTML output is relatively difficult, in part because hydration keys need to be unique (so generating the same thing twice will not and should not give identical results, unless you reset the hydration keys in between) It is possible to do it using something like |
Beta Was this translation helpful? Give feedback.
-
You're right, of course. This particular test is a little contrived. I had hoped to expand the Here is what I have so far: use leptos::{component, view, IntoView};
use markdown::to_html;
use std::{
fs::File,
io::Read,
path::{Path, PathBuf},
};
use thiserror::Error;
#[derive(Debug, Error)]
pub enum MdParseError {
#[error("The markdown file {0} could not be opened")]
PathNotOpened(String),
#[error("The markdown file could not be read into the `String` buffer: {0}")]
FileReadFailure(String),
}
pub trait MdParse {
fn md_parse(self) -> Result<String, MdParseError>;
}
impl MdParse for &str {
fn md_parse(self) -> Result<String, MdParseError> {
Ok(to_html(self))
}
}
impl MdParse for String {
fn md_parse(self) -> Result<String, MdParseError> {
Ok(to_html(self.as_str()))
}
}
impl MdParse for &Path {
fn md_parse(self) -> Result<String, MdParseError> {
if let Ok(mut file) = File::open(self) {
let mut buf = String::new();
let _ = file
.read_to_string(&mut buf)
.map_err(|e| MdParseError::FileReadFailure(e.to_string()));
let html = to_html(buf.as_str());
Ok(html)
} else {
Err(MdParseError::PathNotOpened(format!("{:?}", self)))
}
}
}
#[component]
pub fn Markdown<T: MdParse>(md: T) -> impl IntoView {
if let Ok(html) = md.md_parse() {
view! { <div inner_html=html></div> }
} else {
view! { <div>"This Markdown could not be parsed"</div> }
}
} |
Beta Was this translation helpful? Give feedback.
-
I think, based on your comments, that I won't bother testing the functions that just call methods from the At the moment, I am doing this: #[cfg(test)]
mod tests {
use super::*;
use leptos::{create_runtime, Oco};
use regex::Regex;
/// Strips hydration attributes, newline characters, and HTML comments from the output of
/// View::render_to_string().
fn strip_view_attributes(s: Oco<'static, str>) -> String {
// This regex is admittedly a bit hacky, but it's only for tests.
let re = Regex::new(r#"\s+data-hk="[^"]+"\s*|\n|<!--[^!]+-->"#).unwrap();
let stripped = re.replace_all(s.as_str(), "").to_string();
stripped
}
#[test]
fn markdown_from_file() {
let runtime = create_runtime();
let md = Path::new(r"tests/markdown.md");
let md_view = Markdown(MarkdownProps { md })
.into_view()
.render_to_string();
let md_view = strip_view_attributes(md_view);
assert_eq!(
md_view,
r"<div><h1>The document title</h1><p>This is plain text.</p><ul><li>item 1</li><li>item 2</li></ul><p><code>inline code</code></p></div>"
);
runtime.dispose();
}
} If I keep the document very simple and the number of tests small, it seems like a reasonable sanity check. Definitely interested in other ideas about how to test this type of component. Thanks for your time. |
Beta Was this translation helpful? Give feedback.
I guess the question is -- What are you actually testing here? It appears that you are testing whether the
markdown
crate works properly, and testing whetherleptos
works properly, and trying to test each one of those by whether its HTML output is equal to the other one... But neither of those is necessarily in the scope of your app to control, i.e., you're just testing code you didn't write anyway.I agree that testing based on the HTML output is relatively difficult, in part because hydration keys need to be unique (so generating the same thing twice will not and should not give identical results, unless you reset the hydration keys in between)
It is possible to do it using something like