Skip to content

Commit 68db0d7

Browse files
Add new GUI testsuite
1 parent 39e345b commit 68db0d7

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ harness = false
6565
name = "dogfood"
6666
harness = false
6767

68+
[[test]]
69+
name = "gui"
70+
harness = false
71+
path = "tests/gui/runner.rs"
72+
crate-type = ["bin"]
73+
6874
[lints.rust.unexpected_cfgs]
6975
level = "warn"
7076
check-cfg = ['cfg(bootstrap)']

tests/gui/js-filter.goml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// This test ensures that the (JS) filters are working as expected.
2+
3+
go-to: |DOC_PATH|
4+
// Check that by default, all lints are displayed except the "deprecated" ones.
5+
store-count: ("article .lint-title", nb_lints)
6+
store-count: ("article:not(.hidden) .lint-title", nb_visible_lints)
7+
store-count: ("article.hidden .lint-title", nb_deprecated_lints)
8+
assert: |nb_lints| == |nb_visible_lints| + |nb_deprecated_lints|

tests/gui/runner.rs

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
//! The GUI test runner.
2+
//!
3+
//! This uses the browser-ui-test npm package to use a headless Chrome to
4+
//! exercise the behavior of rendered books. See `CONTRIBUTING.md` for more
5+
//! information.
6+
7+
use serde_json::Value;
8+
use std::env::current_dir;
9+
use std::fs::read_to_string;
10+
use std::process::Command;
11+
12+
fn get_available_browser_ui_test_version_inner(global: bool) -> Option<String> {
13+
let mut command = Command::new("npm");
14+
command.arg("list").arg("--parseable").arg("--long").arg("--depth=0");
15+
if global {
16+
command.arg("--global");
17+
}
18+
let stdout = command.output().expect("`npm` command not found").stdout;
19+
let lines = String::from_utf8_lossy(&stdout);
20+
lines
21+
.lines()
22+
.find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@"))
23+
.map(std::borrow::ToOwned::to_owned)
24+
}
25+
26+
fn get_available_browser_ui_test_version() -> Option<String> {
27+
get_available_browser_ui_test_version_inner(false).or_else(|| get_available_browser_ui_test_version_inner(true))
28+
}
29+
30+
fn expected_browser_ui_test_version() -> String {
31+
let content = read_to_string("package.json").expect("failed to read `package.json`");
32+
let v: Value = serde_json::from_str(&content).expect("failed to parse `package.json`");
33+
let Some(dependencies) = v.get("dependencies") else {
34+
panic!("Missing `dependencies` key in `package.json`");
35+
};
36+
let Some(browser_ui_test) = dependencies.get("browser-ui-test") else {
37+
panic!("Missing `browser-ui-test` key in \"dependencies\" object in `package.json`");
38+
};
39+
let Value::String(version) = browser_ui_test else {
40+
panic!("`browser-ui-test` version is not a string");
41+
};
42+
version.trim().to_string()
43+
}
44+
45+
fn main() {
46+
let browser_ui_test_version = expected_browser_ui_test_version();
47+
if let Some(version) = get_available_browser_ui_test_version() {
48+
if version != browser_ui_test_version {
49+
eprintln!(
50+
"⚠️ Installed version of browser-ui-test (`{version}`) is different than the \
51+
one used in the CI (`{browser_ui_test_version}`) You can install this version \
52+
using `npm update browser-ui-test` or by using `npm install browser-ui-test\
53+
@{browser_ui_test_version}`",
54+
);
55+
}
56+
} else {
57+
let msg = format!(
58+
"`browser-ui-test` is not installed. You can install this package using `npm \
59+
update browser-ui-test` or by using `npm install browser-ui-test\
60+
@{browser_ui_test_version}`"
61+
);
62+
63+
if std::env::var("FORCE_GUI").is_ok_and(|v| v == "1") {
64+
panic!("{msg}");
65+
} else {
66+
println!(
67+
"Ignoring `gui` test (can be overloaded with `FORCE_GUI=1` environment \
68+
variable):"
69+
);
70+
println!("{msg}");
71+
return;
72+
}
73+
}
74+
75+
let current_dir = current_dir().expect("failed to retrieve current directory");
76+
let html_file = current_dir.join("util/gh-pages/index.html");
77+
assert!(html_file.is_file(), "Missing `{html_file:?}`, run `cargo collect-metadata` first");
78+
let html_file = format!("file://{}", html_file.display());
79+
80+
let mut command = Command::new("npx");
81+
command
82+
.arg("browser-ui-test")
83+
.args(["--variable", "DOC_PATH", html_file.as_str()])
84+
.args(["--display-format", "compact"]);
85+
86+
for arg in std::env::args().skip(1) {
87+
if arg.starts_with("--") {
88+
command.arg(arg);
89+
} else {
90+
command.args(["--filter", arg.as_str()]);
91+
}
92+
}
93+
94+
let test_dir = "tests/gui";
95+
command.args(["--test-folder", test_dir]);
96+
97+
// Then we run the GUI tests on it.
98+
let status = command.status().expect("failed to get command output");
99+
assert!(status.success(), "{status:?}");
100+
}

0 commit comments

Comments
 (0)