test-request-session-guard.mjs 3.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import assert from 'node:assert/strict'
  2. import { readFileSync } from 'node:fs'
  3. import test from 'node:test'
  4. const code = readFileSync(new URL('../utils/request.js', import.meta.url), 'utf8')
  5. .replace(/^import[^\n]+\n/gm, '')
  6. .replace(/export /g, '')
  7. .replace("await import('@/stores/user')", 'await loadUserStore()')
  8. function context() {
  9. const storage = new Map([['token', 'old-token'], ['refresh', 'old-refresh'], ['user', { id: 'old-user' }]])
  10. const calls = { requests: [], clears: 0, routes: [], toasts: [] }
  11. const store = { clearLoginInfo: () => {
  12. calls.clears++
  13. storage.clear()
  14. } }
  15. let resolveImport
  16. const imported = new Promise((resolve) => { resolveImport = resolve })
  17. const uni = {
  18. getStorageSync: (key) => storage.get(key), removeStorageSync: (key) => storage.delete(key),
  19. request: (options) => calls.requests.push(options), showToast: (options) => calls.toasts.push(options),
  20. reLaunch: ({ url }) => calls.routes.push(url)
  21. }
  22. const request = new Function('TOKEN_KEY', 'REFRESH_TOKEN_KEY', 'USER_INFO_KEY', 'resolveApiBase',
  23. 'uni', 'getCurrentPages', 'loadUserStore', `${code}; return request`)(
  24. 'token', 'refresh', 'user', () => 'https://portal.invalid/api', uni,
  25. () => [{ route: 'pages/login/login' }], () => imported)
  26. return { storage, calls, request, finishImport: () => resolveImport({ useUserStore: () => store }) }
  27. }
  28. const tick = () => new Promise((resolve) => setImmediate(resolve))
  29. test('old HTTP 401 cannot erase a new login session', async () => {
  30. const p = context()
  31. const result = p.request({ url: '/web/wechat-notices/binding' }).catch((error) => error)
  32. p.storage.set('token', 'new-token')
  33. p.storage.set('user', { id: 'new-user' })
  34. await p.calls.requests[0].success({ statusCode: 401, data: { detail: 'expired' } })
  35. p.finishImport()
  36. await result
  37. await tick()
  38. assert.equal(p.storage.get('token'), 'new-token')
  39. assert.deepEqual(p.storage.get('user'), { id: 'new-user' })
  40. assert.equal(p.calls.clears, 0)
  41. assert.deepEqual(p.calls.routes, [])
  42. })
  43. test('old business 401 cannot erase a new login session', async () => {
  44. const p = context()
  45. const result = p.request({ url: '/web/wechat-notices/binding' }).catch((error) => error)
  46. p.storage.set('token', 'new-token')
  47. await p.calls.requests[0].success({ statusCode: 200, data: { code: 401 } })
  48. p.finishImport()
  49. await result
  50. await tick()
  51. assert.equal(p.storage.get('token'), 'new-token')
  52. assert.equal(p.calls.clears, 0)
  53. })
  54. test('same session 401 still clears expired credentials', async () => {
  55. const p = context()
  56. const result = p.request({ url: '/web/wechat-notices/binding' }).catch((error) => error)
  57. await p.calls.requests[0].success({ statusCode: 401, data: {} })
  58. p.finishImport()
  59. const error = await result
  60. await tick()
  61. assert.equal(error.name, 'UnauthorizedError')
  62. assert.equal(p.storage.get('token'), undefined)
  63. assert.equal(p.calls.clears, 1)
  64. })
  65. test('login completed during deferred store import is not cleared', async () => {
  66. const p = context()
  67. const result = p.request({ url: '/web/wechat-notices/binding' }).catch((error) => error)
  68. await p.calls.requests[0].success({ statusCode: 401, data: {} })
  69. p.storage.set('token', 'new-token')
  70. p.storage.set('user', { id: 'new-user' })
  71. p.finishImport()
  72. await result
  73. await tick()
  74. assert.equal(p.storage.get('token'), 'new-token')
  75. assert.equal(p.calls.clears, 0)
  76. assert.deepEqual(p.calls.routes, [])
  77. })