diff --git a/apps/desktop/src/store/zoom.test.ts b/apps/desktop/src/store/zoom.test.ts new file mode 100644 index 0000000000..5faadf2647 --- /dev/null +++ b/apps/desktop/src/store/zoom.test.ts @@ -0,0 +1,76 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const desktopWindow = window as unknown as { hermesDesktop?: Window['hermesDesktop'] } +const initialHermesDesktop = desktopWindow.hermesDesktop + +type ZoomBridge = NonNullable +type ZoomPayload = Awaited> + +function installZoomBridge(zoom: ZoomBridge): void { + desktopWindow.hermesDesktop = { zoom } as unknown as Window['hermesDesktop'] +} + +beforeEach(() => { + vi.resetModules() +}) + +afterEach(() => { + if (initialHermesDesktop) { + desktopWindow.hermesDesktop = initialHermesDesktop + } else { + delete desktopWindow.hermesDesktop + } +}) + +describe('zoom state sync', () => { + it('uses the initial read when no newer change has arrived', async () => { + const zoom: ZoomBridge = { + get: vi.fn().mockResolvedValue({ level: 1, percent: 125 }), + onChanged: vi.fn(() => vi.fn()), + setPercent: vi.fn() + } + + installZoomBridge(zoom) + + const { $zoomPercent } = await import('./zoom') + + expect($zoomPercent.get()).toBe(125) + }) + + it('does not let a stale initial read overwrite a newer zoom event', async () => { + const callOrder: string[] = [] + let emitChanged: ((payload: ZoomPayload) => void) | undefined + let resolveInitialRead: ((payload: ZoomPayload) => void) | undefined + + const initialRead = new Promise(resolve => { + resolveInitialRead = resolve + }) + + const zoom: ZoomBridge = { + get: vi.fn(() => { + callOrder.push('get') + + return initialRead + }), + onChanged: vi.fn(callback => { + callOrder.push('subscribe') + emitChanged = callback + + return vi.fn() + }), + setPercent: vi.fn() + } + + installZoomBridge(zoom) + + const { $zoomPercent } = await import('./zoom') + + expect(callOrder).toEqual(['subscribe', 'get']) + emitChanged?.({ level: 1, percent: 125 }) + resolveInitialRead?.({ level: 0, percent: 100 }) + await initialRead + await Promise.resolve() + + expect($zoomPercent.get()).toBe(125) + }) +}) diff --git a/apps/desktop/src/store/zoom.ts b/apps/desktop/src/store/zoom.ts index 821563acc4..81816fb01d 100644 --- a/apps/desktop/src/store/zoom.ts +++ b/apps/desktop/src/store/zoom.ts @@ -19,6 +19,17 @@ export function setZoomPercent(percent: number): void { } if (typeof window !== 'undefined' && window.hermesDesktop?.zoom) { - void window.hermesDesktop.zoom.get().then(({ percent }) => $zoomPercent.set(percent)) - window.hermesDesktop.zoom.onChanged(({ percent }) => $zoomPercent.set(percent)) + const zoom = window.hermesDesktop.zoom + let receivedZoomChange = false + + zoom.onChanged(({ percent }) => { + receivedZoomChange = true + $zoomPercent.set(percent) + }) + + void zoom.get().then(({ percent }) => { + if (!receivedZoomChange) { + $zoomPercent.set(percent) + } + }) }