KAN-51: add isolated Tauri macOS app scaffold

This commit is contained in:
2026-09-26 18:41:04 +00:00
parent 7e19364757
commit 2a56d03dbf
21 changed files with 5267 additions and 1 deletions
+107
View File
@@ -0,0 +1,107 @@
#[cfg(target_os = "macos")]
fn main() {
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use tauri::{webview::PageLoadEvent, Manager};
let complete = Arc::new(AtomicBool::new(false));
let passed = Arc::new(AtomicBool::new(false));
let navigation_complete = complete.clone();
let navigation_passed = passed.clone();
let plugin = tauri::plugin::Builder::<tauri::Wry>::new("macos-smoke")
.js_init_script("window.__nativeSmokeErrors = []; window.addEventListener('error', event => window.__nativeSmokeErrors.push(event.message || event.target.src), true);")
.on_page_load(|webview, payload| {
if payload.event() != PageLoadEvent::Finished {
return;
}
if webview.label() == "launcher" {
webview.eval(r#"
(async () => {
for (let attempt = 0; attempt < 100; attempt++) {
if (document.querySelector('.open-workspace')?.textContent === 'Open workspace') break;
await new Promise(resolve => setTimeout(resolve, 100));
}
const link = document.querySelector('.open-workspace');
const appearance = document.querySelector('#appearance');
const translated = link?.textContent === 'Open workspace';
appearance.value = 'dark';
appearance.dispatchEvent(new Event('change'));
const dark = getComputedStyle(document.documentElement).backgroundColor === 'rgb(15, 23, 42)';
appearance.value = 'light';
appearance.dispatchEvent(new Event('change'));
const light = getComputedStyle(document.documentElement).backgroundColor === 'rgb(247, 249, 251)';
appearance.value = 'system';
appearance.dispatchEvent(new Event('change'));
if (translated && dark && light) {
link.click();
} else {
location.href = 'tauri://localhost/__native_smoke_result?passed=false&stage=launcher&translated=' + translated + '&dark=' + dark + '&light=' + light + '&background=' + encodeURIComponent(getComputedStyle(document.documentElement).backgroundColor) + '&label=' + encodeURIComponent(link?.textContent) + '&errors=' + encodeURIComponent(JSON.stringify(window.__nativeSmokeErrors));
}
})();
"#).unwrap();
} else if webview.label() == "workspace" {
webview.eval(r#"
(async () => {
for (let attempt = 0; attempt < 100; attempt++) {
if (document.querySelector('#app')?.innerText.trim().length > 100) break;
await new Promise(resolve => setTimeout(resolve, 100));
}
const root = document.querySelector('#app');
const rendered = root?.innerText.trim().length > 100 && root.getBoundingClientRect().height > 0;
let denied = true;
for (const cmd of ['plugin:path|resolve_directory', 'plugin:window|get_all_windows']) {
try {
await window.__TAURI_INTERNALS__.invoke(cmd);
denied = false;
} catch (error) {
denied = denied && String(error).includes('not allowed');
}
}
const noGlobalApi = typeof window.__TAURI__ === 'undefined';
const report = new URL('/__native_smoke_result', location.origin);
report.searchParams.set('passed', String(rendered && denied && noGlobalApi));
report.searchParams.set('rendered', String(rendered));
report.searchParams.set('nativeDenied', String(denied));
report.searchParams.set('globalAbsent', String(noGlobalApi));
location.href = report.href;
})();
"#).unwrap();
}
})
.on_navigation(move |webview, url| {
if url.path() != "/__native_smoke_result" {
return true;
}
let success = url.query_pairs().any(|(key, value)| key == "passed" && value == "true");
println!("macOS WebView smoke test: {}", url.query().unwrap_or_default());
navigation_passed.store(success, Ordering::SeqCst);
navigation_complete.store(true, Ordering::SeqCst);
webview.app_handle().exit(if success { 0 } else { 1 });
false
})
.build();
let app = kanbangit_native::builder()
.plugin(plugin)
.build(kanbangit_native::context())
.expect("The macOS application must start");
let handle = app.handle().clone();
std::thread::spawn(move || {
std::thread::sleep(std::time::Duration::from_secs(30));
if !complete.load(Ordering::SeqCst) {
eprintln!("macOS smoke test timed out before the server UI rendered");
handle.exit(1);
}
});
app.run_return(|_, _| {});
assert!(
passed.load(Ordering::SeqCst),
"The native smoke test must complete successfully"
);
}
#[cfg(not(target_os = "macos"))]
fn main() {
panic!("Run this smoke test on macOS with an active graphical session");
}