mdbook/tests/testsuite/rendering.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

420 lines
14 KiB
Rust
Raw Normal View History

//! Tests for HTML rendering.
//!
//! Note that markdown-specific rendering tests are in the `markdown` module.
use crate::prelude::*;
// Checks that edit-url-template works.
#[test]
fn edit_url_template() {
BookTest::from_dir("rendering/edit_url_template").check_file_contains(
"book/index.html",
"<a href=\"https://github.com/rust-lang/mdBook/edit/master/guide/src/README.md\" \
title=\"Suggest an edit\" aria-label=\"Suggest an edit\" rel=\"edit\">",
);
}
// Checks that an alternate `src` setting works with the edit url template.
#[test]
fn edit_url_template_explicit_src() {
BookTest::from_dir("rendering/edit_url_template_explicit_src").check_file_contains(
"book/index.html",
"<a href=\"https://github.com/rust-lang/mdBook/edit/master/guide/src2/README.md\" \
title=\"Suggest an edit\" aria-label=\"Suggest an edit\" rel=\"edit\">",
);
}
// Checks that index.html is generated correctly, even when the first few
// chapters are drafts.
#[test]
fn first_chapter_is_copied_as_index_even_if_not_first_elem() {
BookTest::from_dir("rendering/first_chapter_is_copied_as_index_even_if_not_first_elem")
// These two files should be equal.
.check_main_file(
"book/chapter_1.html",
str![[
r##"<h1 id="chapter-1"><a class="header" href="#chapter-1">Chapter 1</a></h1>"##
]],
)
.check_main_file(
"book/index.html",
str![[
r##"<h1 id="chapter-1"><a class="header" href="#chapter-1">Chapter 1</a></h1>"##
]],
);
}
// Fontawesome `<i>` tag support.
#[test]
fn fontawesome() {
BookTest::from_dir("rendering/fontawesome")
.run("build", |cmd| {
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
WARN failed to find Font Awesome icon for icon `does-not-exist` with type `regular` in `fa.md`: Invalid Font Awesome icon name: visit https://fontawesome.com/icons?d=gallery&m=free to see valid names
INFO HTML book written to `[ROOT]/book`
"#]]);
})
.check_all_main_files();
}
// Verifies that an invalid `git-repository-icon` in book.toml produces a
// helpful error message with the icon name, type, and a link to FontAwesome.
#[test]
fn fontawesome_error_message() {
BookTest::from_dir("rendering/fontawesome_error")
.run("build", |cmd| {
cmd.expect_failure();
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
ERROR Rendering failed
[TAB]Caused by: Error rendering "index" line [..], col [..]: Unknown Font Awesome icon `github` for type `regular`. Hint: check the icon name and prefix (fas (solid), fab (brands), or far (regular)) at https://fontawesome.com/v6/search?m=free
[TAB]Caused by: Unknown Font Awesome icon `github` for type `regular`. Hint: check the icon name and prefix (fas (solid), fab (brands), or far (regular)) at https://fontawesome.com/v6/search?m=free
"#]]);
});
}
// Tests the rendering when setting the default rust edition.
#[test]
fn default_rust_edition() {
BookTest::from_dir("rendering/default_rust_edition").check_all_main_files();
}
// Tests the rendering for editable code blocks.
#[test]
fn editable_rust_block() {
BookTest::from_dir("rendering/editable_rust_block").check_all_main_files();
}
// Tests for custom hide lines.
#[test]
fn hidelines() {
BookTest::from_dir("rendering/hidelines").check_all_main_files();
}
// Tests for code blocks of basic rust code.
#[test]
fn language_rust_playground() {
fn expect(input: &str, info: &str, expected: impl snapbox::IntoData) {
BookTest::init(|_| {})
.change_file("book.toml", "output.html.playground.editable = true")
.change_file("src/chapter_1.md", &format!("```rust {info}\n{input}\n```"))
.check_main_file("book/chapter_1.html", expected);
}
// No-main should be wrapped in `fn main` boring lines.
expect(
"x()",
"",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>x()
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<span class="boring">}</span></code></pre>
"#]],
);
// `fn main` should not be wrapped, not boring.
expect(
"fn main() {}",
"",
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
str![[r#"<pre class="playground"><code class="language-rust">fn main() {}</code></pre>"#]],
);
// Lines starting with `#` are boring.
expect(
"let s = \"foo\n # bar\n\";",
"editable",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust editable">let s = "foo
<span class="boring"> bar
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
</span>";</code></pre>
"#]],
);
// `##` is not boring and is used as an escape.
expect(
"let s = \"foo\n ## bar\n\";",
"editable",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust editable">let s = "foo
# bar
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
";</code></pre>
"#]],
);
// `#` on a line by itself is boring.
expect(
"let s = \"foo\n # bar\n#\n\";",
"editable",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust editable">let s = "foo
<span class="boring"> bar
</span><span class="boring">
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
</span>";</code></pre>
"#]],
);
// `#` must be followed by a space to be boring.
expect(
"#x;",
"",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>#x;
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<span class="boring">}</span></code></pre>
"#]],
);
// Other classes like "ignore" should not change things, and the class is
// included in the code tag.
expect(
"let s = \"foo\n # bar\n\";",
"ignore",
str![[r#"
<pre><code class="language-rust ignore">let s = "foo
<span class="boring"> bar
</span>";</code></pre>
"#]],
);
// Inner attributes and normal attributes are not boring.
expect(
"#![no_std]\nlet s = \"foo\";\n #[some_attr]",
"editable",
str![[r#"
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust editable">#![no_std]
let s = "foo";
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
#[some_attr]</code></pre>
"#]],
);
}
// Rust code block in a list.
#[test]
fn code_block_in_list() {
BookTest::init(|_| {})
.change_file(
"src/chapter_1.md",
r#"- inside list
```rust
fn foo() {
let x = 1;
}
```
"#,
)
.check_main_file(
"book/chapter_1.html",
str![[r#"
<ul>
<li>
<p>inside list</p>
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>fn foo() {
let x = 1;
}
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
<span class="boring">}</span></code></pre>
</li>
</ul>
"#]],
);
}
// Checks the rendering of links added to headers.
#[test]
fn header_links() {
BookTest::from_dir("rendering/header_links").check_all_main_files();
}
// A corrupted HTML end tag.
#[test]
fn busted_end_tag() {
BookTest::init(|_| {})
.change_file("src/chapter_1.md", "<div>x<span>foo</span/>y</div>")
.run("build", |cmd| {
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
WARN html parse error in `chapter_1.md`: Self-closing end tag
Html text was:
<div>x<span>foo</span/>y</div>
INFO HTML book written to `[ROOT]/book`
"#]]);
})
Add a new HTML rendering pipeline This rewrites the HTML rendering pipeline to use a tree data structure, and implements a custom HTML serializer. The intent is to make it easier to make changes and to manipulate the output. This should make some future changes much easier. This is a large change, but I'll try to briefly summarize what's changing: - All of the HTML rendering support has been moved out of mdbook-markdown into mdbook-html. For now, all of the API surface is private, though we may consider ways to safely expose it in the future. - Instead of using pulldown-cmark's html serializer, this takes the pulldown-cmark events and translates them into a tree data structure (using the ego-tree crate to define the tree). See `tree.rs`. - HTML in the markdown document is parsed using html5ever, and then lives inside the same tree data structure. See `tokenizer.rs`. - Transformations are then applied to the tree data structure. For example, adding header links or hiding code lines. - Serialization is a simple process of writing out the nodes to a string. See `serialize.rs`. - The search indexer works on the tree structure instead of re-rendering every chapter twice. See `html_handlebars/search.rs`. - The print page now takes a very different approach of taking the same tree structure built for rendering the chapters, and applies transformations to it. This avoid re-parsing everything again. See `print.rs`. - I changed the linking behavior so that links on the print page link to items on the print page instead of outside the print page. - There are a variety of small changes to how it serializes as can be seen in the changes to the tests. Some highlights: - Code blocks no longer have a second layer of `<pre>` tags wrapping it. - Fixed a minor issue where a rust code block with a specific edition was having the wrong classes when there was a default edition. - Drops the ammonia dependency, which significantly reduces the number of dependencies. It was only being used for a very minor task, and we can handle it much more easily now. - Drops `pretty_assertions`, they are no longer used (mostly being migrated to the testsuite). There's obviously a lot of risk trying to parse everything to such a low level, but I think the benefits are worth it. Also, the API isn't super ergonomic compared to say javascript (there are no selectors), but it works well enough so far. I have not run this through rigorous benchmarking, but it does have a very noticeable performance improvement, especially in a debug build. I expect in the future that we'll want to expose some kind of integration with extensions so they have access to this tree structure (or some kind of tree structure). Closes https://github.com/rust-lang/mdBook/issues/1736
2025-09-16 20:14:00 -07:00
.check_main_file("book/chapter_1.html", str!["<div>x<span>foo</span>y</div>"]);
}
// Various html blocks.
#[test]
fn html_blocks() {
BookTest::from_dir("rendering/html_blocks").check_all_main_files();
}
// Test for a fenced code block that is also indented.
#[test]
fn code_block_fenced_with_indent() {
BookTest::from_dir("rendering/code_blocks_fenced_with_indent").check_all_main_files();
}
2025-11-05 10:45:46 -08:00
// Unclosed HTML tags.
//
// Note that the HTML parsing algorithm is much more complicated than what
// this is checking.
#[test]
fn unclosed_html_tags() {
BookTest::init(|_| {})
.change_file("src/chapter_1.md", "<div>x<span>foo<i>xyz")
.run("build", |cmd| {
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
WARN unclosed HTML tag `<i>` found in `chapter_1.md`
WARN unclosed HTML tag `<span>` found in `chapter_1.md`
WARN unclosed HTML tag `<div>` found in `chapter_1.md`
2025-11-05 10:45:46 -08:00
INFO HTML book written to `[ROOT]/book`
"#]]);
})
.check_main_file(
"book/chapter_1.html",
str!["<div>x<span>foo<i>xyz</i></span></div>"],
);
}
2025-11-05 11:17:48 -08:00
// Test for HTML tags out of sync.
#[test]
fn unbalanced_html_tags() {
BookTest::init(|_| {})
.change_file("src/chapter_1.md", "<div>x<span>foo</div></span>")
.run("build", |cmd| {
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
WARN unexpected HTML end tag `</div>` found in `chapter_1.md`
Check that the HTML tags are properly balanced.
2025-11-05 11:17:48 -08:00
WARN unclosed HTML tag `<div>` found in `chapter_1.md`
INFO HTML book written to `[ROOT]/book`
"#]]);
})
.check_main_file("book/chapter_1.html", str!["<div>x<span>foo</span></div>"]);
2025-11-05 11:17:48 -08:00
}
// Test for bug with unbalanced HTML handling in the heading.
#[test]
fn heading_with_unbalanced_html() {
BookTest::init(|_| {})
.change_file("src/chapter_1.md", "### Option<T>")
.run("build", |cmd| {
cmd.expect_stderr(str![[r#"
INFO Book building has started
INFO Running the html backend
WARN unclosed HTML tag `<t>` found in `chapter_1.md` while exiting Heading(H3)
HTML tags must be closed before exiting a markdown element.
INFO HTML book written to `[ROOT]/book`
"#]]);
})
.check_main_file(
"book/chapter_1.html",
str![[r##"<h3 id="option"><a class="header" href="#option">Option<t></t></a></h3>"##]],
);
}
// The following tests cover the `output.html.site-url` feature, which makes
// every generated link absolute (rooted at `site-url`) so a book served from a
// subdirectory resolves cross-chapter, asset, and sidebar links regardless of
// the page's own depth. See https://github.com/rust-lang/mdBook/pull/1802.
// Root-relative `./` links written in chapter content are anchored to the site
// URL, while links with a scheme (e.g. `https`) are left untouched.
#[test]
fn site_url_rewrites_content_links() {
BookTest::from_dir("rendering/site_url")
.check_file_contains(
"book/nested/deep.html",
"<a href=\"https://example.com/docs/other.html\">other chapter</a>",
)
.check_file_contains(
"book/index.html",
"<a href=\"https://example.com/docs/nested/deep.html\">deep chapter</a>",
)
.check_file_contains(
"book/index.html",
"<a href=\"https://rust-lang.org\">external link</a>",
);
}
// `path_to_root` (used by the page chrome, prev/next navigation, and the
// JavaScript sidebar in `toc.js`) becomes the absolute site URL on every page,
// independent of how deeply the page is nested.
#[test]
fn site_url_sets_absolute_path_to_root() {
BookTest::from_dir("rendering/site_url").check_file_contains(
"book/nested/deep.html",
"const path_to_root = \"https://example.com/docs/\";",
);
}
// Static assets resolved through the `{{resource}}` helper are emitted with the
// absolute site URL rather than a depth-relative `../` prefix.
#[test]
fn site_url_makes_assets_absolute() {
BookTest::from_dir("rendering/site_url").check_file_contains(
"book/nested/deep.html",
"<link rel=\"stylesheet\" href=\"https://example.com/docs/css/general",
);
}
// The no-JS sidebar fallback (`toc.html`, loaded in an iframe) carries a
// `<base href>` of the site URL so its root-relative chapter links resolve
// absolutely.
#[test]
fn site_url_sets_toc_html_base() {
BookTest::from_dir("rendering/site_url")
.check_file_contains("book/toc.html", "<base href=\"https://example.com/docs/\">");
}
// The `<base href>` from `toc.html` must not leak onto regular chapter pages,
// which would break their page-relative content links.
#[test]
fn site_url_no_base_href_on_chapter_pages() {
BookTest::from_dir("rendering/site_url")
.check_file_doesnt_contain("book/nested/deep.html", "<base href")
.check_file_doesnt_contain("book/index.html", "<base href");
}
// Without `site-url`, links and assets stay depth-relative and no `<base href>`
// is emitted: the feature is strictly opt-in.
#[test]
fn site_url_absent_keeps_links_relative() {
BookTest::init(|_| {})
.check_file_contains("book/index.html", "const path_to_root = \"\";")
.check_file_doesnt_contain("book/index.html", "<base href")
.check_file_doesnt_contain("book/toc.html", "<base href");
}
// The print page roots its chrome, assets and sidebar at the site URL, while
// cross-chapter references between chapters present on the page are folded into
// intra-page anchors so the consolidated page stays self-contained.
#[test]
fn site_url_print_page() {
BookTest::from_dir("rendering/site_url")
.check_file_contains(
"book/print.html",
"const path_to_root = \"https://example.com/docs/\";",
)
.check_file_contains(
"book/print.html",
"<link rel=\"stylesheet\" href=\"https://example.com/docs/css/general",
)
.check_file_contains("book/print.html", "<a href=\"#deep\">deep chapter</a>")
.check_file_contains("book/print.html", "<a href=\"#other\">other chapter</a>")
.check_file_contains(
"book/print.html",
"<a href=\"https://rust-lang.org\">external link</a>",
);
}