mirror of
https://github.com/rust-lang/mdBook.git
synced 2025-12-27 07:54:20 -05:00
Support multiple books in the GUI tests
This adds the ability to use multiple books for the GUI tests. This is helpful since some tests need special configuration, and sharing the same book can make it difficult or impossible to test different configurations. It also makes it difficult to make changes to the test_book since it can affect other tests. This works by placing the books in the tests/gui/books directory. The test runner will automatically build all the books. The gui tests can then just access the DOC_PATH with the name of the book. Books are now saved in a temp directory to make it easier to use the DOC_PATH variable, instead of being tests/gui/books/book_name/book which is a little awkward. Following commits will restructure the existing book. This is just a mechanical move.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -8,7 +8,7 @@ guide/book
|
|||||||
|
|
||||||
.vscode
|
.vscode
|
||||||
tests/dummy_book/book/
|
tests/dummy_book/book/
|
||||||
test_book/book/
|
tests/gui/books/*/book/
|
||||||
tests/testsuite/*/*/book/
|
tests/testsuite/*/*/book/
|
||||||
|
|
||||||
# Ignore Jetbrains specific files.
|
# Ignore Jetbrains specific files.
|
||||||
|
|||||||
@@ -185,9 +185,7 @@ If you want to disable the headless mode, use the `--disable-headless-test` opti
|
|||||||
cargo test --test gui -- --disable-headless-test
|
cargo test --test gui -- --disable-headless-test
|
||||||
```
|
```
|
||||||
|
|
||||||
The GUI tests are in the directory `tests/gui` in text files with the `.goml` extension. These tests are run
|
The GUI tests are in the directory `tests/gui` in text files with the `.goml` extension. The books that the tests use are located in the `tests/gui/books` directory. These tests are run using a `node.js` framework called `browser-ui-test`. You can find documentation for this language on its [repository](https://github.com/GuillaumeGomez/browser-UI-test/blob/master/goml-script.md).
|
||||||
using a `node.js` framework called `browser-ui-test`. You can find documentation for this language on its
|
|
||||||
[repository](https://github.com/GuillaumeGomez/browser-UI-test/blob/master/goml-script.md).
|
|
||||||
|
|
||||||
### Checking changes in `.js` files
|
### Checking changes in `.js` files
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Tests for collapsed heading sidebar navigation.
|
// Tests for collapsed heading sidebar navigation.
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/collapsed.html"
|
go-to: |DOC_PATH| + "test_book/headings/collapsed.html"
|
||||||
|
|
||||||
assert-count: (".header-item", 12)
|
assert-count: (".header-item", 12)
|
||||||
assert-count: (".current-header", 1)
|
assert-count: (".current-header", 1)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// bottom.
|
// bottom.
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/current-to-bottom.html"
|
go-to: |DOC_PATH| + "test_book/headings/current-to-bottom.html"
|
||||||
assert-count: (".current-header", 1)
|
assert-count: (".current-header", 1)
|
||||||
assert-text: (".current-header", "First header")
|
assert-text: (".current-header", "First header")
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// When there aren't any headings, there shouldn't be any header items in the sidebar.
|
// When there aren't any headings, there shouldn't be any header items in the sidebar.
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/empty.html"
|
go-to: |DOC_PATH| + "test_book/headings/empty.html"
|
||||||
assert-count: (".header-item", 0)
|
assert-count: (".header-item", 0)
|
||||||
assert-count: (".current-header", 0)
|
assert-count: (".current-header", 0)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// you scroll down and make it visible on screen.
|
// you scroll down and make it visible on screen.
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/large-intro.html"
|
go-to: |DOC_PATH| + "test_book/headings/large-intro.html"
|
||||||
assert-count: (".header-item", 2)
|
assert-count: (".header-item", 2)
|
||||||
assert-count: (".current-header", 0)
|
assert-count: (".current-header", 0)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// When a header has various markup, the sidebar should replicate it.
|
// When a header has various markup, the sidebar should replicate it.
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/markup.html"
|
go-to: |DOC_PATH| + "test_book/headings/markup.html"
|
||||||
|
|
||||||
assert-count: (".header-item", 5)
|
assert-count: (".header-item", 5)
|
||||||
assert-count: (".current-header", 1)
|
assert-count: (".current-header", 1)
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// should be "current".
|
// should be "current".
|
||||||
|
|
||||||
set-window-size: (1400, 800)
|
set-window-size: (1400, 800)
|
||||||
go-to: |DOC_PATH| + "headings/normal-intro.html"
|
go-to: |DOC_PATH| + "test_book/headings/normal-intro.html"
|
||||||
assert-count: (".header-item", 4)
|
assert-count: (".header-item", 4)
|
||||||
assert-count: (".current-header", 1)
|
assert-count: (".current-header", 1)
|
||||||
assert-text: (".current-header", "The first heading")
|
assert-text: (".current-header", "The first heading")
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This GUI test checks help popup.
|
// This GUI test checks help popup.
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
assert-css: ("#mdbook-help-container", {"display": "none"})
|
assert-css: ("#mdbook-help-container", {"display": "none"})
|
||||||
press-key: '?'
|
press-key: '?'
|
||||||
wait-for-css: ("#mdbook-help-container", {"display": "flex"})
|
wait-for-css: ("#mdbook-help-container", {"display": "flex"})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This tests pressing the left and right arrows moving to previous and next page.
|
// This tests pressing the left and right arrows moving to previous and next page.
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
|
|
||||||
// default page is the first numbered page
|
// default page is the first numbered page
|
||||||
assert-text: ("title", "Introduction - mdBook test book")
|
assert-text: ("title", "Introduction - mdBook test book")
|
||||||
|
|||||||
@@ -1,41 +1,41 @@
|
|||||||
go-to: |DOC_PATH| + "format/config.html"
|
go-to: |DOC_PATH| + "test_book/format/config.html"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html"})
|
||||||
|
|
||||||
// Check that it preserves fragments when redirecting.
|
// Check that it preserves fragments when redirecting.
|
||||||
go-to: |DOC_PATH| + "format/config.html#fragment"
|
go-to: |DOC_PATH| + "test_book/format/config.html#fragment"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html#fragment"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html#fragment"})
|
||||||
|
|
||||||
// The fragment one here isn't necessary, but should still work.
|
// The fragment one here isn't necessary, but should still work.
|
||||||
go-to: |DOC_PATH| + "pointless-fragment.html"
|
go-to: |DOC_PATH| + "test_book/pointless-fragment.html"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html"})
|
||||||
go-to: |DOC_PATH| + "pointless-fragment.html#foo"
|
go-to: |DOC_PATH| + "test_book/pointless-fragment.html#foo"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html#foo"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html#foo"})
|
||||||
|
|
||||||
// Page rename, and a fragment rename.
|
// Page rename, and a fragment rename.
|
||||||
go-to: |DOC_PATH| + "rename-page-and-fragment.html"
|
go-to: |DOC_PATH| + "test_book/rename-page-and-fragment.html"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html"})
|
||||||
go-to: |DOC_PATH| + "rename-page-and-fragment.html#orig"
|
go-to: |DOC_PATH| + "test_book/rename-page-and-fragment.html#orig"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html#new"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html#new"})
|
||||||
|
|
||||||
// Page rename, and the fragment goes to a *different* page from the default.
|
// Page rename, and the fragment goes to a *different* page from the default.
|
||||||
go-to: |DOC_PATH| + "rename-page-fragment-elsewhere.html"
|
go-to: |DOC_PATH| + "test_book/rename-page-fragment-elsewhere.html"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html"})
|
||||||
go-to: |DOC_PATH| + "rename-page-fragment-elsewhere.html#orig"
|
go-to: |DOC_PATH| + "test_book/rename-page-fragment-elsewhere.html#orig"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "suffix.html#new"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/suffix.html#new"})
|
||||||
|
|
||||||
// Rename fragment on an existing page.
|
// Rename fragment on an existing page.
|
||||||
go-to: |DOC_PATH| + "prefix.html#orig"
|
go-to: |DOC_PATH| + "test_book/prefix.html#orig"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html#new"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html#new"})
|
||||||
|
|
||||||
// Other fragments aren't affected.
|
// Other fragments aren't affected.
|
||||||
go-to: |DOC_PATH| + "index.html" // Reset page since redirects are processed on load.
|
go-to: |DOC_PATH| + "test_book/index.html" // Reset page since redirects are processed on load.
|
||||||
go-to: |DOC_PATH| + "prefix.html"
|
go-to: |DOC_PATH| + "test_book/prefix.html"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html"})
|
||||||
go-to: |DOC_PATH| + "index.html" // Reset page since redirects are processed on load.
|
go-to: |DOC_PATH| + "test_book/index.html" // Reset page since redirects are processed on load.
|
||||||
go-to: |DOC_PATH| + "prefix.html#dont-change"
|
go-to: |DOC_PATH| + "test_book/prefix.html#dont-change"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "prefix.html#dont-change"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/prefix.html#dont-change"})
|
||||||
|
|
||||||
// Rename fragment on an existing page to another page.
|
// Rename fragment on an existing page to another page.
|
||||||
go-to: |DOC_PATH| + "index.html" // Reset page since redirects are processed on load.
|
go-to: |DOC_PATH| + "test_book/index.html" // Reset page since redirects are processed on load.
|
||||||
go-to: |DOC_PATH| + "prefix.html#orig-new-page"
|
go-to: |DOC_PATH| + "test_book/prefix.html#orig-new-page"
|
||||||
assert-window-property: ({"location": |DOC_PATH| + "suffix.html#new"})
|
assert-window-property: ({"location": |DOC_PATH| + "test_book/suffix.html#new"})
|
||||||
|
|||||||
@@ -5,9 +5,9 @@
|
|||||||
//! information.
|
//! information.
|
||||||
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::env::current_dir;
|
use std::fs::read_to_string;
|
||||||
use std::fs::{read_to_string, remove_dir_all};
|
use std::path::{Path, PathBuf};
|
||||||
use std::process::Command;
|
use std::process::{Command, Output};
|
||||||
|
|
||||||
fn get_available_browser_ui_test_version_inner(global: bool) -> Option<String> {
|
fn get_available_browser_ui_test_version_inner(global: bool) -> Option<String> {
|
||||||
let mut command = Command::new("npm");
|
let mut command = Command::new("npm");
|
||||||
@@ -69,23 +69,75 @@ fn main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let current_dir = current_dir().expect("failed to retrieve current directory");
|
let out_dir = Path::new(env!("CARGO_TARGET_TMPDIR")).join("gui");
|
||||||
let test_book = current_dir.join("test_book");
|
build_books(&out_dir);
|
||||||
|
run_browser_ui_test(&out_dir);
|
||||||
|
}
|
||||||
|
|
||||||
// Result doesn't matter.
|
fn build_books(out_dir: &Path) {
|
||||||
let _ = remove_dir_all(test_book.join("book"));
|
let exe = build_mdbook();
|
||||||
|
let root = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||||
|
let books_dir = root.join("tests/gui/books");
|
||||||
|
for entry in books_dir.read_dir().unwrap() {
|
||||||
|
let entry = entry.unwrap();
|
||||||
|
let path = entry.path();
|
||||||
|
if !path.is_dir() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
println!("Building `{}`", path.display());
|
||||||
|
let mut cmd = Command::new(&exe);
|
||||||
|
let output = cmd
|
||||||
|
.arg("build")
|
||||||
|
.arg("--dest-dir")
|
||||||
|
.arg(out_dir.join(path.file_name().unwrap()))
|
||||||
|
.arg(&path)
|
||||||
|
.output()
|
||||||
|
.expect("mdbook should be built");
|
||||||
|
check_status(&cmd, &output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_mdbook() -> PathBuf {
|
||||||
let mut cmd = Command::new("cargo");
|
let mut cmd = Command::new("cargo");
|
||||||
cmd.arg("run").arg("build").arg(&test_book);
|
let output = cmd
|
||||||
// Then we run the GUI tests on it.
|
.arg("build")
|
||||||
assert!(cmd.status().is_ok_and(|status| status.success()));
|
.output()
|
||||||
|
.expect("cargo should be installed");
|
||||||
|
check_status(&cmd, &output);
|
||||||
|
let target_dir = detect_target_dir();
|
||||||
|
target_dir.join("debug/mdbook")
|
||||||
|
}
|
||||||
|
|
||||||
let book_dir = format!("file://{}", current_dir.join("test_book/book/").display());
|
fn detect_target_dir() -> PathBuf {
|
||||||
|
let mut cmd = Command::new("cargo");
|
||||||
|
let output = cmd
|
||||||
|
.args(["metadata", "--format-version=1", "--no-deps"])
|
||||||
|
.output()
|
||||||
|
.expect("cargo should be installed");
|
||||||
|
check_status(&cmd, &output);
|
||||||
|
let v: serde_json::Value = serde_json::from_slice(&output.stdout).expect("invalid json");
|
||||||
|
PathBuf::from(v["target_directory"].as_str().unwrap())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_status(cmd: &Command, output: &Output) {
|
||||||
|
if !output.status.success() {
|
||||||
|
eprintln!("error: `{cmd:?}` failed");
|
||||||
|
let stdout = std::str::from_utf8(&output.stdout).expect("stdout is not utf8");
|
||||||
|
let stderr = std::str::from_utf8(&output.stderr).expect("stderr is not utf8");
|
||||||
|
eprintln!("\n--- stdout\n{stdout}\n--- stderr\n{stderr}");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_browser_ui_test(out_dir: &Path) {
|
||||||
let mut command = Command::new("npx");
|
let mut command = Command::new("npx");
|
||||||
|
let mut doc_path = format!("file://{}", out_dir.display());
|
||||||
|
if !doc_path.ends_with('/') {
|
||||||
|
doc_path.push('/');
|
||||||
|
}
|
||||||
command
|
command
|
||||||
.arg("browser-ui-test")
|
.arg("browser-ui-test")
|
||||||
.args(["--variable", "DOC_PATH", book_dir.as_str()])
|
.args(["--variable", "DOC_PATH", doc_path.as_str()])
|
||||||
.args(["--display-format", "compact"]);
|
.args(["--display-format", "compact"]);
|
||||||
|
|
||||||
for arg in std::env::args().skip(1) {
|
for arg in std::env::args().skip(1) {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// This tests basic search behavior.
|
// This tests basic search behavior.
|
||||||
|
|
||||||
fail-on-js-error: true
|
fail-on-js-error: true
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
|
|
||||||
define-function: (
|
define-function: (
|
||||||
"open-search",
|
"open-search",
|
||||||
@@ -31,7 +31,7 @@ write: "strikethrough"
|
|||||||
wait-for-text: ("#mdbook-searchresults-header", "2 search results for 'strikethrough':")
|
wait-for-text: ("#mdbook-searchresults-header", "2 search results for 'strikethrough':")
|
||||||
|
|
||||||
// Now we test search shortcuts and more page changes.
|
// Now we test search shortcuts and more page changes.
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
|
|
||||||
// This check is to ensure that the search bar is inside the search wrapper.
|
// This check is to ensure that the search bar is inside the search wrapper.
|
||||||
assert: "#mdbook-search-wrapper #mdbook-searchbar"
|
assert: "#mdbook-search-wrapper #mdbook-searchbar"
|
||||||
@@ -66,7 +66,7 @@ assert-document-property: ({"URL": "?search=test"}, ENDS_WITH)
|
|||||||
|
|
||||||
// Now we ensure that when we land on the page with a "search in progress", the search results are
|
// Now we ensure that when we land on the page with a "search in progress", the search results are
|
||||||
// loaded and that the search input has focus.
|
// loaded and that the search input has focus.
|
||||||
go-to: |DOC_PATH| + "index.html?search=test"
|
go-to: |DOC_PATH| + "test_book/index.html?search=test"
|
||||||
wait-for-text: ("#mdbook-searchresults-header", "search results for 'test':", ENDS_WITH)
|
wait-for-text: ("#mdbook-searchresults-header", "search results for 'test':", ENDS_WITH)
|
||||||
assert: "#mdbook-searchbar:focus"
|
assert: "#mdbook-searchbar:focus"
|
||||||
assert: "#mdbook-searchresults"
|
assert: "#mdbook-searchresults"
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
// This GUI test checks the active page sidebar highlight.
|
// This GUI test checks the active page sidebar highlight.
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
|
|
||||||
assert-text: ("mdbook-sidebar-scrollbox a.active", "Prefix Chapter")
|
assert-text: ("mdbook-sidebar-scrollbox a.active", "Prefix Chapter")
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "individual/index.html"
|
go-to: |DOC_PATH| + "test_book/individual/index.html"
|
||||||
|
|
||||||
assert-text: ("mdbook-sidebar-scrollbox a.active", "3. Markdown Individual tags")
|
assert-text: ("mdbook-sidebar-scrollbox a.active", "3. Markdown Individual tags")
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html?highlight=test"
|
go-to: |DOC_PATH| + "test_book/index.html?highlight=test"
|
||||||
|
|
||||||
assert-text: ("mdbook-sidebar-scrollbox a.active", "Prefix Chapter")
|
assert-text: ("mdbook-sidebar-scrollbox a.active", "Prefix Chapter")
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "individual/index.html?highlight=test"
|
go-to: |DOC_PATH| + "test_book/individual/index.html?highlight=test"
|
||||||
|
|
||||||
assert-text: ("mdbook-sidebar-scrollbox a.active", "3. Markdown Individual tags")
|
assert-text: ("mdbook-sidebar-scrollbox a.active", "3. Markdown Individual tags")
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
// We disable javascript
|
// We disable javascript
|
||||||
javascript: false
|
javascript: false
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
store-value: (height, 1028)
|
store-value: (height, 1028)
|
||||||
set-window-size: (1028, |height|)
|
set-window-size: (1028, |height|)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// This GUI test checks sidebar hide/show and also its behaviour on smaller
|
// This GUI test checks sidebar hide/show and also its behaviour on smaller
|
||||||
// width.
|
// width.
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
set-window-size: (1100, 600)
|
set-window-size: (1100, 600)
|
||||||
// Need to reload for the new size to be taken account by the JS.
|
// Need to reload for the new size to be taken account by the JS.
|
||||||
reload:
|
reload:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
debug: true
|
debug: true
|
||||||
|
|
||||||
go-to: |DOC_PATH| + "index.html"
|
go-to: |DOC_PATH| + "test_book/index.html"
|
||||||
|
|
||||||
// TODO: Dark mode is automatic, how to check that here?
|
// TODO: Dark mode is automatic, how to check that here?
|
||||||
assert-css: ("#mdbook-theme-list", {"display": "none"})
|
assert-css: ("#mdbook-theme-list", {"display": "none"})
|
||||||
|
|||||||
Reference in New Issue
Block a user