fix(app): reload webview instead of restart_app in dev mode (#1068) (#1071)

This commit is contained in:
oxoxDev
2026-05-01 17:45:34 -07:00
committed by GitHub
parent 37cf31bcac
commit fbd4c7ee11
2 changed files with 73 additions and 2 deletions
+56 -2
View File
@@ -1,5 +1,5 @@
import { invoke, isTauri } from '@tauri-apps/api/core';
import { beforeEach, describe, expect, type Mock, test, vi } from 'vitest';
import { afterEach, beforeEach, describe, expect, type Mock, test, vi } from 'vitest';
vi.mock('@tauri-apps/api/core', () => ({ invoke: vi.fn(), isTauri: vi.fn() }));
vi.mock('../../services/coreRpcClient', () => ({ callCoreRpc: vi.fn() }));
@@ -19,6 +19,30 @@ describe('tauriCommands/core', () => {
});
describe('restartApp', () => {
// window.location.reload is non-configurable on jsdom's default location;
// swap in a mocked location object for the dev-mode tests and restore after.
let originalLocation: Location;
let reloadSpy: Mock;
beforeEach(() => {
originalLocation = window.location;
reloadSpy = vi.fn();
Object.defineProperty(window, 'location', {
value: { ...originalLocation, reload: reloadSpy },
configurable: true,
writable: true,
});
});
afterEach(() => {
Object.defineProperty(window, 'location', {
value: originalLocation,
configurable: true,
writable: true,
});
vi.unstubAllEnvs();
});
test('no-ops when not in Tauri', async () => {
mockIsTauri.mockReturnValue(false);
const debug = vi.spyOn(console, 'debug').mockImplementation(() => {});
@@ -26,15 +50,45 @@ describe('tauriCommands/core', () => {
await restartApp();
expect(mockInvoke).not.toHaveBeenCalled();
expect(reloadSpy).not.toHaveBeenCalled();
expect(debug).toHaveBeenCalledWith(
expect.stringContaining('restartApp: skipped — not running in Tauri')
);
debug.mockRestore();
});
test('invokes restart_app when in Tauri', async () => {
test('reloads webview in dev mode (#1068 — avoid orphaning vite)', async () => {
// setup.ts seeds DEV=true globally; the binding imported above already
// captured that value, so we just need to invoke the dev-mode branch.
const debug = vi.spyOn(console, 'debug').mockImplementation(() => {});
await restartApp();
expect(reloadSpy).toHaveBeenCalledTimes(1);
expect(mockInvoke).not.toHaveBeenCalled();
expect(debug).toHaveBeenCalledWith(
expect.stringContaining('restartApp: dev mode → window.location.reload()')
);
debug.mockRestore();
});
test('invokes restart_app in production mode (IS_DEV=false)', async () => {
// setup.ts globally mocks ../config with IS_DEV: true. Override with
// doMock + resetModules so a fresh import of ./core sees IS_DEV=false
// and runs the production branch (#1068 dev workaround should be inert).
vi.doMock('../config', () => ({
IS_DEV: false,
// Re-export anything else core.ts might end up using; today just IS_DEV.
}));
vi.resetModules();
const prodCore = await import('./core');
await prodCore.restartApp();
expect(mockInvoke).toHaveBeenCalledWith('restart_app');
expect(reloadSpy).not.toHaveBeenCalled();
vi.doUnmock('../config');
});
});
+17
View File
@@ -4,6 +4,7 @@
import { invoke } from '@tauri-apps/api/core';
import { callCoreRpc } from '../../services/coreRpcClient';
import { IS_DEV } from '../config';
import { CommandResponse, isTauri } from './common';
export interface CoreUpdateStatus {
@@ -61,12 +62,28 @@ export async function restartCoreProcess(): Promise<void> {
/**
* Restart the desktop shell so CEF relaunches with updated profile paths.
*
* In `pnpm dev:app` the launcher graph is:
* `pnpm tauri dev` → `cargo run` → `tauri-cef` CLI → `vite` (child).
* Tauri's `app.restart()` exits the cargo parent, which orphans/kills the
* vite child and tears down the entire dev session (#1068). Use a webview
* reload in dev mode instead — module init re-runs, so localStorage seeds
* (e.g. `OPENHUMAN_ACTIVE_USER_ID`, set by `setActiveUserId` before the
* caller invokes us) are read fresh and redux-persist re-hydrates from
* the active user's namespace, all without touching the cargo / vite
* processes. Packaged builds keep the original `app.restart()` path —
* there is no vite child to orphan there.
*/
export async function restartApp(): Promise<void> {
if (!isTauri()) {
console.debug('[app] restartApp: skipped — not running in Tauri');
return;
}
if (IS_DEV) {
console.debug('[app] restartApp: dev mode → window.location.reload()');
window.location.reload();
return;
}
console.debug('[app] restartApp: invoking restart_app');
await invoke<void>('restart_app');
}