Skip to content

Commit 4f21fc6

Browse files
committed
add temporary macos tests
Signed-off-by: Andrei Gherghescu <[email protected]>
1 parent 2e87a31 commit 4f21fc6

File tree

3 files changed

+292
-3
lines changed

3 files changed

+292
-3
lines changed

.github/workflows/ci.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,51 @@ jobs:
121121
cargo test -p plotly_static --features chromedriver,webdriver_download
122122
fi
123123
124+
test-macos-compatibility:
125+
name: Test macOS Compatibility
126+
runs-on: macos-latest
127+
steps:
128+
- uses: actions/checkout@v4
129+
130+
- name: Setup Chrome
131+
uses: browser-actions/setup-chrome@v1
132+
with:
133+
chrome-version: 'latest'
134+
install-chromedriver: true
135+
136+
- uses: dtolnay/rust-toolchain@stable
137+
138+
- name: Test Chrome and chromedriver installation
139+
run: |
140+
echo "Checking Chrome installation..."
141+
ls -la "/Applications/Google Chrome.app/Contents/MacOS/" || echo "Chrome not found in Applications"
142+
which google-chrome || echo "Chrome not found in PATH"
143+
144+
echo "Checking chromedriver installation..."
145+
chromedriver --version || echo "chromedriver not found in PATH"
146+
ls -la /usr/local/bin/chromedriver || echo "chromedriver not found in /usr/local/bin"
147+
ls -la /opt/homebrew/bin/chromedriver || echo "chromedriver not found in /opt/homebrew/bin"
148+
149+
- name: Run macOS-specific tests
150+
run: |
151+
echo "Running macOS compatibility tests..."
152+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_chrome_installation
153+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_chromedriver_installation
154+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_static_exporter_creation_macos
155+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_basic_png_export_macos
156+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_macos_chrome_flags
157+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib macos_tests::macos_tests::test_user_data_directory_management
158+
159+
- name: Run all plotly_static tests on macOS
160+
run: |
161+
echo "Running all plotly_static tests on macOS..."
162+
cargo test -p plotly_static --features chromedriver,webdriver_download --lib
163+
164+
- name: Test plotly with static export on macOS
165+
run: |
166+
echo "Testing plotly with static export on macOS..."
167+
cargo test -p plotly --features static_export_chromedriver,static_export_downloader --lib
168+
124169
code-coverage:
125170
name: Code Coverage
126171
runs-on: ubuntu-latest

