forked from OurHike/OurHike
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuseInstallPrompt.test.ts
More file actions
134 lines (105 loc) · 4.04 KB
/
Copy pathuseInstallPrompt.test.ts
File metadata and controls
134 lines (105 loc) · 4.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { describe, it, expect, vi, afterEach } from 'vitest'
import { renderHook, act } from '@testing-library/react'
import { detectInstallPlatform, isStandalone, useInstallPrompt } from './useInstallPrompt'
function stubUserAgent(ua: string, platform = 'Linux', maxTouchPoints = 0) {
vi.stubGlobal('navigator', {
userAgent: ua,
platform,
maxTouchPoints,
onLine: true,
})
}
function stubDisplayMode(standalone: boolean) {
vi.stubGlobal('matchMedia', (query: string) => ({
matches: standalone && query.includes('standalone'),
media: query,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
}))
}
afterEach(() => {
vi.unstubAllGlobals()
vi.clearAllMocks()
})
describe('detectInstallPlatform', () => {
it('recognises Android', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
expect(detectInstallPlatform()).toBe('android')
})
it('recognises an iPhone', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (iPhone; CPU iPhone OS 17_0) Version/17.0 Safari')
expect(detectInstallPlatform()).toBe('ios')
})
it('recognises an iPad, which reports itself as a Mac', () => {
// iPadOS 13+ sends a desktop Safari UA. Without the touch-point check an
// iPad would be told it is a computer and never see the install steps.
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari', 'MacIntel', 5)
expect(detectInstallPlatform()).toBe('ios')
})
it('does not mistake a real Mac for an iPad', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) Safari', 'MacIntel', 0)
expect(detectInstallPlatform()).toBe('other')
})
it('reports an installed app as installed, whatever the platform', () => {
stubDisplayMode(true)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
expect(detectInstallPlatform()).toBe('installed')
})
})
describe('isStandalone', () => {
it("trusts Safari's own flag, the only signal iOS gives", () => {
stubDisplayMode(false)
vi.stubGlobal('navigator', {
userAgent: 'iPhone',
platform: 'iPhone',
standalone: true,
})
expect(isStandalone()).toBe(true)
})
})
describe('useInstallPrompt', () => {
it('offers no prompt until the browser says the page qualifies', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
const { result } = renderHook(() => useInstallPrompt())
expect(result.current.canPrompt).toBe(false)
})
it('offers a prompt once beforeinstallprompt fires, and suppresses the browser bar', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
const { result } = renderHook(() => useInstallPrompt())
const event = new Event('beforeinstallprompt')
const preventDefault = vi.spyOn(event, 'preventDefault')
act(() => {
window.dispatchEvent(event)
})
expect(result.current.canPrompt).toBe(true)
// Chrome shows its own mini-infobar otherwise; the app asks at a moment it
// chooses, on the Downloads screen.
expect(preventDefault).toHaveBeenCalled()
})
it('stops offering to install once the app is installed', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
const { result } = renderHook(() => useInstallPrompt())
act(() => {
window.dispatchEvent(new Event('beforeinstallprompt'))
})
expect(result.current.canPrompt).toBe(true)
act(() => {
window.dispatchEvent(new Event('appinstalled'))
})
expect(result.current.canPrompt).toBe(false)
expect(result.current.platform).toBe('installed')
})
it('does nothing when asked to install with no pending prompt', () => {
stubDisplayMode(false)
stubUserAgent('Mozilla/5.0 (Linux; Android 14; Pixel 8) Chrome/120')
const { result } = renderHook(() => useInstallPrompt())
expect(() => result.current.install()).not.toThrow()
})
})