Skip to content

Commit 7d3fea3

Browse files
committed
update e2e tests
1 parent 7a60f53 commit 7d3fea3

18 files changed

Lines changed: 393 additions & 60 deletions
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
{
2-
"name": "vite-task-tests-bins",
2+
"name": "vite-task-test-bins",
33
"private": true,
44
"bin": {
5-
"readfile": "./readfile.mjs"
5+
"print-file": "./src/print-file.ts",
6+
"json-edit": "./src/json-edit.ts"
67
},
78
"dependencies": {
89
"oxlint": "catalog:",
9-
"vite-task-tests-bins": "link:"
10+
"vite-task-test-bins": "link:"
1011
}
1112
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { readFileSync, writeFileSync } from 'node:fs';
2+
import { parseArgs } from 'node:util';
3+
4+
const { positionals } = parseArgs({
5+
allowPositionals: true,
6+
});
7+
8+
const filename = positionals[0];
9+
const script = positionals[1];
10+
11+
if (!filename || !script) {
12+
console.error('Usage: json-edit <filename> <script>');
13+
console.error('Example: json-edit package.json \'_.version = "1.2.3"\'');
14+
process.exit(1);
15+
}
16+
17+
const json = JSON.parse(readFileSync(filename, 'utf-8'));
18+
const func = new Function('_', script + '; return _;');
19+
const result = func(json);
20+
21+
writeFileSync(filename, JSON.stringify(result, null, 2) + '\n', 'utf-8');
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { readFileSync } from 'fs';
1+
import { readFileSync } from 'node:fs';
22

33
const content = readFileSync(process.argv[2]);
44
process.stdout.write(content);

crates/vite_task_bin/tests/test_snapshots/fixtures/cache-keys/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"scripts": {
33
"lint": "vite lint",
4+
"hello": "print-file",
45
"lint-and-echo": "vite lint && echo",
56
"echo-and-lint": "echo Linting && vite lint"
67
}
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,26 @@
11
[[plan]]
2-
name = "user task cache key"
2+
name = "synthetic task in user task"
33
args = ["run", "lint"]
44

55
[[plan]]
6-
name = "user task cache key with extra args"
6+
name = "synthetic task with extra args in user task"
77
args = ["run", "lint", "--fix"]
88

99
[[plan]]
10-
name = "direct synthetic task cache key"
10+
name = "normal task with extra args"
11+
args = ["run", "hello", "a.txt"]
12+
13+
[[plan]]
14+
name = "direct synthetic task"
1115
args = ["lint"]
1216

1317
[[plan]]
14-
name = "direct synthetic task cache key with cwd"
18+
name = "direct synthetic task with cwd"
1519
cwd = "subdir"
1620
args = ["lint"]
1721

1822
[[plan]]
19-
name = "direct synthetic task cache key with extra args"
23+
name = "direct synthetic task with extra args"
2024
args = ["lint", "--fix"]
2125

2226
[[plan]]
@@ -26,3 +30,9 @@ args = ["run", "lint-and-echo", "Linting complete"]
2630
[[plan]]
2731
name = "echo and lint with extra args"
2832
args = ["run", "echo-and-lint", "--fix"]
33+
34+
[[e2e]]
35+
name = "direct lint"
36+
steps = [
37+
"vite lint",
38+
]

crates/vite_task_bin/tests/test_snapshots/main.rs

Lines changed: 91 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
mod redact;
22

3-
use std::{collections::HashMap, convert::Infallible, ffi::OsStr, path::Path, sync::Arc};
3+
use std::{
4+
collections::HashMap,
5+
convert::Infallible,
6+
env::{self, join_paths, split_paths},
7+
ffi::OsStr,
8+
fmt::format,
9+
path::Path,
10+
process::Command,
11+
sync::Arc,
12+
};
413

514
use copy_dir::copy_dir;
6-
use redact::redact_snapshot;
15+
use redact::{redact_e2e_output, redact_snapshot};
716
use tokio::runtime::Runtime;
817
use vite_path::{AbsolutePath, RelativePathBuf};
918
use vite_str::Str;
@@ -21,6 +30,9 @@ struct Plan {
2130

2231
#[derive(serde::Deserialize, Debug)]
2332
struct E2e {
33+
pub name: Str,
34+
#[serde(default)]
35+
pub cwd: RelativePathBuf,
2436
pub steps: Vec<Str>,
2537
}
2638

@@ -62,26 +74,47 @@ fn run_case(runtime: &Runtime, tmpdir: &AbsolutePath, fixture_path: &Path) {
6274
Err(err) => panic!("Failed to read cases.toml for fixture {}: {}", fixture_name, err),
6375
};
6476

65-
// Add bins to PATH so test programs (such as readfile) in fixtures can be found.
66-
let envs: HashMap<Arc<OsStr>, Arc<OsStr>> = [(
67-
Arc::<OsStr>::from(OsStr::new("PATH")),
68-
Arc::<OsStr>::from(
69-
std::env::current_dir()
70-
.unwrap()
71-
.join("test_bins")
72-
.join("node_modules")
73-
.join(".bin")
74-
.into_os_string(),
77+
let test_bin_path = Arc::<OsStr>::from(
78+
std::env::current_dir()
79+
.unwrap()
80+
.join("test_bins")
81+
.join("node_modules")
82+
.join(".bin")
83+
.into_os_string(),
84+
);
85+
86+
// Add test_bins to PATH so test programs (such as print-file) in fixtures can be found.
87+
let plan_envs: HashMap<Arc<OsStr>, Arc<OsStr>> =
88+
[(Arc::<OsStr>::from(OsStr::new("PATH")), Arc::clone(&test_bin_path))]
89+
.into_iter()
90+
.collect();
91+
92+
// Prepare PATH for e2e tests
93+
let e2e_env_path = join_paths(
94+
[
95+
// Include vite binary path to PATH so that e2e tests can run "vite ..." commands.
96+
{
97+
let vite_path = AbsolutePath::new(env!("CARGO_BIN_EXE_vite")).unwrap();
98+
let vite_dir = vite_path.parent().unwrap();
99+
vite_dir.as_path().as_os_str().into()
100+
},
101+
// Include test_bins to PATH so that e2e tests can run utilities such as json-edit.
102+
test_bin_path,
103+
]
104+
.into_iter()
105+
.chain(
106+
// the existing PATH
107+
split_paths(&env::var_os("PATH").unwrap())
108+
.map(|path| Arc::<OsStr>::from(path.into_os_string())),
75109
),
76-
)]
77-
.into_iter()
78-
.collect();
110+
)
111+
.unwrap();
79112

80113
runtime.block_on(async {
81114
let workspace_root_str = workspace_root.path.as_path().to_str().unwrap();
82115
let mut owned_callbacks = vite_task_bin::OwnedSessionCallbacks::default();
83116
let mut session = Session::init_with(
84-
envs,
117+
plan_envs,
85118
Arc::clone(&workspace_root.path),
86119
owned_callbacks.as_callbacks(),
87120
)
@@ -95,6 +128,7 @@ fn run_case(runtime: &Runtime, tmpdir: &AbsolutePath, fixture_path: &Path) {
95128
);
96129
insta::assert_json_snapshot!("task graph", task_graph_json);
97130

131+
let mut e2e_count = 0u32;
98132
for plan in cases_file.plan_cases {
99133
let snapshot_name = format!("query - {}", plan.name);
100134

@@ -126,29 +160,48 @@ fn run_case(runtime: &Runtime, tmpdir: &AbsolutePath, fixture_path: &Path) {
126160

127161
let plan_json = redact_snapshot(&plan, workspace_root_str);
128162
insta::assert_json_snapshot!(snapshot_name, &plan_json);
129-
130-
// let cwd: Arc<AbsolutePath> = case_stage_path.join(&cli_query.cwd).into();
131-
// let task_query = match cli_task_query.into_task_query(&cwd) {
132-
// Ok(ok) => ok,
133-
// Err(err) => {
134-
// insta::assert_json_snapshot!(snapshot_name, err);
135-
// continue;
136-
// }
137-
// };
138-
139-
// let execution_graph = match indexed_task_graph.query_tasks(task_query) {
140-
// Ok(ok) => ok,
141-
// Err(err) => {
142-
// insta::assert_json_snapshot!(snapshot_name, err);
143-
// continue;
144-
// }
145-
// };
146-
147-
// let execution_graph_snapshot =
148-
// snapshot_execution_graph(&execution_graph, &indexed_task_graph);
149-
// insta::assert_json_snapshot!(snapshot_name, execution_graph_snapshot);
150163
}
151-
for e2e in cases_file.e2e_cases {}
164+
for e2e in cases_file.e2e_cases {
165+
let e2e_stage_path = tmpdir.join(format!("e2e_stage_{}", e2e_count));
166+
e2e_count += 1;
167+
assert!(copy_dir(fixture_path, &e2e_stage_path).unwrap().is_empty());
168+
169+
let e2e_stage_path_str = e2e_stage_path.as_path().to_str().unwrap();
170+
171+
let mut e2e_outputs = String::new();
172+
for step in e2e.steps {
173+
let mut cmd = if cfg!(windows) {
174+
let mut cmd = Command::new("cmd.exe");
175+
// https://github.com/nodejs/node/blob/dbd24b165128affb7468ca42f69edaf7e0d85a9a/lib/child_process.js#L633
176+
cmd.args(["/d", "/s", "/c"]);
177+
cmd
178+
} else {
179+
let mut cmd = Command::new("sh");
180+
cmd.args(["-c"]);
181+
cmd
182+
};
183+
cmd.arg(step.as_str())
184+
.env_clear()
185+
.env("PATH", &e2e_env_path)
186+
.current_dir(e2e_stage_path.join(&e2e.cwd));
187+
let output = cmd.output().unwrap();
188+
189+
let exit_code = output.status.code().unwrap_or(-1);
190+
if exit_code != 0 {
191+
e2e_outputs.push_str(format!("[{}]", exit_code).as_str());
192+
}
193+
e2e_outputs.push_str("> ");
194+
e2e_outputs.push_str(step.as_str());
195+
e2e_outputs.push('\n');
196+
197+
let stdout = String::from_utf8(output.stdout).unwrap();
198+
let stderr = String::from_utf8(output.stderr).unwrap();
199+
e2e_outputs.push_str(&redact_e2e_output(stdout, e2e_stage_path_str));
200+
e2e_outputs.push_str(&redact_e2e_output(stderr, e2e_stage_path_str));
201+
e2e_outputs.push('\n');
202+
}
203+
insta::assert_snapshot!(e2e.name.as_str(), e2e_outputs);
204+
}
152205
});
153206
}
154207

crates/vite_task_bin/tests/test_snapshots/redact.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,40 @@ fn visit_json(value: &mut serde_json::Value, f: &mut impl FnMut(&mut serde_json:
2020
}
2121
}
2222

23-
fn redact_paths(value: &mut serde_json::Value, redactions: &[(&str, &str)]) {
24-
use cow_utils::CowUtils as _;
23+
fn redact_string_in_json(value: &mut serde_json::Value, redactions: &[(&str, &str)]) {
2524
visit_json(value, &mut |v| {
2625
if let serde_json::Value::String(s) = v {
27-
for (from, to) in redactions {
28-
if let Cow::Owned(mut replaced) = s.as_str().cow_replace(from, to) {
29-
if cfg!(windows) {
30-
// Also replace with backslashes on Windows
31-
replaced = replaced.cow_replace("\\", "/").into_owned();
32-
}
33-
*s = replaced;
34-
}
35-
}
26+
redact_string(s, redactions);
3627
}
3728
});
3829
}
3930

31+
fn redact_string(s: &mut String, redactions: &[(&str, &str)]) {
32+
use cow_utils::CowUtils as _;
33+
for (from, to) in redactions {
34+
if let Cow::Owned(mut replaced) = s.as_str().cow_replace(from, to) {
35+
if cfg!(windows) {
36+
// Also replace with backslashes on Windows
37+
replaced = replaced.cow_replace("\\", "/").into_owned();
38+
}
39+
*s = replaced;
40+
}
41+
}
42+
}
43+
44+
pub fn redact_e2e_output(mut output: String, workspace_root: &str) -> String {
45+
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
46+
redact_string(
47+
&mut output,
48+
&[(workspace_root, "<workspace>"), (manifest_dir.as_str(), "<manifest_dir>")],
49+
);
50+
output
51+
}
52+
4053
pub fn redact_snapshot(value: &impl Serialize, workspace_root: &str) -> serde_json::Value {
4154
let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").unwrap();
4255
let mut json_value = serde_json::to_value(value).unwrap();
43-
redact_paths(
56+
redact_string_in_json(
4457
&mut json_value,
4558
&[(workspace_root, "<workspace>"), (manifest_dir.as_str(), "<manifest_dir>")],
4659
);

0 commit comments

Comments
 (0)