| import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest' |
| import { defineComponent, h } from 'vue' |
| import { mount } from '@vue/test-utils' |
| import { useWakeLock } from './useWakeLock' |
|
|
| |
| |
| |
| |
| |
| function mountWakeLock() { |
| let exposed |
| const Host = defineComponent({ |
| setup() { |
| exposed = useWakeLock() |
| return () => h('div') |
| }, |
| }) |
| const wrapper = mount(Host) |
| return { wrapper, ...exposed } |
| } |
|
|
| describe('useWakeLock', () => { |
| let originalWakeLock |
| let wrapper |
|
|
| beforeEach(() => { |
| originalWakeLock = navigator.wakeLock |
| }) |
|
|
| afterEach(() => { |
| wrapper?.unmount() |
| wrapper = undefined |
| if (originalWakeLock === undefined) delete navigator.wakeLock |
| else Object.defineProperty(navigator, 'wakeLock', { value: originalWakeLock, configurable: true }) |
| vi.restoreAllMocks() |
| }) |
|
|
| it('does nothing when the Wake Lock API is not supported', async () => { |
| delete navigator.wakeLock |
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await expect(result.acquireWakeLock()).resolves.toBeUndefined() |
| await expect(result.releaseWakeLock()).resolves.toBeUndefined() |
| }) |
|
|
| it('acquires and releases a wake lock when supported', async () => { |
| const release = vi.fn().mockResolvedValue(undefined) |
| const mockLock = { addEventListener: vi.fn(), release } |
| Object.defineProperty(navigator, 'wakeLock', { |
| value: { request: vi.fn().mockResolvedValue(mockLock) }, |
| configurable: true, |
| }) |
|
|
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await result.acquireWakeLock() |
| expect(navigator.wakeLock.request).toHaveBeenCalledWith('screen') |
|
|
| await result.releaseWakeLock() |
| expect(release).toHaveBeenCalled() |
| }) |
|
|
| it('does not request a second lock while one is already held', async () => { |
| const mockLock = { addEventListener: vi.fn(), release: vi.fn().mockResolvedValue(undefined) } |
| const request = vi.fn().mockResolvedValue(mockLock) |
| Object.defineProperty(navigator, 'wakeLock', { value: { request }, configurable: true }) |
|
|
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await result.acquireWakeLock() |
| await result.acquireWakeLock() |
| expect(request).toHaveBeenCalledTimes(1) |
| await result.releaseWakeLock() |
| }) |
|
|
| it('silently ignores a rejected wake lock request', async () => { |
| Object.defineProperty(navigator, 'wakeLock', { |
| value: { request: vi.fn().mockRejectedValue(new Error('denied')) }, |
| configurable: true, |
| }) |
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await expect(result.acquireWakeLock()).resolves.toBeUndefined() |
| await result.releaseWakeLock() |
| }) |
|
|
| it('releaseWakeLock is a no-op when no lock is held', async () => { |
| delete navigator.wakeLock |
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await expect(result.releaseWakeLock()).resolves.toBeUndefined() |
| }) |
|
|
| it('re-acquires the lock when the tab becomes visible again after wanting one', async () => { |
| const mockLock = { addEventListener: vi.fn(), release: vi.fn().mockResolvedValue(undefined) } |
| const request = vi.fn().mockResolvedValue(mockLock) |
| Object.defineProperty(navigator, 'wakeLock', { value: { request }, configurable: true }) |
|
|
| const result = mountWakeLock() |
| wrapper = result.wrapper |
| await result.acquireWakeLock() |
| |
| const releaseCallback = mockLock.addEventListener.mock.calls[0][1] |
| releaseCallback() |
|
|
| Object.defineProperty(document, 'visibilityState', { value: 'visible', configurable: true }) |
| document.dispatchEvent(new Event('visibilitychange')) |
| |
| await Promise.resolve() |
| await Promise.resolve() |
| expect(request).toHaveBeenCalledTimes(2) |
| await result.releaseWakeLock() |
| }) |
|
|
| it('cleans up the visibility listener and releases the lock on unmount', async () => { |
| const release = vi.fn().mockResolvedValue(undefined) |
| const mockLock = { addEventListener: vi.fn(), release } |
| Object.defineProperty(navigator, 'wakeLock', { |
| value: { request: vi.fn().mockResolvedValue(mockLock) }, |
| configurable: true, |
| }) |
| const removeSpy = vi.spyOn(document, 'removeEventListener') |
|
|
| const result = mountWakeLock() |
| await result.acquireWakeLock() |
| result.wrapper.unmount() |
| wrapper = undefined |
|
|
| expect(removeSpy).toHaveBeenCalledWith('visibilitychange', expect.any(Function)) |
| expect(release).toHaveBeenCalled() |
| }) |
| }) |
|
|