Skip to content

Commit be54f28

Browse files
committed
test(desktop): cover minimized/hidden window-state + visibilitychange pause for GlyphSpinner
Regression coverage requested in review of NousResearch#74357: mock window.hermesDesktop.onWindowStateChanged (pattern from persistent.test.tsx) and assert minimized/hidden clears the spinner interval while restore resumes it; also cover document.visibilityState hidden/visible via visibilitychange.
1 parent 9a20d7f commit be54f28

1 file changed

Lines changed: 68 additions & 0 deletions

File tree

apps/desktop/src/components/ui/glyph-spinner.test.tsx

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,72 @@ describe('GlyphSpinner', () => {
9595
act(() => vi.advanceTimersByTime(80))
9696
expect(status.textContent).not.toBe(frozen)
9797
})
98+
99+
it('suspends animation while the Electron window is minimized or hidden, then resumes on restore', () => {
100+
let windowStateCallback: ((payload: { isMinimized?: boolean; isVisible?: boolean }) => void) | null = null
101+
102+
Object.defineProperty(window, 'hermesDesktop', {
103+
configurable: true,
104+
value: {
105+
onWindowStateChanged: vi.fn((callback: typeof windowStateCallback) => {
106+
windowStateCallback = callback
107+
108+
return () => {
109+
if (windowStateCallback === callback) {
110+
windowStateCallback = null
111+
}
112+
}
113+
})
114+
}
115+
})
116+
117+
try {
118+
render(<GlyphSpinner spinner="braille" />)
119+
120+
const status = screen.getByRole('status', { name: 'Loading' })
121+
expect(windowStateCallback).not.toBeNull()
122+
expect(vi.getTimerCount()).toBe(1)
123+
124+
act(() => windowStateCallback?.({ isMinimized: true, isVisible: false }))
125+
expect(vi.getTimerCount()).toBe(0)
126+
127+
const frozen = status.textContent
128+
act(() => vi.advanceTimersByTime(800))
129+
expect(status.textContent).toBe(frozen)
130+
131+
act(() => windowStateCallback?.({ isMinimized: false, isVisible: true }))
132+
expect(vi.getTimerCount()).toBe(1)
133+
134+
act(() => vi.advanceTimersByTime(80))
135+
expect(status.textContent).not.toBe(frozen)
136+
} finally {
137+
delete (window as unknown as { hermesDesktop?: unknown }).hermesDesktop
138+
}
139+
})
140+
141+
it('suspends animation while the document is hidden', () => {
142+
render(<GlyphSpinner spinner="braille" />)
143+
144+
const status = screen.getByRole('status', { name: 'Loading' })
145+
expect(vi.getTimerCount()).toBe(1)
146+
147+
Object.defineProperty(document, 'visibilityState', { configurable: true, value: 'hidden' })
148+
try {
149+
act(() => document.dispatchEvent(new Event('visibilitychange')))
150+
expect(vi.getTimerCount()).toBe(0)
151+
152+
const frozen = status.textContent
153+
act(() => vi.advanceTimersByTime(800))
154+
expect(status.textContent).toBe(frozen)
155+
156+
Object.defineProperty(document, 'visibilityState', { configurable: true, value: 'visible' })
157+
act(() => document.dispatchEvent(new Event('visibilitychange')))
158+
expect(vi.getTimerCount()).toBe(1)
159+
160+
act(() => vi.advanceTimersByTime(80))
161+
expect(status.textContent).not.toBe(frozen)
162+
} finally {
163+
Object.defineProperty(document, 'visibilityState', { configurable: true, value: 'visible' })
164+
}
165+
})
98166
})

0 commit comments

Comments
 (0)