sweet_cli/test_runners/
test_wasm.rs1use anyhow::Result;
2use clap::Parser;
3use std::fs;
4use std::path::PathBuf;
5use std::process::Child;
6use std::process::Command;
7use std::str::FromStr;
8use sweet::prelude::*;
9
10#[derive(Debug, Parser)]
25pub struct TestWasm {
26 test_binary: String,
30 #[arg(long)]
32 wasm_bindgen_args: Option<String>,
33
34 #[command(flatten)]
37 runner_args: sweet::prelude::TestRunnerConfig,
38}
39
40
41impl TestWasm {
42 pub fn run(self) -> Result<()> {
43 self.run_wasm_bindgen()?;
44 self.init_deno()?;
45 self.run_deno()?;
46 Ok(())
47 }
48 fn run_wasm_bindgen(&self) -> Result<()> {
49 let output = Command::new("wasm-bindgen")
50 .arg("--out-dir")
51 .arg(sweet_target_dir())
52 .arg("--out-name")
53 .arg("bindgen")
54 .arg("--target")
55 .arg("web")
56 .arg("--no-typescript")
57 .arg(&self.test_binary)
58 .args(
59 self.wasm_bindgen_args
60 .as_deref()
61 .unwrap_or_default()
62 .split_whitespace(),
63 )
64 .spawn()?;
65
66 handle_process("wasm-bindgen", output)?;
67 Ok(())
68 }
69
70
71 fn init_deno(&self) -> Result<()> {
75 let deno_runner_path = deno_runner_path();
76 let deno_str = include_str!("./deno.ts");
77
78 if ReadFile::exists(&deno_runner_path) {
80 let runner_hash = ReadFile::hash_file(&deno_runner_path)?;
81 let deno_hash = ReadFile::hash_string(deno_str);
82 if runner_hash == deno_hash {
83 return Ok(());
84 }
85 };
86
87 let deno_installed =
88 match Command::new("deno").arg("--version").status() {
89 Ok(val) => val.success(),
90 _ => false,
91 };
92 if !deno_installed {
93 anyhow::bail!(INSTALL_DENO);
94 }
95 println!("copying deno file to {}", deno_runner_path.display());
96
97 fs::write(deno_runner_path, deno_str)?;
99 Ok(())
100 }
101
102 fn run_deno(&self) -> Result<()> {
103 let args = std::env::args().skip(2).collect::<Vec<_>>();
107 let child = Command::new("deno")
108 .arg("--allow-read")
109 .arg("--allow-net")
110 .arg("--allow-env")
111 .arg(deno_runner_path())
112 .args(args)
113 .spawn()?;
114 handle_process("deno", child)?;
115 Ok(())
116 }
117}
118
119
120fn handle_process(_stderr_prefix: &str, child: Child) -> Result<()> {
121 let output = child.wait_with_output()?;
122
123 let stdout = String::from_utf8_lossy(&output.stdout);
124 if !stdout.is_empty() {
125 println!("{}", stdout);
126 }
127
128 if !output.status.success() {
129 let stderr = String::from_utf8_lossy(&output.stderr);
130 anyhow::bail!("{stderr}");
131 }
132 Ok(())
133}
134
135fn workspace_root() -> PathBuf {
136 let root_str = std::env::var("SWEET_ROOT").unwrap_or_default();
137 PathBuf::from_str(&root_str).unwrap()
138}
139
140fn sweet_target_dir() -> PathBuf {
141 let mut path = workspace_root();
142 path.push("target/sweet");
143 path
144}
145
146fn deno_runner_path() -> PathBuf {
147 let mut path = sweet_target_dir();
148 path.push("deno.ts");
149 path
150}
151
152const INSTALL_DENO: &str = "
153🦖 Sweet uses Deno for wasm tests 🦖
154
155Install Deno via:
156shell: curl -fsSL https://deno.land/install.sh | sh
157powershell: irm https://deno.land/install.ps1 | iex
158website: https://docs.deno.com/runtime/getting_started/installation/
159
160";
161
162
163#[cfg(test)]
164mod test {
165 use crate::prelude::*;
166 use sweet::prelude::*;
167 use test_wasm::deno_runner_path;
168
169 #[test]
170 fn works() {
171 expect(deno_runner_path().to_string_lossy().replace("\\", "/"))
172 .to_end_with("target/sweet/deno.ts");
173 }
174}