mirror of
https://github.com/hanzoai/desktop.git
synced 2026-10-30 14:58:42 +00:00
* chore(deps): bump Tauri to 2.11 + all deps to latest within-major
Forwards-only, within-major dependency refresh across the JS and Rust
trees. No major-version crossings.
Tauri (Rust + JS kept mutually consistent):
- tauri 2.4 -> 2.11.3, tauri-build 2.4 -> 2.6, plugins -> latest 2.x
(dialog 2.7, fs 2.5, log 2.8, updater 2.10, deep-link 2.4, ...).
- @tauri-apps/api 2.11.1, cli 2.11.3, plugin-* aligned to the same 2.x.
- gen/schemas regenerated for the new plugin ACL permissions.
JS: raised all caret ranges to highest-within-major (radix-ui, tanstack,
framer-motion 12.41, zod 3.25, vite 6.4.3, vitest 4.1.9, typescript 5.9.3,
typescript-eslint 8.62, eslint 9.39, @types/node 20.19.43, ...). pnpm
install + dedupe; package-lock.json regenerated to match (npm-ci CI path).
React pin preserved: react & react-dom stay exactly 19.0.6 (kept equal to
avoid the React reconciler mismatch / blank-app failure mode).
pnpm.overrides added (pnpm ignored the npm-style top-level `overrides`):
- @radix-ui/react-primitive pinned 2.1.4 — 2.1.5+ adds a global
`declare module 'react'` CSSProperties augmentation (`--radix-${string}`)
that breaks rjsf StyleHTMLAttributes typing; the pin keeps every radix
component bump while dropping just the breaking transitive augmentation.
Held at safe boundary (would increase the typecheck error count):
- react-error-boundary held at ~6.0.3 (6.1.x retypes FallbackProps.error
Error -> unknown, breaking the app's typed fallbacks).
Verification (baseline = origin/main):
- frontend `tsc -b`: 34 -> 33 errors (0 new; 1 pre-existing fixed by
@types/node bump). Constraint "must not increase" satisfied.
- `cargo check` (src-tauri): 0 errors / 71 warnings, unchanged from baseline.
* test(e2e): real Tauri E2E harness (tauri-driver + WebdriverIO), decomplected from frontend smoke
The existing e2e-tests/*.spec.ts (Playwright `page.goto(:1420)`) drive the Vite
frontend in Chromium with NO Tauri IPC. That's frontend smoke, not E2E. This
adds the canonical Tauri 2.x E2E: tauri-driver launches the real hanzo-desktop
binary and WebdriverIO drives the native WebKit webview over WebDriver — real
window, real `window.__TAURI_INTERNALS__`, real commands.
Decomplected — one script per intent, no duplication:
- `pnpm test:e2e` -> wdio, real native app (apps/hanzo-desktop/e2e/)
- `pnpm test:smoke` -> playwright frontend smoke (apps/hanzo-desktop/e2e-tests/)
Playwright config + e2e-tests/README relabelled "frontend smoke — NOT Tauri E2E".
Harness (DRY):
- wdio.conf.ts (app root): capability is `tauri:options.application` ->
src-tauri/target/debug/hanzo-desktop, NO browserName (tauri-driver forwards an
unknown browserName to WebKitWebDriver otherwise). Spawns/kills tauri-driver in
beforeSession/afterSession/onComplete, frees stale ports, kills the driver's
native-driver child via its process group. ESM-safe (__dirname from
import.meta.url; the repo is "type":"module"). Headless on DISPLAY=:1.
- tsconfig.e2e.json: own TS project (node + DOM + @wdio/globals) so the specs
typecheck and stay out of the app's tsconfig.app/spec.
- e2e/helpers.ts: shared waitForAppMounted / navigateTo (client-side history,
the app uses BrowserRouter) / restoreSignedInSession (seeds the REAL persisted
zustand stores for a returning cloud user — unlocks ProtectedRoutes with no
IPC/behaviour mocks).
- Specs (minimal but real, no mocks): app-load (window + #root mount +
__TAURI_INTERNALS__ + onboarding), login (Login button gates on terms
checkbox), models (local "Zen Engine" surface + chat composer), chat (real
composer round-trip), mining (mining-page, on-chain/pending balances,
4-tier privacy selector, recent-proofs).
- e2e/README.md: how to run (needs webkit2gtk-driver + tauri-driver + a debug
build), macOS-unsupported caveat.
Deps: @wdio/{cli,local-runner,mocha-framework,spec-reporter,globals,types}
^9.29.0 (devDeps, within-major). pnpm + package-lock both updated.
Verified: config + specs typecheck (tsc -p tsconfig.e2e.json = 0 errors); app
typecheck unchanged at 33 (no e2e leakage); eslint ignores the e2e suites (their
own tsconfigs) — also clears the pre-existing e2e-tests parse error; tauri-driver
+ WebKitWebDriver present, debug binary builds & launches, wdio reaches session
creation. NOT faked green: on this box's bleeding-edge WebKitGTK 2.52.3 the
tauri-driver automation handshake hangs (IncompleteMessage / HEADERS_TIMEOUT) —
an upstream WebKitGTK>=2.46 issue, documented in e2e/README.md with mitigations.
84 lines
3.0 KiB
TypeScript
84 lines
3.0 KiB
TypeScript
// Shared, DRY helpers for the real-Tauri (WebdriverIO) suite. No mocks: these
|
|
// only drive the real app — wait for first paint, navigate the hash router, and
|
|
// (for the post-onboarding surfaces) restore a real persisted session exactly
|
|
// as the app itself would on a returning launch.
|
|
import { browser, $, expect } from '@wdio/globals';
|
|
|
|
/** The app mounts React here (apps/hanzo-desktop/index.html). */
|
|
export const ROOT = '#root';
|
|
|
|
/** Wait until the native webview has booted and React has mounted content. */
|
|
export async function waitForAppMounted(): Promise<void> {
|
|
const root = await $(ROOT);
|
|
await root.waitForExist({ timeout: 60000 });
|
|
// React has rendered *something* (not an empty shell) — proves the real
|
|
// bundle ran inside the Tauri webview, not just a blank window.
|
|
await browser.waitUntil(
|
|
async () =>
|
|
(await root.getHTML({ includeSelectorTag: false })).trim().length > 0,
|
|
{ timeout: 60000, timeoutMsg: 'React never rendered into #root' },
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Seed the *real* persisted zustand stores so the app boots as a returning,
|
|
* signed-in user with onboarding finished — the same localStorage envelope the
|
|
* app writes itself. This unlocks the ProtectedRoute surfaces (home, chat,
|
|
* mining) WITHOUT mocking any IPC or component behaviour. Cloud mode
|
|
* (`hanzo_token` present) is used so no local node spawn is required.
|
|
*
|
|
* Onboarding is just two required steps (terms-conditions, analytics); marking
|
|
* both completed makes `isOnboardingComplete()` true.
|
|
*/
|
|
export async function restoreSignedInSession(): Promise<void> {
|
|
await browser.execute(() => {
|
|
const auth = {
|
|
state: {
|
|
auth: {
|
|
profile: 'main',
|
|
node_address: 'http://127.0.0.1:9850',
|
|
hanzo_identity: '@@hanzo_e2e.sep-hanzo',
|
|
encryption_pk: 'e2e',
|
|
identity_pk: 'e2e',
|
|
api_v2_key: 'e2e-api-key',
|
|
hanzo_token: 'e2e-cloud-token',
|
|
hanzo_refresh_token: 'e2e-refresh-token',
|
|
},
|
|
},
|
|
version: 0,
|
|
};
|
|
const settings = {
|
|
state: {
|
|
onboarding: {
|
|
steps: {
|
|
'terms-conditions': { completed: true, choice: true },
|
|
analytics: { completed: true, choice: true },
|
|
},
|
|
},
|
|
defaultAgentId: '',
|
|
},
|
|
version: 0,
|
|
};
|
|
localStorage.setItem('auth', JSON.stringify(auth));
|
|
localStorage.setItem('settings', JSON.stringify(settings));
|
|
});
|
|
await browser.refresh();
|
|
await waitForAppMounted();
|
|
}
|
|
|
|
/**
|
|
* Navigate the in-app router (react-router `BrowserRouter`) to a path using
|
|
* client-side history — pushState + a `popstate` event, which react-router
|
|
* listens to — so we stay inside the real SPA instead of triggering a full
|
|
* document load the embedded protocol can't serve.
|
|
*/
|
|
export async function navigateTo(routePath: string): Promise<void> {
|
|
await browser.execute((p: string) => {
|
|
window.history.pushState({}, '', p);
|
|
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
}, routePath);
|
|
await waitForAppMounted();
|
|
}
|
|
|
|
export { browser, $, expect };
|