login-authorization-v2 1.1.5 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/README.md +54 -54
  2. package/babel.config.js +6 -0
  3. package/coverage/clover.xml +140 -0
  4. package/coverage/coverage-final.json +8 -0
  5. package/coverage/lcov-report/base.css +224 -0
  6. package/coverage/lcov-report/block-navigation.js +87 -0
  7. package/coverage/lcov-report/common-authorization-v2/index.html +116 -0
  8. package/coverage/lcov-report/common-authorization-v2/index.ts.html +547 -0
  9. package/coverage/lcov-report/common-authorization-v2/src/compatible.ts.html +223 -0
  10. package/coverage/lcov-report/common-authorization-v2/src/constance.ts.html +106 -0
  11. package/coverage/lcov-report/common-authorization-v2/src/cookie.ts.html +346 -0
  12. package/coverage/lcov-report/common-authorization-v2/src/dom.ts.html +262 -0
  13. package/coverage/lcov-report/common-authorization-v2/src/index.html +206 -0
  14. package/coverage/lcov-report/common-authorization-v2/src/request.ts.html +361 -0
  15. package/coverage/lcov-report/common-authorization-v2/src/shares.ts.html +163 -0
  16. package/coverage/lcov-report/common-authorization-v2/src/types.ts.html +412 -0
  17. package/coverage/lcov-report/common-authorization-v2/src/utils.ts.html +145 -0
  18. package/coverage/lcov-report/compatible.ts.html +223 -0
  19. package/coverage/lcov-report/constance.ts.html +106 -0
  20. package/coverage/lcov-report/cookie.ts.html +310 -0
  21. package/coverage/lcov-report/dom.ts.html +262 -0
  22. package/coverage/lcov-report/favicon.png +0 -0
  23. package/coverage/lcov-report/index.html +206 -0
  24. package/coverage/lcov-report/prettify.css +1 -0
  25. package/coverage/lcov-report/prettify.js +2 -0
  26. package/coverage/lcov-report/shares.ts.html +163 -0
  27. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  28. package/coverage/lcov-report/sorter.js +210 -0
  29. package/coverage/lcov-report/types.ts.html +412 -0
  30. package/coverage/lcov-report/utils.ts.html +145 -0
  31. package/coverage/lcov.info +268 -0
  32. package/dist/compatible.d.ts +10 -0
  33. package/dist/compatible.d.ts.map +1 -0
  34. package/dist/constance.d.ts +6 -0
  35. package/dist/constance.d.ts.map +1 -0
  36. package/dist/cookie.d.ts +8 -0
  37. package/dist/cookie.d.ts.map +1 -0
  38. package/dist/dom.d.ts +2 -0
  39. package/dist/dom.d.ts.map +1 -0
  40. package/dist/index.d.ts +15 -0
  41. package/dist/index.d.ts.map +1 -0
  42. package/dist/index.esm.js +498 -0
  43. package/dist/index.js.LICENSE.txt +1 -0
  44. package/dist/{index.js → index.umd.js} +125 -14
  45. package/dist/request.d.ts +36 -0
  46. package/dist/request.d.ts.map +1 -0
  47. package/dist/shares.d.ts +10 -0
  48. package/dist/shares.d.ts.map +1 -0
  49. package/dist/src/compatible.d.ts +10 -0
  50. package/dist/src/compatible.d.ts.map +1 -0
  51. package/dist/src/constance.d.ts +8 -0
  52. package/dist/src/constance.d.ts.map +1 -0
  53. package/dist/src/cookie.d.ts +8 -0
  54. package/dist/src/cookie.d.ts.map +1 -0
  55. package/dist/src/dom.d.ts +3 -0
  56. package/dist/src/dom.d.ts.map +1 -0
  57. package/dist/src/request.d.ts +36 -0
  58. package/dist/src/request.d.ts.map +1 -0
  59. package/dist/src/shares.d.ts +10 -0
  60. package/dist/src/shares.d.ts.map +1 -0
  61. package/dist/src/types.d.ts +89 -0
  62. package/dist/src/types.d.ts.map +1 -0
  63. package/dist/src/utils.d.ts +4 -0
  64. package/dist/src/utils.d.ts.map +1 -0
  65. package/dist/test/cookie.test.d.ts +2 -0
  66. package/dist/test/cookie.test.d.ts.map +1 -0
  67. package/dist/test/shares.test.d.ts +2 -0
  68. package/dist/test/shares.test.d.ts.map +1 -0
  69. package/dist/types.d.ts +89 -0
  70. package/dist/types.d.ts.map +1 -0
  71. package/dist/utils.d.ts +2 -0
  72. package/dist/utils.d.ts.map +1 -0
  73. package/index.html +28 -0
  74. package/index.ts +154 -0
  75. package/jest.config.js +6 -0
  76. package/package.json +55 -28
  77. package/src/compatible.ts +46 -0
  78. package/src/constance.ts +7 -0
  79. package/src/cookie.ts +75 -0
  80. package/src/dom.ts +59 -0
  81. package/src/request.ts +99 -0
  82. package/src/shares.ts +26 -0
  83. package/src/types.ts +109 -0
  84. package/src/utils.ts +20 -0
  85. package/tests/compatible.test.ts +420 -0
  86. package/tests/cookie.test.ts +78 -0
  87. package/tests/dom.test.ts +95 -0
  88. package/tests/index.test.ts +126 -0
  89. package/tests/shares.test.ts +52 -0
  90. package/tests/utils.test.ts +79 -0
  91. package/tsconfig.json +49 -0
  92. package/webpack.config.mjs +47 -0
  93. package/index.js +0 -304
  94. package/webpack.config.js +0 -9
