Skip to content

Commit d8f7443

Browse files
Add new GUI testsuite
1 parent 39e345b commit d8f7443

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-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: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
match get_available_browser_ui_test_version() {
48+
Some(version) => {
49+
if version != browser_ui_test_version {
50+
eprintln!(
51+
"⚠️ Installed version of browser-ui-test (`{version}`) is different than the \
52+
one used in the CI (`{browser_ui_test_version}`) You can install this version \
53+
using `npm update browser-ui-test` or by using `npm install browser-ui-test\
54+
@{browser_ui_test_version}`",
55+
);
56+
}
57+
},
58+
None => {
59+
let msg = format!(
60+
"`browser-ui-test` is not installed. You can install this package using `npm \
61+
update browser-ui-test` or by using `npm install browser-ui-test\
62+
@{browser_ui_test_version}`"
63+
);
64+
65+
if std::env::var("FORCE_GUI").is_ok_and(|v| v == "1") {
66+
panic!("{msg}");
67+
} else {
68+
println!(
69+
"Ignoring `gui` test (can be overloaded with `FORCE_GUI=1` environment \
70+
variable):"
71+
);
72+
println!("{msg}");
73+
return;
74+
}
75+
},
76+
}
77+
78+
let current_dir = current_dir().expect("failed to retrieve current directory");
79+
let html_file = current_dir.join("util/gh-pages/index.html");
80+
if !html_file.is_file() {
81+
panic!("Missing `{:?}`, run `cargo collect-metadata` first", html_file);
82+
}
83+
let html_file = format!("file://{}", html_file.display());
84+
85+
let mut command = Command::new("npx");
86+
command
87+
.arg("browser-ui-test")
88+
.args(["--variable", "DOC_PATH", html_file.as_str()])
89+
.args(["--display-format", "compact"]);
90+
91+
for arg in std::env::args().skip(1) {
92+
if arg.starts_with("--") {
93+
command.arg(arg);
94+
} else {
95+
command.args(["--filter", arg.as_str()]);
96+
}
97+
}
98+
99+
let test_dir = "tests/gui";
100+
command.args(["--test-folder", test_dir]);
101+
102+
// Then we run the GUI tests on it.
103+
let status = command.status().expect("failed to get command output");
104+
assert!(status.success(), "{status:?}");
105+
}

0 commit comments

Comments
 (0)