openpencil/crates/op-host-web/tests/ci_workflow.rs
Kayshen-X a7d73ebb62 feat(ai): pencil-style agentic design tool-loop, multi-chat tabs, #27 panel restyle
Built-in design generation now runs as an agentic MCP tool-loop (reusing the
agent-rs BuiltInProvider), gated behind OPENPENCIL_DESIGN_AGENT_LOOP / the
Settings experimental toggle; the orchestrator stays the default.

- design-agent system prompt + in-process design toolset (parity-locked with
  the MCP surface) + flag-gated Intent::Design routing
- spawn_agents execution as sequential sub-loops + live creation-mode badges
  (per-agent glow + 'N/M designing...' header)
- new MCP tools: get_guidelines, ToolSearch, get_screenshot, get_editor_state,
  export_nodes, spawn_agents; style-guide local audit
- #27 AI panel restyle: rounded tool cards + green check-rings, gray user
  bubbles, model-pill bottom toolbar, header, empty-state pills, the
  PARALLEL AGENTS (agent_team_size) 1x-6x chip dropdown
- multi-chat tabs: ChatSessions model (Deref-to-active) + tab row UI
  (switch / close / + / Cmd+T) with each run bound to its tab

Large checkpoint commit spanning the working tree (Rust shell crates).
2026-07-02 21:21:06 +08:00

164 lines
5.7 KiB
Rust

#[test]
fn rust_check_runs_canvaskit_widget_host_tests() {
let workflow = std::fs::read_to_string(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../.github/workflows/rust-check.yml"
))
.expect("rust-check workflow is readable");
assert!(
workflow.contains("Run CanvasKit web host tests"),
"rust-check should name the CanvasKit web host test step"
);
assert!(
workflow.contains("cargo test -p op-host-web"),
"rust-check should run op-host-web tests explicitly"
);
assert!(
workflow.contains("--features canvaskit"),
"rust-check must enable the production CanvasKit web host feature"
);
}
#[test]
fn release_workflow_documents_current_canvaskit_bundle_path() {
let workflow = std::fs::read_to_string(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../.github/workflows/rust-release.yml"
))
.expect("rust-release workflow is readable");
assert!(
workflow.contains("wasm-bundle-build.yml"),
"release workflow notes should point at the current CanvasKit bundle workflow"
);
assert!(
!workflow.contains("--features skia"),
"release workflow must not describe the retired skia wasm build path"
);
assert!(
!workflow.contains("EMSDK"),
"release workflow must not describe the retired EMSDK wasm build path"
);
}
#[test]
fn web_smoke_page_uses_current_canvaskit_bundle_command() {
let smoke = std::fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/smoke/step-1b.html"))
.expect("web smoke page is readable");
assert!(
smoke.contains("--features canvaskit"),
"web smoke page should show the current CanvasKit bundle build command"
);
assert!(
smoke.contains("mod.mount_ck('op')"),
"web smoke page should mount the production CanvasKit shell"
);
assert!(
!smoke.contains("mod.mount('op')"),
"web smoke page must not mount the default wasm stub"
);
assert!(
!smoke.contains("--features skia"),
"web smoke page must not point users at the retired skia wasm build"
);
assert!(
!smoke.contains("EMSDK"),
"web smoke page must not require the retired EMSDK setup"
);
}
#[test]
fn web_integration_notes_avoid_legacy_ambiguous_markers() {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let files = [
"Cargo.toml",
"src/dom_io.rs",
"src/file_actions.rs",
"src/iconify_web.rs",
"src/lib.rs",
"src/live_sync.rs",
"src/raf_pump.rs",
"src/web_ai_transport.rs",
"src/web_chat.rs",
"src/web_clipboard.rs",
"src/web_fonts.rs",
];
for file in files {
let text = std::fs::read_to_string(manifest_dir.join(file))
.unwrap_or_else(|err| panic!("{file} is readable: {err}"));
assert!(
!text.contains("UNVERIFIED in-browser"),
"{file} should name the concrete smoke/daemon boundary instead of a blanket UNVERIFIED marker"
);
assert!(
!text.contains("EMSDK"),
"{file} should describe the current CanvasKit/web-sys boundary instead of the retired EMSDK path"
);
}
}
#[test]
fn browser_smoke_script_and_ci_cover_canvas_and_daemon_paths() {
let repo = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let script = std::fs::read_to_string(repo.join("tools/check-web-browser-smoke.sh"))
.expect("browser smoke script is readable");
let workflow = std::fs::read_to_string(repo.join(".github/workflows/wasm-bundle-build.yml"))
.expect("wasm bundle workflow is readable");
assert!(
script.contains("--dump-dom"),
"browser smoke should drive a real headless browser, not only curl"
);
assert!(
script.contains("/smoke/step-1b.html"),
"browser smoke should cover the pure CanvasKit mount harness"
);
assert!(
script.contains("/api/mcp/server"),
"browser smoke should cover the daemon health path"
);
assert!(
script.contains("data-op-smoke=\"ok\""),
"browser smoke should assert the DOM success marker written after mount"
);
assert!(
workflow.contains("tools/check-web-browser-smoke.sh"),
"bundle workflow should run the browser smoke after building the bundle"
);
}
#[test]
fn web_rust_publish_has_docker_and_start_script_entrypoints() {
let repo = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let dockerfile =
std::fs::read_to_string(repo.join("Dockerfile.web-rust")).expect("Dockerfile readable");
let start_script = std::fs::read_to_string(repo.join("scripts/start-web-rust.sh"))
.expect("web rust start script is readable");
let package =
std::fs::read_to_string(repo.join("package.json")).expect("package.json readable");
assert!(
dockerfile.contains("op-host-web-server --serve-web"),
"web Rust Docker image should publish through the headless serve-web daemon"
);
assert!(
start_script.contains("tools/check-wasm-bundle.sh"),
"start script should build or verify the deployable CanvasKit bundle"
);
assert!(
start_script.contains("op-host-web-server") && start_script.contains("--serve-web"),
"start script should publish through op-host-web-server --serve-web"
);
assert!(
start_script.contains("OPENPENCIL_WEB_BUNDLE_DIR"),
"start script should point the daemon at the built web bundle explicitly"
);
assert!(
package.contains("\"shell:web:serve\""),
"package scripts should expose the web Rust start script"
);
}