package/src/shares.ts ADDED
@@ -0,0 +1,26 @@
1
+ import { Tenant, Brand } from './types'
2
+ import { INVALID_BRAND, INVALID_TENANT_ID } from './constance'
3
+
4
+ export let tenantId!: Tenant
5
+ export let brand!: Brand
6
+ export let moduleBaseUrl: string = ''
7
+ export let loginPageUrl: string = ''
8
+
9
+ export const setTenantId = (id: Tenant) => {
10
+ if (!Object.values(Tenant).includes(id)) {
11
+ throw new Error(INVALID_TENANT_ID)
12
+ }
13
+ tenantId = id
14
+ }
15
+ export const setBrand = (id: Brand) => {
16
+ if (!Object.values(Brand).includes(id)) {
17
+ throw new Error(INVALID_BRAND)
18
+ }
19
+ brand = id
20
+ }
21
+ export const setModuleBaseUrl = (url: string) => {
22
+ moduleBaseUrl = url
23
+ }
24
+ export const setLoginPageUrl = (url: string) => {
25
+ loginPageUrl = url
26
+ }
package/src/types.ts ADDED
@@ -0,0 +1,109 @@
1
+ const modules = [
2
+ {
3
+ href: '',
4
+ name: 'commonLogin'
5
+ },
6
+ {
7
+ href: '',
8
+ name: 'App'
9
+ },
10
+ {
11
+ href: '',
12
+ name: 'Portal'
13
+ },
14
+ {
15
+ href: '',
16
+ name: 'AgentPortal'
17
+ },
18
+ {
19
+ href: '',
20
+ name: 'AdminPortal'
21
+ },
22
+ {
23
+ href: '',
24
+ name: 'CRM'
25
+ },
26
+ {
27
+ href: '',
28
+ name: 'Finance'
29
+ },
30
+ {
31
+ href: '',
32
+ name: 'FundingAdmin'
33
+ },
34
+ {
35
+ href: '',
36
+ name: 'MessageTemplate'
37
+ },
38
+ {
39
+ href: '',
40
+ name: 'Translate'
41
+ },
42
+ {
43
+ href: '',
44
+ name: 'TradeConfig'
45
+ },
46
+ {
47
+ href: '',
48
+ name: 'Ticket'
49
+ },
50
+ {
51
+ href: '',
52
+ name: 'IBPortalAdmin'
53
+ },
54
+ {
55
+ href: '',
56
+ name: 'OPPortal'
57
+ },
58
+ {
59
+ href: '',
60
+ name: 'ClientInfoHub'
61
+ },
62
+ {
63
+ href: '',
64
+ name: 'Promotion'
65
+ }
66
+ ] as const
67
+
68
+ export type ModuleName = typeof modules[number]['name']
69
+
70
+ export type UserInfo = {
71
+ 'aud': string
72
+ 'aud_time': number
73
+ 'cognito:groups': ModuleName[]
74
+ 'cognito:username': string
75
+ 'custom:encrypt_email_var': string
76
+ 'custom:tenant_id': Tenant
77
+ 'custom:user_id': string
78
+ 'email': string
79
+ 'email_verified': boolean
80
+ 'exp': number
81
+ 'event_id': string
82
+ 'iat': number
83
+ 'iss': string
84
+ 'jti': string
85
+ 'origin_jti': string
86
+ 'preferred_username': string
87
+ 'sub': string
88
+ 'token_use': string
89
+ }
90
+
91
+ export enum Brand {
92
+ ZERO = 1,
93
+ HEDGEHOOD = 2,
94
+ NISE = 3
95
+ }
96
+
97
+ export enum Tenant {
98
+ ZERO_INT = 1,
99
+ HEDGEHOOD = 2,
100
+ ZERO_NZ = 3,
101
+ ZERO_LA = 4,
102
+ ZERO_BR = 4,
103
+ NISE_EU = 5
104
+ }
105
+
106
+ export enum SystemType {
107
+ Staff = 'staff',
108
+ Client = 'client'
109
+ }
package/src/utils.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { UserInfo } from './types'
2
+ import { getAccessToken } from './cookie'
3
+ import { NO_ACCESS_TOKEN } from './constance'
4
+ import { Base64 } from 'js-base64'
5
+
6
+ export const isMobile = ():boolean => {
7
+ const ua = navigator.userAgent;
8
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(ua);
9
+ }
10
+
11
+ export const getUserInfo = (): Promise<UserInfo> => {
12
+ return new Promise((resolve, reject) => {
13
+ const token = getAccessToken()
14
+ if (!token) return reject(new Error(NO_ACCESS_TOKEN))
15
+ const splits = token.split('.')
16
+ if (splits.length < 3) return reject(new Error(NO_ACCESS_TOKEN))
17
+
18
+ resolve(JSON.parse(Base64.decode(splits[1] as string)) as UserInfo)
19
+ })
20
+ }
@@ -0,0 +1,420 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ import { describe, expect, test, jest, beforeEach, afterEach } from '@jest/globals'
5
+ import * as cookieUtils from '../src/cookie'
6
+ import Cookie from 'js-cookie'
7
+ import {
8
+ setIdToken,
9
+ getIdToken,
10
+ setCookie,
11
+ clearLoginCookie,
12
+ getCookie,
13
+ getUrlParam
14
+ } from '../src/compatible'
15
+
16
+ // 模拟 js-cookie
17
+ jest.mock('js-cookie', () => ({
18
+ set: jest.fn(),
19
+ get: jest.fn(),
20
+ remove: jest.fn()
21
+ }))
22
+
23
+ // 模拟 cookie 模块
24
+ jest.mock('../src/cookie', () => ({
25
+ getAccessToken: jest.fn(),
26
+ setAccessToken: jest.fn(),
27
+ setRefreshToken: jest.fn()
28
+ }))
29
+
30
+ describe('compatibility.ts 单元测试', () => {
31
+ let originalLocation: Location
32
+ let originalDocumentCookie: string
33
+
34
+ beforeEach(() => {
35
+ // 保存原始对象
36
+ originalLocation = window.location
37
+ originalDocumentCookie = document.cookie
38
+
39
+ // 重置所有模拟
40
+ jest.clearAllMocks()
41
+
42
+ // 模拟 document.cookie
43
+ Object.defineProperty(document, 'cookie', {
44
+ writable: true,
45
+ value: ''
46
+ })
47
+ })
48
+
49
+ afterEach(() => {
50
+ // 恢复原始对象
51
+ window.location = originalLocation
52
+ document.cookie = originalDocumentCookie
53
+ })
54
+
55
+ describe('setIdToken 和 getIdToken', () => {
56
+ test('setIdToken 应该是 setAccessToken 的别名', () => {
57
+ const mockToken = 'test-token-123'
58
+
59
+ // 调用 setIdToken
60
+ setIdToken(mockToken)
61
+
62
+ // 验证 setAccessToken 被调用
63
+ expect(cookieUtils.setAccessToken).toHaveBeenCalledWith(mockToken)
64
+ })
65
+
66
+ test('getIdToken 应该是 getAccessToken 的别名', () => {
67
+ (cookieUtils.getAccessToken as jest.Mock).mockReturnValue('test-token-456')
68
+
69
+ const result = getIdToken()
70
+
71
+ expect(cookieUtils.getAccessToken).toHaveBeenCalled()
72
+ expect(result).toBe('test-token-456')
73
+ })
74
+
75
+ test('setIdToken 传递 null 应该调用 setAccessToken(null)', () => {
76
+ setIdToken(null)
77
+ expect(cookieUtils.setAccessToken).toHaveBeenCalledWith(null)
78
+ })
79
+ })
80
+
81
+ describe('setCookie 函数', () => {
82
+ test('设置 cookie 应该调用 Cookie.set 正确参数', () => {
83
+ const name = 'testCookie'
84
+ const value = 'testValue'
85
+ const domain = 'example.com'
86
+ const path = '/test'
87
+ const time = 7 * 24 * 60 * 60 * 1000 // 7天
88
+
89
+ setCookie(name, value, domain, path, time)
90
+
91
+ expect(Cookie.set).toHaveBeenCalledWith(
92
+ name,
93
+ value,
94
+ {
95
+ domain,
96
+ path,
97
+ expires: 7 // time / (24 * 60 * 60 * 1000) = 7
98
+ }
99
+ )
100
+ })
101
+
102
+ test('setCookie 使用默认路径和时间', () => {
103
+ const name = 'testCookie'
104
+ const value = 'testValue'
105
+ const domain = 'example.com'
106
+
107
+ setCookie(name, value, domain)
108
+
109
+ expect(Cookie.set).toHaveBeenCalledWith(
110
+ name,
111
+ value,
112
+ {
113
+ domain,
114
+ path: '/',
115
+ expires: 30 // 默认时间 30天
116
+ }
117
+ )
118
+ })
119
+
120
+ test('setCookie 值为 null 应该删除 cookie', () => {
121
+ const name = 'testCookie'
122
+ const domain = 'example.com'
123
+
124
+ setCookie(name, null, domain)
125
+
126
+ expect(Cookie.remove).toHaveBeenCalledWith(name)
127
+ })
128
+
129
+ test('setCookie 值为 undefined 应该删除 cookie', () => {
130
+ const name = 'testCookie'
131
+ const domain = 'example.com'
132
+
133
+ setCookie(name, undefined, domain)
134
+
135
+ expect(Cookie.remove).toHaveBeenCalledWith(name)
136
+ })
137
+
138
+ test('setCookie 值为空字符串应该正常设置', () => {
139
+ const name = 'testCookie'
140
+ const value = ''
141
+ const domain = 'example.com'
142
+
143
+ setCookie(name, value, domain)
144
+
145
+ expect(Cookie.set).toHaveBeenCalledWith(
146
+ name,
147
+ value,
148
+ expect.objectContaining({
149
+ domain,
150
+ path: '/',
151
+ expires: 30
152
+ })
153
+ )
154
+ })
155
+
156
+ test('setCookie 时间计算正确', () => {
157
+ const name = 'testCookie'
158
+ const value = 'testValue'
159
+ const domain = 'example.com'
160
+
161
+ // 测试 1天
162
+ setCookie(name, value, domain, '/', 24 * 60 * 60 * 1000)
163
+ expect(Cookie.set).toHaveBeenCalledWith(
164
+ name,
165
+ value,
166
+ expect.objectContaining({
167
+ expires: 1
168
+ })
169
+ )
170
+
171
+ // 测试 0天
172
+ setCookie(name, value, domain, '/', 0)
173
+ expect(Cookie.set).toHaveBeenCalledWith(
174
+ name,
175
+ value,
176
+ expect.objectContaining({
177
+ expires: 0
178
+ })
179
+ )
180
+
181
+ // 测试半天
182
+ setCookie(name, value, domain, '/', 12 * 60 * 60 * 1000)
183
+ expect(Cookie.set).toHaveBeenCalledWith(
184
+ name,
185
+ value,
186
+ expect.objectContaining({
187
+ expires: 0.5
188
+ })
189
+ )
190
+ })
191
+ })
192
+
193
+ describe('clearLoginCookie 函数', () => {
194
+ test('应该调用 setAccessToken(null) 和 setRefreshToken(null)', () => {
195
+ clearLoginCookie()
196
+
197
+ expect(cookieUtils.setAccessToken).toHaveBeenCalledWith(null)
198
+ expect(cookieUtils.setRefreshToken).toHaveBeenCalledWith(null)
199
+ })
200
+
201
+ test('应该按照正确顺序调用', () => {
202
+ clearLoginCookie()
203
+
204
+ // 获取调用顺序
205
+ const calls = (cookieUtils.setAccessToken as jest.Mock).mock.invocationCallOrder[0]
206
+ const calls2 = (cookieUtils.setRefreshToken as jest.Mock).mock.invocationCallOrder[0]
207
+
208
+ // 两者都被调用,但顺序不重要
209
+ expect(cookieUtils.setAccessToken).toHaveBeenCalled()
210
+ expect(cookieUtils.setRefreshToken).toHaveBeenCalled()
211
+ })
212
+ })
213
+
214
+ describe('getCookie 函数', () => {
215
+ test('从 document.cookie 中获取 cookie 值', () => {
216
+ // 设置 document.cookie
217
+ document.cookie = 'testCookie=testValue; otherCookie=otherValue'
218
+
219
+ const result = getCookie('testCookie')
220
+
221
+ expect(result).toBe('testValue')
222
+ })
223
+
224
+ test('获取不存在的 cookie 返回 null', () => {
225
+ document.cookie = 'testCookie=testValue'
226
+
227
+ const result = getCookie('nonExistentCookie')
228
+
229
+ expect(result).toBeNull()
230
+ })
231
+
232
+ test('处理 document.cookie 为空的情况', () => {
233
+ document.cookie = ''
234
+
235
+ const result = getCookie('testCookie')
236
+
237
+ expect(result).toBeNull()
238
+ })
239
+
240
+ test('处理 cookie 值中包含特殊字符', () => {
241
+ const encodedValue = encodeURIComponent('test value with spaces & symbols=+')
242
+ document.cookie = `testCookie=${encodedValue}`
243
+
244
+ const result = getCookie('testCookie')
245
+
246
+ expect(result).toBe('test value with spaces & symbols=+')
247
+ })
248
+
249
+ test('处理多个 cookie 的情况', () => {
250
+ document.cookie = 'cookie1=value1; cookie2=value2; cookie3=value3'
251
+
252
+ const result1 = getCookie('cookie1')
253
+ const result2 = getCookie('cookie2')
254
+ const result3 = getCookie('cookie3')
255
+
256
+ expect(result1).toBe('value1')
257
+ expect(result2).toBe('value2')
258
+ expect(result3).toBe('value3')
259
+ })
260
+
261
+ test('处理 cookie 名称出现在值中的情况', () => {
262
+ document.cookie = 'testCookie=testValue; otherCookie=testCookie=notTheCookieName'
263
+
264
+ const result = getCookie('testCookie')
265
+
266
+ expect(result).toBe('testValue')
267
+ })
268
+
269
+ test('处理没有分号结尾的 cookie', () => {
270
+ document.cookie = 'testCookie=testValue'
271
+
272
+ const result = getCookie('testCookie')
273
+
274
+ expect(result).toBe('testValue')
275
+ })
276
+ })
277
+
278
+ describe('getUrlParam 函数', () => {
279
+ test('从 URL 查询参数中获取值', () => {
280
+ const name = getUrlParam('name', 'http://example.com/path?name=John&age=30')
281
+ const age = getUrlParam('age', 'http://example.com/path?name=John&age=30')
282
+
283
+ expect(name).toBe('John')
284
+ expect(age).toBe('30')
285
+ })
286
+
287
+ test('获取不存在的参数返回 null', () => {
288
+ const result = getUrlParam('nonExistent', 'http://example.com/path?name=John')
289
+
290
+ expect(result).toBeNull()
291
+ })
292
+
293
+ test('处理没有查询参数的 URL', () => {
294
+ const result = getUrlParam('name', 'http://example.com/path')
295
+
296
+ expect(result).toBeNull()
297
+ })
298
+
299
+ test('处理哈希后面的查询参数', () => {
300
+ const result = getUrlParam('notThis', 'http://example.com/#/pathsection?notThis=value&alsoNot=this')
301
+
302
+ expect(result).toBe('value') // 因为查询参数在哈希后面,不会被解析
303
+ })
304
+
305
+ test('处理空值的参数', () => {
306
+ const empty = getUrlParam('empty', 'http://example.com/path?empty=&null=null')
307
+ const nullParam = getUrlParam('null', 'http://example.com/path?empty=&null=null')
308
+
309
+ expect(empty).toBe('')
310
+ expect(nullParam).toBe('null')
311
+ })
312
+
313
+ test('处理编码的参数值', () => {
314
+ const name = getUrlParam('name', 'http://example.com/path?name=John%20Doe&city=New%20York')
315
+ const city = getUrlParam('city', 'http://example.com/path?name=John%20Doe&city=New%20York')
316
+
317
+ expect(name).toBe('John Doe')
318
+ expect(city).toBe('New York')
319
+ })
320
+
321
+ test('处理 URL 中有多个参数的情况', () => {
322
+ const a = getUrlParam('a', 'http://example.com/path?a=1&b=2&c=3&d=4&e=5')
323
+ const e = getUrlParam('e', 'http://example.com/path?a=1&b=2&c=3&d=4&e=5')
324
+
325
+ expect(a).toBe('1')
326
+ expect(e).toBe('5')
327
+ })
328
+
329
+ test('处理 URL 中带端口和路径的情况', () => {
330
+ const result = getUrlParam('param', 'http://example.com:8080/path/to/page?param=value')
331
+
332
+ expect(result).toBe('value')
333
+ })
334
+
335
+ test('处理 HTTPS URL', () => {
336
+ const result = getUrlParam('secure', 'https://example.com/path?secure=yes')
337
+
338
+ expect(result).toBe('yes')
339
+ })
340
+ })
341
+
342
+ describe('集成测试', () => {
343
+ test('setCookie 和 getCookie 配合工作', () => {
344
+ // 模拟 Cookie.set 来设置 document.cookie
345
+ (Cookie.set as jest.Mock).mockImplementation((name, value, options: any) => {
346
+ document.cookie = `${name}=${value}; domain=${options.domain}; path=${options.path}`
347
+ })
348
+
349
+ // 设置 cookie
350
+ setCookie('test', 'value', 'example.com')
351
+
352
+ // 使用 getCookie 获取
353
+ const result = getCookie('test')
354
+
355
+ expect(result).toBe('value')
356
+ })
357
+
358
+ test('clearLoginCookie 清除所有登录相关 cookie', () => {
359
+ clearLoginCookie()
360
+
361
+ expect(cookieUtils.setAccessToken).toHaveBeenCalledWith(null)
362
+ expect(cookieUtils.setRefreshToken).toHaveBeenCalledWith(null)
363
+ })
364
+ })
365
+
366
+ describe('错误处理和边缘情况', () => {
367
+ test('getCookie 处理空的 cookie 名称', () => {
368
+ document.cookie = '=value' // 无效的 cookie
369
+
370
+ const result = getCookie('')
371
+
372
+ // 根据实现,这应该返回 null,因为空字符串不是有效的 cookie 名称
373
+ expect(result).toBeNull()
374
+ })
375
+
376
+ test('getCookie 处理 cookie 值包含等号的情况', () => {
377
+ const complexValue = 'a=b&c=d'
378
+ document.cookie = `complex=${encodeURIComponent(complexValue)}`
379
+
380
+ const result = getCookie('complex')
381
+
382
+ expect(result).toBe(complexValue)
383
+ })
384
+
385
+ test('getUrlParam 处理 window.location.href 没有查询字符串的情况', () => {
386
+ const result = getUrlParam('any', 'http://example.com/path')
387
+
388
+ expect(result).toBeNull()
389
+ })
390
+
391
+ test('getUrlParam 处理 window.location.href 只有问号的情况', () => {
392
+ const result = getUrlParam('any', 'http://example.com/path?')
393
+
394
+ expect(result).toBeNull()
395
+ })
396
+
397
+ test('getUrlParam 处理 window.location.href 有空查询参数的情况', () => {
398
+ const result = getUrlParam('', 'http://example.com/path?&')
399
+
400
+ expect(result).toBeNull()
401
+ })
402
+
403
+ test('setCookie 处理异常时间值', () => {
404
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
405
+
406
+ // 测试 NaN
407
+ setCookie('test', 'value', 'example.com', '/', NaN as any)
408
+
409
+ expect(Cookie.set).toHaveBeenCalledWith(
410
+ 'test',
411
+ 'value',
412
+ expect.objectContaining({
413
+ expires: NaN
414
+ })
415
+ )
416
+
417
+ consoleSpy.mockRestore()
418
+ })
419
+ })
420
+ })
@@ -0,0 +1,78 @@
1
+ /**
2
+ * @jest-environment jsdom
3
+ */
4
+ import Cookies from 'js-cookie'
5
+ import { describe, expect, test } from '@jest/globals'
6
+ import { setAccessToken, setRefreshToken } from '../src/cookie'
7
+ import { getUserInfo } from '../src/utils'
8
+ import { INVALID_REFRESH_TOKEN, INVALID_ACCESS_TOKEN } from '../src/constance'
9
+
10
+ const accessToken = 'eyJraWQiOiJUQTVBanVVYURheGlZdFVYR3l6ajlEZEdPZFJIYUVlUTRTRnF6VWdzc0ZNPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJkNzQ0M2FmOC1mMGExLTcwMzItZGIzMC0wM2Y3NDczZTY0ZDciLCJjb2duaXRvOmdyb3VwcyI6WyJBZ2VudFBvcnRhbCIsIkZpbmFuY2UiLCJUaWNrZXQiLCJQb3J0YWwiXSwiZW1haWxfdmVyaWZpZWQiOnRydWUsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1ub3J0aGVhc3QtMS5hbWF6b25hd3MuY29tXC9hcC1ub3J0aGVhc3QtMV9JSFp0Y2JNZnQiLCJjdXN0b206dXNlcl9pZCI6IjUiLCJjb2duaXRvOnVzZXJuYW1lIjoiZmJjM2Q0ZDIwNzUxNGMwOGEyMGM1NDRjMGNjNmRlYTciLCJjdXN0b206dGVuYW50X2lkIjoiMSIsInByZWZlcnJlZF91c2VybmFtZSI6IuaZk-e6oiDlvKAiLCJjdXN0b206ZW5jcnlwdF9lbWFpbF92YXIiOiJjbGllbnQrNUBoZWRnZWhvb2QuY2MiLCJvcmlnaW5fanRpIjoiYWE4YjY3NzctYzhhZC00MDU3LWJlNTEtZjI1Nzc0M2E5NDY2IiwiYXVkIjoibjRibnJxdGY1OXBqazB1OG01dnVoM2ZxdCIsImV2ZW50X2lkIjoiNmI0ZTJkMjktODI3YS00ODg4LWE1NjUtZjgwYTVkNWU0MGI0IiwidG9rZW5fdXNlIjoiaWQiLCJhdXRoX3RpbWUiOjE3NjU3NzY5NTQsImV4cCI6MTc2NTc4NDE1NCwiaWF0IjoxNzY1Nzc2OTU0LCJlbWFpbCI6Im9ubGluZV90ZXN0QHRtcGVtbC5jb20iLCJqdGkiOiI3NGIzYzUzMi1kOWFlLTQ5YTItOWIzZC1mNzNmNjZkOGM3NDYifQ.VnCQy9EleScDCFLUkOyFdglxos3a2lQ7UGjoZv4sQPibfZrOlp69qlozqDHVoxEboaZ9foZ_EtxnUUkuK2G8rpBGF2mViGdqsNBOYATAN9At1JDTgZsr8yldtJy1EtCgKx6BjBKcL22EQkTreOLXJNpMLY_pkhyjrRoOZ_UTQmKvHthkRU9kCYldk0wh_NsncR8vUSIwG7f9rDqpY01Xu8_FctxudV_zg0WR3YEi45Sql47_RjeYKjoKTVcN2YYSbngJZa3dgfU93tfyx4C2qU5ZC-k7IZsKaRk_G3zcLzP1VeeuVPYgLlb8b-WMJsMJdR4megvmbbDAxWDpQQ-zCQ'
11
+ const refreshToken = 'eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.i9ZK_G5dMP0mol3m85EAun1VLyeMh1cnwhFC6jX5jTsxY0qp1exdE8_EyhZdYJJG__hqqXptk1LBAC6NrDPXQ9LC2QcaOfq4CxE8Ai4RTR7dOSOhQbpWu1vxSmIX1Gy9HiFMmlUxyknPDcVC1JXdXtLFPbeOWctXIg_S6xLILG3Kb2B9wMeJEHYPiAb2bIZk7qnT-I8geh9XzabUqeXqLBBHMp2xr3BU3ycgOEnuQQat_W7J0U0Szo5pD9Td7T5QytLYNkFBxo5CNzJzmq2B-alwBqYTm0pXUL1gASI757dlMbVig8tpnJgGtziv67EUiP0NCkTSTeqd4S-WY8H48Q.iJeo5oRqo5MnjbFI.kgtUI6ipZFsTehsicL8mT4DAORSY7J-8JAgYVta8GEyFnXAol2hJIaj4ob9cSOWZENoO8ZT_i7Co8DCLLFoTA4aNeLebFCnJTzdJSYDhBeJ6OrRVEtw8-dniJd1VZriuN53ZWjmM-RxPSYrFYFpUFpYG_xk00w06CWowxSy0WrhUzgrrC-OLUViTRL3Sl3TPW7AxNnzjgMZVZUQ2udWaw3Y2EfcyGYE_Un2HvyLYYbEUm6EMqRTh5BgNMxnCiFrhiaQpuJaABskHH-PUSFdtoHnWONqayjlRazCF_lTYpKglIgi7PQp12SVU8A_gZP6JEGc3nYLpyj2CeR8ocvkMWP58bnzYoU9Jdke0avrAjC2YPfO2R-YcF2LUM6q3HECe_ukMGAEiYM5YwM5o8w2Mcbn-WtRS6nZxTWhChfqMYYme61QaEm2nsZO72aoGc9nTN27PU_j-lq9-HLC-caDzpPYLq5wpZgLvK5HsRAsxknDtJh02wb-6miLZHAZTbdjAlCOMXz3334Vdha17by1lTu_L4C5rUpSPSQaspdRl0moBqH7He27XIoHem6RXlWb-a-jXjGhA1FLHu73rTYU40gZ681UE6qrVz2aQCVDcbhE1iytUS7NcLXI2i5zbzo4YBnYGNvOVLd58CesSI1T_T0_Y4ip966lEypERJAVYJ20Ji2F54KDYPr17Cv3ltz80qqqPN_1QI5oRszt6xU7IjTCp47YGVAHt7RcfR2FemiodpW3_-Xm2PYgo0rwgkEX7z7fZ6Ban1jSeZsYD0vPrlf6nlD8QvA7bP6acZufmfok5oMJ2SC5hv7mGjggd9HT8h3yj8yH4exfga2BSIHTwgNXU-cBw_mQyZCScELof20HJdpE8f3TzOHZfURn1uJdKSZ0tZAdIaTqdHIUlEgUZ8xok7JRpqayVsXve1GvCaZylG0Mw9FTx5DJRi6IblXVdL7yZwLFk8FUYcn4KqtPlamoxR9rpGGMtXIexY4yN99v-hc8_gn3ilYMeA3-a4cFx1mmld8VRQJeD7q_u0lRheDBqW9K6JRBjn8s59hLfyoiRPMi_NZFc2OJNwJofNJbmTcfQmR1dQtsTh2Rtv4krG2YnczzGmPZJppOpaebictrv_ogc93NnXZqJtZGAbSy4RdQYj3Fnx17EY-NSU-VQerlhgV_e35cz8ZNmsiISq7Lp6zUTQwr6ASztyLQ8i_71Xr0OXgf4l4qXWyVQJhbOTJdIUyX5s3ebJruU1qSwPG20Fd3Pm6boIbIlsGHWM6VvRxON8CbJ0PGU_rcIJPVkEGZ0MoiMGvh3BnFYaZYtSPD5p7F9w_LBMRdzb3JimdzNtn48jGYG.XHICmXlRw5-f1fQVFS1Zdw'
12
+
13
+ describe('cookie.ts access token(短token)测试', () => {
14
+ test('测试不合法的 access token 流程', () => {
15
+ setAccessToken(accessToken)
16
+ expect(() => setAccessToken('invalidToken')).toThrow(INVALID_ACCESS_TOKEN)
17
+ expect(Cookies.get('access_token')).toBe(accessToken)
18
+
19
+ setAccessToken(0)
20
+ expect(Cookies.get('access_token')).toBeUndefined()
21
+ expect(() => setAccessToken({})).toThrow()
22
+ })
23
+
24
+ test('测试设置合法的 access token 流程', async () => {
25
+ setAccessToken('')
26
+ expect(Cookies.get('access_token')).toBeUndefined()
27
+
28
+ setAccessToken(accessToken)
29
+ expect(Cookies.get('access_token')).toBe(accessToken)
30
+
31
+ const userInfo = await getUserInfo()
32
+
33
+ expect(userInfo).not.toBeNull()
34
+ })
35
+
36
+ test('测试清除 access token 流程', () => {
37
+ setAccessToken(accessToken)
38
+ expect(Cookies.get('access_token')).toBe(accessToken)
39
+ setAccessToken('')
40
+ expect(Cookies.get('access_token')).toBeUndefined()
41
+
42
+ setAccessToken(accessToken)
43
+ expect(Cookies.get('access_token')).toBe(accessToken)
44
+ setAccessToken(null)
45
+ expect(Cookies.get('access_token')).toBeUndefined()
46
+ })
47
+ })
48
+
49
+ describe('cookie.ts refresh token tests', () => {
50
+ test('测试不合法的 refresh token 流程', () => {
51
+ setRefreshToken(refreshToken)
52
+ expect(() => setRefreshToken('invalidToken')).toThrow(INVALID_REFRESH_TOKEN)
53
+
54
+ setRefreshToken(0)
55
+ expect(Cookies.get('refresh_token')).toBeUndefined()
56
+ expect(() => setRefreshToken({})).toThrow()
57
+ })
58
+
59
+ test('测试设置合法的 refresh token 流程', async () => {
60
+ setRefreshToken('')
61
+ expect(Cookies.get('refresh_token')).toBeUndefined()
62
+
63
+ setRefreshToken(refreshToken)
64
+ expect(Cookies.get('refresh_token')).toBe(refreshToken)
65
+ })
66
+
67
+ test('测试清除 refresh token 流程', () => {
68
+ setRefreshToken(refreshToken)
69
+ expect(Cookies.get('refresh_token')).toBe(refreshToken)
70
+ setRefreshToken('')
71
+ expect(Cookies.get('refresh_token')).toBeUndefined()
72
+
73
+ setRefreshToken(refreshToken)
74
+ expect(Cookies.get('refresh_token')).toBe(refreshToken)
75
+ setRefreshToken(null)
76
+ expect(Cookies.get('refresh_token')).toBeUndefined()
77
+ })
78
+ })