-
-
Notifications
You must be signed in to change notification settings - Fork 204
Expand file tree
/
Copy pathdataFetching.test.ts
More file actions
90 lines (80 loc) · 2.57 KB
/
Copy pathdataFetching.test.ts
File metadata and controls
90 lines (80 loc) · 2.57 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
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { useStore } from './store'
import { authFetch } from './dataFetching'
import type { LoginStatus } from './store/types'
function mockFetchStatus(status: number) {
vi.stubGlobal(
'fetch',
vi.fn().mockResolvedValue({
ok: status >= 200 && status < 300,
status,
json: () => Promise.resolve({})
} as Response)
)
}
const loggedIn: LoginStatus = {
status: 'loggedIn',
authenticationRequired: true,
username: 'admin',
authProviders: [
{
id: 'oidc',
name: 'SSO Login',
loginUrl: '/signalk/v1/auth/oidc/login',
autoLogin: false
}
]
}
describe('authFetch 401 handling', () => {
beforeEach(() => {
useStore.setState({ loginStatus: { ...loggedIn } })
})
afterEach(() => {
vi.unstubAllGlobals()
})
it('flips loggedIn -> notLoggedIn on 401 from a non-login URL', async () => {
mockFetchStatus(401)
await authFetch('/signalk/v1/plugins')
const ls = useStore.getState().loginStatus
expect(ls.status).toBe('notLoggedIn')
expect(ls.username).toBeUndefined()
// Server settings preserved across the credential expiry.
expect(ls.authenticationRequired).toBe(true)
expect(ls.authProviders).toEqual(loggedIn.authProviders)
})
it('does not touch loginStatus on 401 from /signalk/v1/auth/login', async () => {
mockFetchStatus(401)
await authFetch('/signalk/v1/auth/login', { method: 'POST' })
const ls = useStore.getState().loginStatus
expect(ls.status).toBe('loggedIn')
expect(ls.username).toBe('admin')
})
it('does not touch loginStatus on 200', async () => {
mockFetchStatus(200)
await authFetch('/signalk/v1/plugins')
const ls = useStore.getState().loginStatus
expect(ls.status).toBe('loggedIn')
expect(ls.username).toBe('admin')
})
it('is a no-op when already notLoggedIn (dedup under parallel 401 storm)', async () => {
const seed: LoginStatus = {
status: 'notLoggedIn',
authenticationRequired: true
}
useStore.setState({ loginStatus: seed })
mockFetchStatus(401)
await Promise.all([
authFetch('/signalk/v1/plugins'),
authFetch('/signalk/v1/webapps'),
authFetch('/signalk/v1/addons')
])
const ls = useStore.getState().loginStatus
expect(ls.status).toBe('notLoggedIn')
expect(ls.username).toBeUndefined()
// No stale fields leaked in from the spread path (which only runs
// when status was 'loggedIn').
expect(Object.keys(ls).sort()).toEqual(
['authenticationRequired', 'status'].sort()
)
})
})