plotly_static/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,10 @@ const DEFAULT_CAPS_ARRAY: [&str; 20] = [
288288
mod template;
289289
mod webdriver;
290290

291+
#[cfg(test)]
292+
#[cfg(target_os = "macos")]
293+
mod macos_tests;
294+
291295
/// Supported image formats for static image export.
292296
///
293297
/// This enum defines all the image formats that can be exported from Plotly
@@ -701,9 +705,7 @@ impl Drop for StaticExporter {
701705
// Clean up user data directory
702706
if let Some(ref user_data_dir) = self.user_data_dir {
703707
if let Err(e) = std::fs::remove_dir_all(user_data_dir) {
704-
warn!(
705-
"Failed to remove user data directory {user_data_dir:?}: {e}"
706-
);
708+
warn!("Failed to remove user data directory {user_data_dir:?}: {e}");
707709
} else {
708710
debug!("Cleaned up user data directory: {user_data_dir:?}");
709711
}

plotly_static/src/macos_tests.rs

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#[cfg(test)]
2+
#[cfg(target_os = "macos")]
3+
mod macos_tests {
4+
use std::path::Path;
5+
use std::process::Command;
6+
7+
use super::*;
8+
9+
/// Test that Google Chrome is installed and accessible
10+
#[test]
11+
fn test_chrome_installation() {
12+
let chrome_paths = [
13+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
14+
"/Applications/Chromium.app/Contents/MacOS/Chromium",
15+
];
16+
17+
let mut chrome_found = false;
18+
for path in &chrome_paths {
19+
if Path::new(path).exists() {
20+
println!("Found Chrome at: {}", path);
21+
chrome_found = true;
22+
break;
23+
}
24+
}
25+
26+
if !chrome_found {
27+
// Try to find Chrome using 'which' command
28+
if let Ok(output) = Command::new("which").arg("google-chrome").output() {
29+
if output.status.success() {
30+
let path = String::from_utf8_lossy(&output.stdout).trim();
31+
println!("Found Chrome via 'which': {}", path);
32+
chrome_found = true;
33+
}
34+
}
35+
}
36+
37+
if !chrome_found {
38+
// Try to find Chrome using 'mdfind' (macOS Spotlight)
39+
if let Ok(output) = Command::new("mdfind")
40+
.args(["-name", "Google Chrome.app"])
41+
.output()
42+
{
43+
if output.status.success() {
44+
let paths = String::from_utf8_lossy(&output.stdout);
45+
for path in paths.lines() {
46+
let chrome_binary = format!("{}/Contents/MacOS/Google Chrome", path.trim());
47+
if Path::new(&chrome_binary).exists() {
48+
println!("Found Chrome via Spotlight: {}", chrome_binary);
49+
chrome_found = true;
50+
break;
51+
}
52+
}
53+
}
54+
}
55+
}
56+
57+
assert!(
58+
chrome_found,
59+
"Google Chrome not found on macOS. Please install Chrome or Chromium."
60+
);
61+
}
62+
63+
/// Test that chromedriver is installed and can be executed
64+
#[test]
65+
fn test_chromedriver_installation() {
66+
// Check if chromedriver is in PATH
67+
let mut chromedriver_found = false;
68+
69+
if let Ok(output) = Command::new("chromedriver").arg("--version").output() {
70+
if output.status.success() {
71+
let version = String::from_utf8_lossy(&output.stdout);
72+
println!("Found chromedriver: {}", version.trim());
73+
chromedriver_found = true;
74+
}
75+
}
76+
77+
// Check common installation paths
78+
let chromedriver_paths = [
79+
"/usr/local/bin/chromedriver",
80+
"/opt/homebrew/bin/chromedriver",
81+
"/usr/bin/chromedriver",
82+
];
83+
84+
for path in &chromedriver_paths {
85+
if Path::new(path).exists() {
86+
println!("Found chromedriver at: {}", path);
87+
chromedriver_found = true;
88+
break;
89+
}
90+
}
91+
92+
assert!(
93+
chromedriver_found,
94+
"chromedriver not found on macOS. Please install chromedriver."
95+
);
96+
}
97+
98+
/// Test that we can create a StaticExporter with Chrome on macOS
99+
#[test]
100+
fn test_static_exporter_creation_macos() {
101+
let exporter = StaticExporterBuilder::default()
102+
.spawn_webdriver(true)
103+
.webdriver_port(4444)
104+
.build();
105+
106+
match exporter {
107+
Ok(_) => println!("Successfully created StaticExporter on macOS"),
108+
Err(e) => {
109+
// If it fails, it might be because port 4444 is in use
110+
// Try with a different port
111+
let exporter2 = StaticExporterBuilder::default()
112+
.spawn_webdriver(true)
113+
.webdriver_port(4445)
114+
.build();
115+
116+
match exporter2 {
117+
Ok(_) => {
118+
println!("Successfully created StaticExporter on macOS with port 4445")
119+
}
120+
Err(e2) => panic!(
121+
"Failed to create StaticExporter on macOS: {:?}, {:?}",
122+
e, e2
123+
),
124+
}
125+
}
126+
}
127+
}
128+
129+
/// Test basic PNG export functionality on macOS
130+
#[test]
131+
fn test_basic_png_export_macos() {
132+
let test_plot = serde_json::json!({
133+
"data": [{
134+
"type": "scatter",
135+
"x": [1, 2, 3, 4],
136+
"y": [10, 11, 12, 13]
137+
}],
138+
"layout": {
139+
"title": "macOS Test Plot"
140+
}
141+
});
142+
143+
let mut exporter = StaticExporterBuilder::default()
144+
.spawn_webdriver(true)
145+
.webdriver_port(4446)
146+
.build()
147+
.expect("Failed to create StaticExporter");
148+
149+
let result = exporter.write_to_string(&test_plot, ImageFormat::PNG, 800, 600, 1.0);
150+
151+
match result {
152+
Ok(data) => {
153+
assert!(!data.is_empty(), "PNG export returned empty data");
154+
assert!(data.len() > 100, "PNG export data seems too small");
155+
println!("Successfully exported PNG on macOS ({} bytes)", data.len());
156+
}
157+
Err(e) => {
158+
panic!("Failed to export PNG on macOS: {:?}", e);
159+
}
160+
}
161+
}
162+
163+
/// Test that the macOS-specific Chrome flags are working
164+
#[test]
165+
fn test_macos_chrome_flags() {
166+
let exporter = StaticExporterBuilder::default()
167+
.spawn_webdriver(true)
168+
.webdriver_port(4447)
169+
.build()
170+
.expect("Failed to create StaticExporter");
171+
172+
// Check that the macOS-specific flags are in the browser capabilities
173+
let caps = exporter
174+
.build_webdriver_caps()
175+
.expect("Failed to build capabilities");
176+
177+
if let Some(args) = caps
178+
.get("goog:chromeOptions")
179+
.and_then(|opts| opts.get("args"))
180+
.and_then(|args| args.as_array())
181+
{
182+
let args_str: Vec<&str> = args.iter().filter_map(|arg| arg.as_str()).collect();
183+
184+
// Check for macOS-specific flags
185+
let required_flags = [
186+
"--enable-unsafe-swiftshader",
187+
"--use-mock-keychain",
188+
"--password-store=basic",
189+
"--disable-web-security",
190+
];
191+
192+
for flag in &required_flags {
193+
assert!(
194+
args_str.contains(flag),
195+
"Missing required macOS flag: {}",
196+
flag
197+
);
198+
}
199+
200+
println!("All required macOS Chrome flags are present");
201+
} else {
202+
panic!("Could not extract Chrome arguments from capabilities");
203+
}
204+
}
205+
206+
/// Test that user data directories are properly created and cleaned up
207+
#[test]
208+
fn test_user_data_directory_management() {
209+
use std::sync::atomic::{AtomicU32, Ordering};
210+
static PORT_COUNTER: AtomicU32 = AtomicU32::new(4448);
211+
212+
let port = PORT_COUNTER.fetch_add(1, Ordering::SeqCst);
213+
214+
let exporter = StaticExporterBuilder::default()
215+
.spawn_webdriver(true)
216+
.webdriver_port(port)
217+
.build()
218+
.expect("Failed to create StaticExporter");
219+
220+
// Check that user data directory was created
221+
assert!(
222+
exporter.user_data_dir.is_some(),
223+
"User data directory should be set"
224+
);
225+
226+
let user_data_dir = exporter.user_data_dir.as_ref().unwrap();
227+
assert!(
228+
user_data_dir.exists(),
229+
"User data directory should exist: {:?}",
230+
user_data_dir
231+
);
232+
233+
println!(
234+
"User data directory created successfully: {:?}",
235+
user_data_dir
236+
);
237+
238+
// The directory should be cleaned up when exporter is dropped
239+
// We can't easily test this in a single test, but we can verify it
240+
// exists
241+
}
242+
}

0 commit comments

Comments
 (0)