mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
On iOS PWA (black-translucent + viewport-fit=cover), opening the virtual keyboard causes iOS to scroll the page upward, pushing the session header behind the system status bar. Fix by resetting window.scrollTo(0, 0) when the keyboard is detected open, and listening to visualViewport scroll events in addition to resize to catch any deferred scrolling. via [HAPI](https://hapi.run) Co-authored-by: HAPI <noreply@hapi.run>
107 lines
3.6 KiB
TypeScript
107 lines
3.6 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
/**
|
|
* Unit tests for the useViewportHeight hook logic.
|
|
*
|
|
* Because the hook depends on window.visualViewport (not available in jsdom),
|
|
* we test the core update logic directly rather than rendering the hook.
|
|
*/
|
|
describe('useViewportHeight update logic', () => {
|
|
const root = document.documentElement
|
|
|
|
beforeEach(() => {
|
|
root.style.removeProperty('--app-viewport-height')
|
|
})
|
|
|
|
afterEach(() => {
|
|
root.style.removeProperty('--app-viewport-height')
|
|
})
|
|
|
|
it('sets --app-viewport-height when visual viewport is smaller than window', () => {
|
|
// Simulate the update logic from the hook
|
|
const viewportHeight = 400
|
|
const windowHeight = 800
|
|
const diff = windowHeight - viewportHeight
|
|
if (diff > 1) {
|
|
root.style.setProperty('--app-viewport-height', `${viewportHeight}px`)
|
|
} else {
|
|
root.style.removeProperty('--app-viewport-height')
|
|
}
|
|
|
|
expect(root.style.getPropertyValue('--app-viewport-height')).toBe('400px')
|
|
})
|
|
|
|
it('removes --app-viewport-height when viewports match', () => {
|
|
// First set it
|
|
root.style.setProperty('--app-viewport-height', '400px')
|
|
|
|
// Then simulate keyboard close
|
|
const viewportHeight = 800
|
|
const windowHeight = 800
|
|
const diff = windowHeight - viewportHeight
|
|
if (diff > 1) {
|
|
root.style.setProperty('--app-viewport-height', `${viewportHeight}px`)
|
|
} else {
|
|
root.style.removeProperty('--app-viewport-height')
|
|
}
|
|
|
|
expect(root.style.getPropertyValue('--app-viewport-height')).toBe('')
|
|
})
|
|
|
|
it('ignores sub-pixel differences (threshold of 1px)', () => {
|
|
const viewportHeight = 799.5
|
|
const windowHeight = 800
|
|
const diff = windowHeight - viewportHeight
|
|
if (diff > 1) {
|
|
root.style.setProperty('--app-viewport-height', `${viewportHeight}px`)
|
|
} else {
|
|
root.style.removeProperty('--app-viewport-height')
|
|
}
|
|
|
|
expect(root.style.getPropertyValue('--app-viewport-height')).toBe('')
|
|
})
|
|
|
|
it('resets page scroll when keyboard is open', () => {
|
|
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {})
|
|
|
|
// Simulate: keyboard open AND page has been scrolled by iOS
|
|
Object.defineProperty(window, 'scrollY', { value: 120, configurable: true })
|
|
|
|
const viewportHeight = 400
|
|
const windowHeight = 800
|
|
const diff = windowHeight - viewportHeight
|
|
if (diff > 1) {
|
|
root.style.setProperty('--app-viewport-height', `${viewportHeight}px`)
|
|
if (window.scrollY > 0) {
|
|
window.scrollTo(0, 0)
|
|
}
|
|
}
|
|
|
|
expect(scrollToSpy).toHaveBeenCalledWith(0, 0)
|
|
|
|
// Cleanup
|
|
Object.defineProperty(window, 'scrollY', { value: 0, configurable: true })
|
|
scrollToSpy.mockRestore()
|
|
})
|
|
|
|
it('does not reset scroll when page is not scrolled', () => {
|
|
const scrollToSpy = vi.spyOn(window, 'scrollTo').mockImplementation(() => {})
|
|
|
|
Object.defineProperty(window, 'scrollY', { value: 0, configurable: true })
|
|
|
|
const viewportHeight = 400
|
|
const windowHeight = 800
|
|
const diff = windowHeight - viewportHeight
|
|
if (diff > 1) {
|
|
root.style.setProperty('--app-viewport-height', `${viewportHeight}px`)
|
|
if (window.scrollY > 0) {
|
|
window.scrollTo(0, 0)
|
|
}
|
|
}
|
|
|
|
expect(scrollToSpy).not.toHaveBeenCalled()
|
|
|
|
scrollToSpy.mockRestore()
|
|
})
|
|
})
|