agent-messenger 2.10.0 → 2.10.2

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 (239) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/package.json +1 -1
  3. package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -1
  4. package/dist/src/platforms/teams/token-extractor.js +15 -2
  5. package/dist/src/platforms/teams/token-extractor.js.map +1 -1
  6. package/dist/src/shared/chromium/decryptor.d.ts +6 -0
  7. package/dist/src/shared/chromium/decryptor.d.ts.map +1 -1
  8. package/dist/src/shared/chromium/decryptor.js +26 -6
  9. package/dist/src/shared/chromium/decryptor.js.map +1 -1
  10. package/e2e/channeltalk.e2e.test.ts +13 -13
  11. package/e2e/channeltalkbot.e2e.test.ts +13 -13
  12. package/e2e/discord.e2e.test.ts +24 -24
  13. package/e2e/discordbot.e2e.test.ts +16 -16
  14. package/e2e/instagram.e2e.test.ts +10 -10
  15. package/e2e/kakaotalk.e2e.test.ts +7 -7
  16. package/e2e/line.e2e.test.ts +8 -8
  17. package/e2e/slack.e2e.test.ts +34 -34
  18. package/e2e/slackbot.e2e.test.ts +14 -14
  19. package/e2e/teams.e2e.test.ts +23 -23
  20. package/e2e/telegram.e2e.test.ts +8 -8
  21. package/e2e/webex.e2e.test.ts +14 -14
  22. package/e2e/whatsapp.e2e.test.ts +8 -8
  23. package/e2e/whatsappbot.e2e.test.ts +6 -6
  24. package/package.json +1 -1
  25. package/skills/agent-channeltalk/SKILL.md +1 -1
  26. package/skills/agent-channeltalkbot/SKILL.md +1 -1
  27. package/skills/agent-discord/SKILL.md +1 -1
  28. package/skills/agent-discordbot/SKILL.md +1 -1
  29. package/skills/agent-instagram/SKILL.md +1 -1
  30. package/skills/agent-kakaotalk/SKILL.md +1 -1
  31. package/skills/agent-line/SKILL.md +1 -1
  32. package/skills/agent-slack/SKILL.md +1 -1
  33. package/skills/agent-slackbot/SKILL.md +1 -1
  34. package/skills/agent-teams/SKILL.md +1 -1
  35. package/skills/agent-telegram/SKILL.md +1 -1
  36. package/skills/agent-webex/SKILL.md +1 -1
  37. package/skills/agent-wechatbot/SKILL.md +1 -1
  38. package/skills/agent-whatsapp/SKILL.md +1 -1
  39. package/skills/agent-whatsappbot/SKILL.md +1 -1
  40. package/src/platforms/channeltalk/client.test.ts +26 -26
  41. package/src/platforms/channeltalk/commands/auth.test.ts +16 -16
  42. package/src/platforms/channeltalk/commands/bot.test.ts +2 -2
  43. package/src/platforms/channeltalk/commands/chat.test.ts +3 -3
  44. package/src/platforms/channeltalk/commands/group.test.ts +4 -4
  45. package/src/platforms/channeltalk/commands/manager.test.ts +2 -2
  46. package/src/platforms/channeltalk/commands/message.test.ts +17 -17
  47. package/src/platforms/channeltalk/commands/snapshot.test.ts +7 -7
  48. package/src/platforms/channeltalk/commands/whoami.test.ts +3 -3
  49. package/src/platforms/channeltalk/credential-manager.test.ts +18 -18
  50. package/src/platforms/channeltalk/ensure-auth.test.ts +5 -5
  51. package/src/platforms/channeltalk/index.test.ts +23 -23
  52. package/src/platforms/channeltalk/token-extractor.test.ts +21 -21
  53. package/src/platforms/channeltalk/types.test.ts +12 -12
  54. package/src/platforms/channeltalkbot/client.test.ts +14 -14
  55. package/src/platforms/channeltalkbot/commands/auth.test.ts +16 -16
  56. package/src/platforms/channeltalkbot/commands/bot.test.ts +6 -6
  57. package/src/platforms/channeltalkbot/commands/chat.test.ts +9 -9
  58. package/src/platforms/channeltalkbot/commands/group.test.ts +6 -6
  59. package/src/platforms/channeltalkbot/commands/manager.test.ts +3 -3
  60. package/src/platforms/channeltalkbot/commands/message.test.ts +10 -10
  61. package/src/platforms/channeltalkbot/commands/snapshot.test.ts +7 -7
  62. package/src/platforms/channeltalkbot/commands/whoami.test.ts +4 -4
  63. package/src/platforms/channeltalkbot/credential-manager.test.ts +27 -27
  64. package/src/platforms/channeltalkbot/index.test.ts +15 -15
  65. package/src/platforms/discord/client.test.ts +28 -28
  66. package/src/platforms/discord/commands/auth.test.ts +7 -7
  67. package/src/platforms/discord/commands/channel.test.ts +7 -7
  68. package/src/platforms/discord/commands/dm.test.ts +4 -4
  69. package/src/platforms/discord/commands/file.test.ts +4 -4
  70. package/src/platforms/discord/commands/friend.test.ts +6 -6
  71. package/src/platforms/discord/commands/member.test.ts +5 -5
  72. package/src/platforms/discord/commands/mention.test.ts +5 -5
  73. package/src/platforms/discord/commands/message.test.ts +9 -9
  74. package/src/platforms/discord/commands/note.test.ts +6 -6
  75. package/src/platforms/discord/commands/profile.test.ts +4 -4
  76. package/src/platforms/discord/commands/reaction.test.ts +5 -5
  77. package/src/platforms/discord/commands/server.test.ts +7 -7
  78. package/src/platforms/discord/commands/snapshot.test.ts +6 -6
  79. package/src/platforms/discord/commands/thread.test.ts +6 -6
  80. package/src/platforms/discord/commands/user.test.ts +5 -5
  81. package/src/platforms/discord/commands/whoami.test.ts +6 -6
  82. package/src/platforms/discord/credential-manager.test.ts +16 -16
  83. package/src/platforms/discord/ensure-auth.test.ts +8 -8
  84. package/src/platforms/discord/index.test.ts +17 -17
  85. package/src/platforms/discord/listener.test.ts +33 -33
  86. package/src/platforms/discord/token-extractor.test.ts +53 -53
  87. package/src/platforms/discord/types.test.ts +26 -26
  88. package/src/platforms/discordbot/client.test.ts +31 -31
  89. package/src/platforms/discordbot/commands/auth.test.ts +18 -18
  90. package/src/platforms/discordbot/commands/channel.test.ts +11 -11
  91. package/src/platforms/discordbot/commands/file.test.ts +7 -7
  92. package/src/platforms/discordbot/commands/message.test.ts +25 -25
  93. package/src/platforms/discordbot/commands/reaction.test.ts +6 -6
  94. package/src/platforms/discordbot/commands/server.test.ts +12 -12
  95. package/src/platforms/discordbot/commands/snapshot.test.ts +13 -13
  96. package/src/platforms/discordbot/commands/thread.test.ts +10 -10
  97. package/src/platforms/discordbot/commands/user.test.ts +9 -9
  98. package/src/platforms/discordbot/commands/whoami.test.ts +4 -4
  99. package/src/platforms/discordbot/credential-manager.test.ts +28 -28
  100. package/src/platforms/instagram/client.test.ts +18 -18
  101. package/src/platforms/instagram/commands/auth.test.ts +11 -11
  102. package/src/platforms/instagram/commands/chat.test.ts +6 -6
  103. package/src/platforms/instagram/commands/message.test.ts +11 -11
  104. package/src/platforms/instagram/commands/shared.test.ts +12 -12
  105. package/src/platforms/instagram/commands/whoami.test.ts +3 -3
  106. package/src/platforms/instagram/credential-manager.test.ts +21 -21
  107. package/src/platforms/instagram/ensure-auth.test.ts +4 -4
  108. package/src/platforms/instagram/index.test.ts +9 -9
  109. package/src/platforms/instagram/listener.test.ts +8 -8
  110. package/src/platforms/instagram/token-extractor.test.ts +35 -35
  111. package/src/platforms/kakaotalk/client.test.ts +33 -33
  112. package/src/platforms/kakaotalk/commands/auth.test.ts +11 -11
  113. package/src/platforms/kakaotalk/commands/chat.test.ts +6 -6
  114. package/src/platforms/kakaotalk/commands/message.test.ts +7 -7
  115. package/src/platforms/kakaotalk/commands/whoami.test.ts +5 -5
  116. package/src/platforms/kakaotalk/credential-manager.test.ts +15 -15
  117. package/src/platforms/kakaotalk/index.test.ts +15 -15
  118. package/src/platforms/kakaotalk/listener.test.ts +17 -17
  119. package/src/platforms/line/client.test.ts +17 -17
  120. package/src/platforms/line/commands/auth.test.ts +8 -8
  121. package/src/platforms/line/commands/chat.test.ts +7 -7
  122. package/src/platforms/line/commands/friend.test.ts +6 -6
  123. package/src/platforms/line/commands/message.test.ts +7 -7
  124. package/src/platforms/line/commands/whoami.test.ts +6 -6
  125. package/src/platforms/line/credential-manager.test.ts +17 -17
  126. package/src/platforms/line/index.test.ts +10 -10
  127. package/src/platforms/line/listener.test.ts +15 -15
  128. package/src/platforms/line/types.test.ts +14 -14
  129. package/src/platforms/slack/cli.test.ts +8 -8
  130. package/src/platforms/slack/client.test.ts +151 -151
  131. package/src/platforms/slack/commands/activity.test.ts +13 -13
  132. package/src/platforms/slack/commands/auth.test.ts +34 -34
  133. package/src/platforms/slack/commands/bookmark.test.ts +9 -9
  134. package/src/platforms/slack/commands/channel.test.ts +17 -17
  135. package/src/platforms/slack/commands/drafts.test.ts +7 -7
  136. package/src/platforms/slack/commands/emoji.test.ts +3 -3
  137. package/src/platforms/slack/commands/file.test.ts +12 -12
  138. package/src/platforms/slack/commands/message.test.ts +19 -19
  139. package/src/platforms/slack/commands/pin.test.ts +7 -7
  140. package/src/platforms/slack/commands/reaction.test.ts +10 -10
  141. package/src/platforms/slack/commands/reminder.test.ts +9 -9
  142. package/src/platforms/slack/commands/saved.test.ts +7 -7
  143. package/src/platforms/slack/commands/sections.test.ts +5 -5
  144. package/src/platforms/slack/commands/snapshot.test.ts +13 -13
  145. package/src/platforms/slack/commands/unread.test.ts +6 -6
  146. package/src/platforms/slack/commands/user.test.ts +10 -10
  147. package/src/platforms/slack/commands/usergroup.test.ts +15 -15
  148. package/src/platforms/slack/commands/whoami.test.ts +6 -6
  149. package/src/platforms/slack/commands/workspace.test.ts +26 -26
  150. package/src/platforms/slack/credential-manager.test.ts +14 -14
  151. package/src/platforms/slack/ensure-auth.test.ts +21 -21
  152. package/src/platforms/slack/index.test.ts +12 -12
  153. package/src/platforms/slack/listener.test.ts +17 -17
  154. package/src/platforms/slack/token-extractor-node.test.ts +2 -2
  155. package/src/platforms/slack/token-extractor.test.ts +37 -37
  156. package/src/platforms/slack/types.test.ts +21 -21
  157. package/src/platforms/slackbot/client.test.ts +22 -22
  158. package/src/platforms/slackbot/commands/auth.test.ts +14 -14
  159. package/src/platforms/slackbot/commands/channel.test.ts +7 -7
  160. package/src/platforms/slackbot/commands/message.test.ts +13 -13
  161. package/src/platforms/slackbot/commands/reaction.test.ts +6 -6
  162. package/src/platforms/slackbot/commands/user.test.ts +7 -7
  163. package/src/platforms/slackbot/commands/whoami.test.ts +4 -4
  164. package/src/platforms/slackbot/credential-manager.test.ts +22 -22
  165. package/src/platforms/slackbot/types.test.ts +7 -7
  166. package/src/platforms/teams/client.test.ts +30 -30
  167. package/src/platforms/teams/commands/auth.test.ts +8 -8
  168. package/src/platforms/teams/commands/channel.test.ts +7 -7
  169. package/src/platforms/teams/commands/file.test.ts +4 -4
  170. package/src/platforms/teams/commands/message.test.ts +5 -5
  171. package/src/platforms/teams/commands/reaction.test.ts +4 -4
  172. package/src/platforms/teams/commands/snapshot.test.ts +7 -7
  173. package/src/platforms/teams/commands/team.test.ts +8 -8
  174. package/src/platforms/teams/commands/user.test.ts +4 -4
  175. package/src/platforms/teams/commands/whoami.test.ts +6 -6
  176. package/src/platforms/teams/credential-manager.test.ts +17 -17
  177. package/src/platforms/teams/ensure-auth.test.ts +13 -13
  178. package/src/platforms/teams/index.test.ts +15 -15
  179. package/src/platforms/teams/token-extractor.test.ts +219 -145
  180. package/src/platforms/teams/token-extractor.ts +13 -2
  181. package/src/platforms/teams/types.test.ts +26 -26
  182. package/src/platforms/telegram/app-config.test.ts +4 -4
  183. package/src/platforms/telegram/chat-utils.test.ts +12 -12
  184. package/src/platforms/telegram/client.test.ts +4 -4
  185. package/src/platforms/telegram/commands/auth.test.ts +16 -16
  186. package/src/platforms/telegram/commands/chat.test.ts +9 -9
  187. package/src/platforms/telegram/commands/message.test.ts +6 -6
  188. package/src/platforms/telegram/commands/shared.test.ts +3 -3
  189. package/src/platforms/telegram/commands/whoami.test.ts +3 -3
  190. package/src/platforms/telegram/credential-manager.test.ts +10 -10
  191. package/src/platforms/telegram/types.test.ts +6 -6
  192. package/src/platforms/webex/app-config.test.ts +8 -8
  193. package/src/platforms/webex/cli.test.ts +5 -5
  194. package/src/platforms/webex/client.test.ts +65 -65
  195. package/src/platforms/webex/commands/auth.test.ts +18 -18
  196. package/src/platforms/webex/commands/member.test.ts +5 -5
  197. package/src/platforms/webex/commands/message.test.ts +12 -12
  198. package/src/platforms/webex/commands/snapshot.test.ts +5 -5
  199. package/src/platforms/webex/commands/space.test.ts +10 -10
  200. package/src/platforms/webex/commands/whoami.test.ts +6 -6
  201. package/src/platforms/webex/credential-manager.test.ts +22 -22
  202. package/src/platforms/webex/encryption.test.ts +4 -4
  203. package/src/platforms/webex/ensure-auth.test.ts +5 -5
  204. package/src/platforms/webex/index.test.ts +5 -5
  205. package/src/platforms/webex/markdown-to-html.test.ts +33 -33
  206. package/src/platforms/webex/token-extractor.test.ts +23 -23
  207. package/src/platforms/webex/types.test.ts +27 -27
  208. package/src/platforms/wechatbot/client.test.ts +27 -27
  209. package/src/platforms/wechatbot/commands/auth.test.ts +15 -15
  210. package/src/platforms/wechatbot/commands/message.test.ts +8 -8
  211. package/src/platforms/wechatbot/commands/template.test.ts +9 -9
  212. package/src/platforms/wechatbot/commands/user.test.ts +7 -7
  213. package/src/platforms/wechatbot/commands/whoami.test.ts +5 -5
  214. package/src/platforms/wechatbot/credential-manager.test.ts +18 -18
  215. package/src/platforms/wechatbot/index.test.ts +10 -10
  216. package/src/platforms/wechatbot/types.test.ts +25 -25
  217. package/src/platforms/whatsapp/commands/auth.test.ts +13 -13
  218. package/src/platforms/whatsapp/commands/chat.test.ts +8 -8
  219. package/src/platforms/whatsapp/commands/message.test.ts +10 -10
  220. package/src/platforms/whatsapp/commands/whoami.test.ts +3 -3
  221. package/src/platforms/whatsapp/credential-manager.test.ts +23 -23
  222. package/src/platforms/whatsapp/ensure-auth.test.ts +4 -4
  223. package/src/platforms/whatsapp/index.test.ts +8 -8
  224. package/src/platforms/whatsapp/types.test.ts +42 -42
  225. package/src/platforms/whatsappbot/client.test.ts +27 -27
  226. package/src/platforms/whatsappbot/commands/auth.test.ts +14 -14
  227. package/src/platforms/whatsappbot/commands/message.test.ts +16 -16
  228. package/src/platforms/whatsappbot/commands/template.test.ts +9 -9
  229. package/src/platforms/whatsappbot/commands/whoami.test.ts +5 -5
  230. package/src/platforms/whatsappbot/credential-manager.test.ts +18 -18
  231. package/src/platforms/whatsappbot/index.test.ts +7 -7
  232. package/src/platforms/whatsappbot/types.test.ts +18 -18
  233. package/src/shared/chromium/browsers.test.ts +22 -22
  234. package/src/shared/chromium/cookie-reader.test.ts +13 -13
  235. package/src/shared/chromium/decryptor.test.ts +97 -32
  236. package/src/shared/chromium/decryptor.ts +27 -6
  237. package/src/shared/utils/concurrency.test.ts +6 -6
  238. package/src/shared/utils/derived-key-cache.test.ts +11 -11
  239. package/src/tui/utils.test.ts +31 -31
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, spyOn, it } from 'bun:test'
2
2
  import * as childProcess from 'node:child_process'
3
3
 
4
4
  import { WebexClient } from '../client'
@@ -42,7 +42,7 @@ describe('auth commands', () => {
42
42
  })
43
43
 
44
44
  describe('loginAction with --token', () => {
45
- test('authenticates with provided token (bot token flow)', async () => {
45
+ it('authenticates with provided token (bot token flow)', async () => {
46
46
  protoSpy(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient())
47
47
  protoSpy(WebexClient.prototype, 'testAuth').mockResolvedValue(mockPerson)
48
48
  protoSpy(WebexCredentialManager.prototype, 'saveConfig').mockResolvedValue(undefined)
@@ -56,7 +56,7 @@ describe('auth commands', () => {
56
56
  expect(output.user.displayName).toBe('Test User')
57
57
  })
58
58
 
59
- test('saves tokenType as manual with expiresAt 0', async () => {
59
+ it('saves tokenType as manual with expiresAt 0', async () => {
60
60
  protoSpy(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient())
61
61
  protoSpy(WebexClient.prototype, 'testAuth').mockResolvedValue(mockPerson)
62
62
  const saveSpy = protoSpy(WebexCredentialManager.prototype, 'saveConfig').mockResolvedValue(undefined)
@@ -71,7 +71,7 @@ describe('auth commands', () => {
71
71
  })
72
72
 
73
73
  describe('loginAction with --client-id and --client-secret', () => {
74
- test('uses provided credentials for Device Grant flow', async () => {
74
+ it('uses provided credentials for Device Grant flow', async () => {
75
75
  protoSpy(WebexCredentialManager.prototype, 'requestDeviceCode').mockResolvedValue({
76
76
  deviceCode: 'd',
77
77
  userCode: 'u',
@@ -101,7 +101,7 @@ describe('auth commands', () => {
101
101
  )
102
102
  })
103
103
 
104
- test('saves tokenType as oauth in config', async () => {
104
+ it('saves tokenType as oauth in config', async () => {
105
105
  protoSpy(WebexCredentialManager.prototype, 'requestDeviceCode').mockResolvedValue({
106
106
  deviceCode: 'd',
107
107
  userCode: 'u',
@@ -125,7 +125,7 @@ describe('auth commands', () => {
125
125
  expect(savedConfig.tokenType).toBe('oauth')
126
126
  })
127
127
 
128
- test('saves clientId and clientSecret in config', async () => {
128
+ it('saves clientId and clientSecret in config', async () => {
129
129
  protoSpy(WebexCredentialManager.prototype, 'requestDeviceCode').mockResolvedValue({
130
130
  deviceCode: 'd',
131
131
  userCode: 'u',
@@ -152,7 +152,7 @@ describe('auth commands', () => {
152
152
  })
153
153
 
154
154
  describe('statusAction', () => {
155
- test('shows authenticated status when token is valid', async () => {
155
+ it('shows authenticated status when token is valid', async () => {
156
156
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
157
157
  protoSpy(WebexCredentialManager.prototype, 'getToken').mockResolvedValue('valid-token')
158
158
  protoSpy(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient())
@@ -166,7 +166,7 @@ describe('auth commands', () => {
166
166
  expect(output.user.displayName).toBe('Test User')
167
167
  })
168
168
 
169
- test('shows not authenticated when no token', async () => {
169
+ it('shows not authenticated when no token', async () => {
170
170
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
171
171
  protoSpy(WebexCredentialManager.prototype, 'getToken').mockResolvedValue(null)
172
172
  const exitSpy = protoSpy(process, 'exit').mockImplementation(() => undefined as never)
@@ -179,7 +179,7 @@ describe('auth commands', () => {
179
179
  expect(exitSpy).toHaveBeenCalledWith(1)
180
180
  })
181
181
 
182
- test('shows not authenticated when token validation fails', async () => {
182
+ it('shows not authenticated when token validation fails', async () => {
183
183
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
184
184
  protoSpy(WebexCredentialManager.prototype, 'getToken').mockResolvedValue('invalid-token')
185
185
  protoSpy(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient())
@@ -192,7 +192,7 @@ describe('auth commands', () => {
192
192
  expect(output.authenticated).toBe(false)
193
193
  })
194
194
 
195
- test('loads config for stored client credentials', async () => {
195
+ it('loads config for stored client credentials', async () => {
196
196
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue({
197
197
  accessToken: 'at',
198
198
  refreshToken: 'rt',
@@ -211,7 +211,7 @@ describe('auth commands', () => {
211
211
  })
212
212
 
213
213
  describe('extractAction', () => {
214
- test('passes deviceUrl and tokenType to client.login', async () => {
214
+ it('passes deviceUrl and tokenType to client.login', async () => {
215
215
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue({
216
216
  accessToken: 'extracted-token-at-least-twenty-chars',
217
217
  refreshToken: 'refresh-token',
@@ -232,7 +232,7 @@ describe('auth commands', () => {
232
232
  })
233
233
  })
234
234
 
235
- test('attempts refresh when token is expired', async () => {
235
+ it('attempts refresh when token is expired', async () => {
236
236
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue({
237
237
  accessToken: 'expired-token-at-least-twenty-chars-',
238
238
  refreshToken: 'valid-refresh-token',
@@ -257,7 +257,7 @@ describe('auth commands', () => {
257
257
  expect(output.refreshed).toBe(true)
258
258
  })
259
259
 
260
- test('reports expired token with actionable hint when refresh fails', async () => {
260
+ it('reports expired token with actionable hint when refresh fails', async () => {
261
261
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue({
262
262
  accessToken: 'expired-token-at-least-twenty-chars-',
263
263
  refreshToken: 'bad-refresh-token',
@@ -278,7 +278,7 @@ describe('auth commands', () => {
278
278
  expect(exitSpy).toHaveBeenCalledWith(1)
279
279
  })
280
280
 
281
- test('rethrows non-auth errors even when token is expired', async () => {
281
+ it('rethrows non-auth errors even when token is expired', async () => {
282
282
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue({
283
283
  accessToken: 'expired-token-at-least-twenty-chars-',
284
284
  refreshToken: 'bad-refresh-token',
@@ -298,7 +298,7 @@ describe('auth commands', () => {
298
298
  }
299
299
  })
300
300
 
301
- test('rethrows non-expiry auth errors', async () => {
301
+ it('rethrows non-expiry auth errors', async () => {
302
302
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue({
303
303
  accessToken: 'valid-token-at-least-twenty-chars-xx',
304
304
  expiresAt: Date.now() + 3600000,
@@ -316,7 +316,7 @@ describe('auth commands', () => {
316
316
  }
317
317
  })
318
318
 
319
- test('outputs no token found when extract returns null', async () => {
319
+ it('outputs no token found when extract returns null', async () => {
320
320
  protoSpy(WebexTokenExtractor.prototype, 'extract').mockResolvedValue(null)
321
321
  const exitSpy = protoSpy(process, 'exit').mockImplementation(() => undefined as never)
322
322
 
@@ -330,7 +330,7 @@ describe('auth commands', () => {
330
330
  })
331
331
 
332
332
  describe('logoutAction', () => {
333
- test('clears credentials when authenticated', async () => {
333
+ it('clears credentials when authenticated', async () => {
334
334
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue({
335
335
  accessToken: 'token',
336
336
  refreshToken: 'refresh',
@@ -346,7 +346,7 @@ describe('auth commands', () => {
346
346
  expect(output.success).toBe(true)
347
347
  })
348
348
 
349
- test('shows error when not authenticated', async () => {
349
+ it('shows error when not authenticated', async () => {
350
350
  protoSpy(WebexCredentialManager.prototype, 'loadConfig').mockResolvedValue(null)
351
351
  const exitSpy = protoSpy(process, 'exit').mockImplementation(() => undefined as never)
352
352
 
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
3
  import { WebexError } from '../types'
4
4
 
@@ -59,7 +59,7 @@ describe('member commands', () => {
59
59
  consoleSpy.mockRestore()
60
60
  })
61
61
 
62
- test('listAction calls listMemberships with spaceId and outputs mapped members', async () => {
62
+ it('calls listMemberships with spaceId and outputs mapped members', async () => {
63
63
  await listAction('room-1', {})
64
64
 
65
65
  expect(mockListMemberships).toHaveBeenCalledWith('room-1', { max: undefined })
@@ -85,13 +85,13 @@ describe('member commands', () => {
85
85
  )
86
86
  })
87
87
 
88
- test('listAction passes limit option to listMemberships', async () => {
88
+ it('passes limit option to listMemberships', async () => {
89
89
  await listAction('room-1', { limit: 25 })
90
90
 
91
91
  expect(mockListMemberships).toHaveBeenCalledWith('room-1', { max: 25 })
92
92
  })
93
93
 
94
- test('listAction handles not-authenticated case', async () => {
94
+ it('throws when not authenticated', async () => {
95
95
  mockLogin.mockImplementation(async () => {
96
96
  throw new WebexError('No Webex credentials found.', 'no_credentials')
97
97
  })
@@ -101,7 +101,7 @@ describe('member commands', () => {
101
101
  expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
102
102
  })
103
103
 
104
- test('listAction handles API error', async () => {
104
+ it('throws on API error', async () => {
105
105
  mockListMemberships.mockImplementation(async () => {
106
106
  throw new Error('API failure')
107
107
  })
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
3
  import { WebexError } from '../types'
4
4
 
@@ -77,7 +77,7 @@ afterEach(() => {
77
77
  consoleLogSpy.mockRestore()
78
78
  })
79
79
 
80
- test('send: calls sendMessage with correct args and outputs result', async () => {
80
+ it('calls sendMessage with correct args and outputs result', async () => {
81
81
  await sendAction('space_456', 'Hello world', { pretty: false })
82
82
 
83
83
  expect(mockSendMessage).toHaveBeenCalledWith('space_456', 'Hello world', {
@@ -90,13 +90,13 @@ test('send: calls sendMessage with correct args and outputs result', async () =>
90
90
  expect(output).toContain('user@example.com')
91
91
  })
92
92
 
93
- test('send: with --markdown passes markdown option', async () => {
93
+ it('passes markdown option when --markdown flag is set on send', async () => {
94
94
  await sendAction('space_456', '**bold**', { markdown: true, pretty: false })
95
95
 
96
96
  expect(mockSendMessage).toHaveBeenCalledWith('space_456', '**bold**', { markdown: true })
97
97
  })
98
98
 
99
- test('send: not authenticated shows error', async () => {
99
+ it('throws when not authenticated on send', async () => {
100
100
  mockLogin.mockImplementation(async () => {
101
101
  throw new WebexError('No Webex credentials found.', 'no_credentials')
102
102
  })
@@ -106,7 +106,7 @@ test('send: not authenticated shows error', async () => {
106
106
  expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
107
107
  })
108
108
 
109
- test('dm: calls sendDirectMessage with email and text', async () => {
109
+ it('calls sendDirectMessage with email and text', async () => {
110
110
  await dmAction('alice@example.com', 'Hello!', { pretty: false })
111
111
 
112
112
  expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', 'Hello!', {
@@ -117,7 +117,7 @@ test('dm: calls sendDirectMessage with email and text', async () => {
117
117
  expect(output).toContain('msg_123')
118
118
  })
119
119
 
120
- test('dm: with --markdown passes markdown option', async () => {
120
+ it('passes markdown option to sendDirectMessage when --markdown flag is set', async () => {
121
121
  await dmAction('alice@example.com', '**bold**', { markdown: true, pretty: false })
122
122
 
123
123
  expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', '**bold**', {
@@ -125,7 +125,7 @@ test('dm: with --markdown passes markdown option', async () => {
125
125
  })
126
126
  })
127
127
 
128
- test('list: calls listMessages with limit and outputs array', async () => {
128
+ it('calls listMessages with limit and outputs array', async () => {
129
129
  await listAction('space_456', { limit: 50, pretty: false })
130
130
 
131
131
  expect(mockListMessages).toHaveBeenCalledWith('space_456', { max: 50 })
@@ -135,7 +135,7 @@ test('list: calls listMessages with limit and outputs array', async () => {
135
135
  expect(output).toContain('msg_124')
136
136
  })
137
137
 
138
- test('get: calls getMessage with correct id and outputs result', async () => {
138
+ it('calls getMessage with correct id and outputs result', async () => {
139
139
  await getAction('msg_123', { pretty: false })
140
140
 
141
141
  expect(mockGetMessage).toHaveBeenCalledWith('msg_123')
@@ -145,7 +145,7 @@ test('get: calls getMessage with correct id and outputs result', async () => {
145
145
  expect(output).toContain('user@example.com')
146
146
  })
147
147
 
148
- test('delete: with --force calls deleteMessage and outputs deleted id', async () => {
148
+ it('calls deleteMessage and outputs deleted id when --force flag is set', async () => {
149
149
  await deleteAction('msg_123', { force: true, pretty: false })
150
150
 
151
151
  expect(mockDeleteMessage).toHaveBeenCalledWith('msg_123')
@@ -155,7 +155,7 @@ test('delete: with --force calls deleteMessage and outputs deleted id', async ()
155
155
  expect(output).toContain('msg_123')
156
156
  })
157
157
 
158
- test('delete: without --force shows warning and does not delete', async () => {
158
+ it('shows warning and does not delete without --force flag', async () => {
159
159
  try {
160
160
  await deleteAction('msg_123', { force: false, pretty: false })
161
161
  } catch {}
@@ -167,7 +167,7 @@ test('delete: without --force shows warning and does not delete', async () => {
167
167
  expect(output).toContain('--force')
168
168
  })
169
169
 
170
- test('edit: calls editMessage with roomId in args and outputs result', async () => {
170
+ it('calls editMessage with roomId in args and outputs result', async () => {
171
171
  await editAction('msg_123', 'space_456', 'Updated message', { pretty: false })
172
172
 
173
173
  expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', 'Updated message', {
@@ -179,7 +179,7 @@ test('edit: calls editMessage with roomId in args and outputs result', async ()
179
179
  expect(output).toContain('Updated message')
180
180
  })
181
181
 
182
- test('edit: with --markdown passes markdown option', async () => {
182
+ it('passes markdown option to editMessage when --markdown flag is set', async () => {
183
183
  await editAction('msg_123', 'space_456', '**updated**', { markdown: true, pretty: false })
184
184
 
185
185
  expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', '**updated**', {
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
3
  import { WebexError } from '../types'
4
4
 
@@ -79,7 +79,7 @@ describe('snapshot command', () => {
79
79
  consoleSpy.mockRestore()
80
80
  })
81
81
 
82
- test('brief snapshot returns spaces with id and title only', async () => {
82
+ it('returns spaces with id and title only in brief mode', async () => {
83
83
  await snapshotAction({})
84
84
 
85
85
  expect(consoleSpy).toHaveBeenCalled()
@@ -91,7 +91,7 @@ describe('snapshot command', () => {
91
91
  expect(output.hint).toBeDefined()
92
92
  })
93
93
 
94
- test('full snapshot returns spaces with id, title, type, lastActivity', async () => {
94
+ it('returns spaces with id, title, type, and lastActivity in full mode', async () => {
95
95
  await snapshotAction({ full: true })
96
96
 
97
97
  expect(consoleSpy).toHaveBeenCalled()
@@ -104,7 +104,7 @@ describe('snapshot command', () => {
104
104
  expect(output.hint).toBeUndefined()
105
105
  })
106
106
 
107
- test('filters spaces to only those in my memberships', async () => {
107
+ it('filters spaces to only those in my memberships', async () => {
108
108
  await snapshotAction({})
109
109
 
110
110
  const output = JSON.parse(consoleSpy.mock.calls[consoleSpy.mock.calls.length - 1][0])
@@ -112,7 +112,7 @@ describe('snapshot command', () => {
112
112
  expect(output.spaces[0].id).toBe('space-1')
113
113
  })
114
114
 
115
- test('not authenticated outputs error', async () => {
115
+ it('throws when not authenticated', async () => {
116
116
  mockLogin.mockImplementation(async () => {
117
117
  throw new WebexError('No Webex credentials found.', 'no_credentials')
118
118
  })
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, it } from 'bun:test'
2
2
 
3
3
  import { WebexError } from '../types'
4
4
 
@@ -74,7 +74,7 @@ afterEach(() => {
74
74
  })
75
75
 
76
76
  describe('listAction', () => {
77
- test('calls listSpaces and outputs mapped array', async () => {
77
+ it('calls listSpaces and outputs mapped array', async () => {
78
78
  await listAction({})
79
79
 
80
80
  expect(mockListSpaces).toHaveBeenCalled()
@@ -98,19 +98,19 @@ describe('listAction', () => {
98
98
  )
99
99
  })
100
100
 
101
- test('passes type and limit options to listSpaces', async () => {
101
+ it('passes type and limit options to listSpaces', async () => {
102
102
  await listAction({ type: 'group', limit: 10 })
103
103
 
104
104
  expect(mockListSpaces).toHaveBeenCalledWith({ type: 'group', max: 10 })
105
105
  })
106
106
 
107
- test('passes undefined type and limit when not provided', async () => {
107
+ it('passes undefined type and limit when not provided', async () => {
108
108
  await listAction({})
109
109
 
110
110
  expect(mockListSpaces).toHaveBeenCalledWith({ type: undefined, max: undefined })
111
111
  })
112
112
 
113
- test('outputs pretty-printed JSON when pretty is true', async () => {
113
+ it('outputs pretty-printed JSON when pretty is true', async () => {
114
114
  await listAction({ pretty: true })
115
115
 
116
116
  expect(consoleLogSpy).toHaveBeenCalledWith(
@@ -137,7 +137,7 @@ describe('listAction', () => {
137
137
  )
138
138
  })
139
139
 
140
- test('not authenticated: outputs error and exits', async () => {
140
+ it('throws when not authenticated', async () => {
141
141
  mockLogin.mockImplementation(async () => {
142
142
  throw new WebexError('No Webex credentials found.', 'no_credentials')
143
143
  })
@@ -150,7 +150,7 @@ describe('listAction', () => {
150
150
  })
151
151
 
152
152
  describe('infoAction', () => {
153
- test('calls getSpace with spaceId and outputs space details', async () => {
153
+ it('calls getSpace with spaceId and outputs space details', async () => {
154
154
  await infoAction('space-1', {})
155
155
 
156
156
  expect(mockGetSpace).toHaveBeenCalledWith('space-1')
@@ -168,7 +168,7 @@ describe('infoAction', () => {
168
168
  )
169
169
  })
170
170
 
171
- test('outputs null for teamId when not present', async () => {
171
+ it('outputs null for teamId when not present', async () => {
172
172
  mockGetSpace.mockImplementation(() => Promise.resolve({ ...mockSpace, teamId: undefined }))
173
173
 
174
174
  await infoAction('space-1', {})
@@ -179,7 +179,7 @@ describe('infoAction', () => {
179
179
  expect(output.teamId).toBeNull()
180
180
  })
181
181
 
182
- test('outputs pretty-printed JSON when pretty is true', async () => {
182
+ it('outputs pretty-printed JSON when pretty is true', async () => {
183
183
  await infoAction('space-1', { pretty: true })
184
184
 
185
185
  expect(consoleLogSpy).toHaveBeenCalledWith(
@@ -200,7 +200,7 @@ describe('infoAction', () => {
200
200
  )
201
201
  })
202
202
 
203
- test('not authenticated: outputs error and exits', async () => {
203
+ it('throws when not authenticated', async () => {
204
204
  mockLogin.mockImplementation(async () => {
205
205
  throw new WebexError('No Webex credentials found.', 'no_credentials')
206
206
  })
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, expect, spyOn, test } from 'bun:test'
1
+ import { afterEach, beforeEach, expect, spyOn, it } from 'bun:test'
2
2
 
3
3
  import * as clientModule from '../client'
4
4
  import { WebexError } from '../types'
@@ -42,19 +42,19 @@ afterEach(() => {
42
42
  processExitSpy?.mockRestore()
43
43
  })
44
44
 
45
- test('whoami command is defined with correct name and description', () => {
45
+ it('whoami command is defined with correct name and description', () => {
46
46
  expect(whoamiCommand).toBeDefined()
47
47
  expect(whoamiCommand.name()).toBe('whoami')
48
48
  expect(whoamiCommand.description()).toBe('Show current authenticated user')
49
49
  })
50
50
 
51
- test('whoami command has --pretty option', () => {
51
+ it('whoami command has --pretty option', () => {
52
52
  const options = whoamiCommand.options
53
53
  const hasPretty = options.some((opt: { long?: string }) => opt.long === '--pretty')
54
54
  expect(hasPretty).toBe(true)
55
55
  })
56
56
 
57
- test('whoami calls testAuth and outputs user fields', async () => {
57
+ it('whoami calls testAuth and outputs user fields', async () => {
58
58
  // given: authenticated webex user
59
59
  // when: running whoami
60
60
  await whoamiCommand.parseAsync([], { from: 'user' })
@@ -75,7 +75,7 @@ test('whoami calls testAuth and outputs user fields', async () => {
75
75
  )
76
76
  })
77
77
 
78
- test('whoami outputs pretty-printed JSON when --pretty flag is passed', async () => {
78
+ it('whoami outputs pretty-printed JSON when --pretty flag is passed', async () => {
79
79
  // given: authenticated webex user
80
80
  // when: running whoami with --pretty
81
81
  await whoamiCommand.parseAsync(['--pretty'], { from: 'user' })
@@ -100,7 +100,7 @@ test('whoami outputs pretty-printed JSON when --pretty flag is passed', async ()
100
100
  )
101
101
  })
102
102
 
103
- test('whoami exits with code 1 when not authenticated', async () => {
103
+ it('whoami exits with code 1 when not authenticated', async () => {
104
104
  // given: no credentials
105
105
  webexClientSpy.mockImplementation(
106
106
  () =>
@@ -1,4 +1,4 @@
1
- import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
1
+ import { afterEach, beforeEach, describe, expect, mock, it } from 'bun:test'
2
2
  import { mkdtemp, rm, writeFile } from 'node:fs/promises'
3
3
  import { tmpdir } from 'node:os'
4
4
  import { join } from 'node:path'
@@ -18,11 +18,11 @@ describe('WebexCredentialManager', () => {
18
18
  await rm(tempDir, { recursive: true, force: true })
19
19
  })
20
20
 
21
- test('loadConfig returns null when no file exists', async () => {
21
+ it('loadConfig returns null when no file exists', async () => {
22
22
  expect(await credManager.loadConfig()).toBeNull()
23
23
  })
24
24
 
25
- test('saveConfig + loadConfig round trip with OAuth tokens', async () => {
25
+ it('saveConfig and loadConfig round-trip OAuth tokens', async () => {
26
26
  const config = {
27
27
  accessToken: 'test-access-token',
28
28
  refreshToken: 'test-refresh-token',
@@ -33,7 +33,7 @@ describe('WebexCredentialManager', () => {
33
33
  expect(loaded).toEqual(config)
34
34
  })
35
35
 
36
- test('getToken returns accessToken when not expired', async () => {
36
+ it('getToken returns accessToken when not expired', async () => {
37
37
  await credManager.saveConfig({
38
38
  accessToken: 'valid-token',
39
39
  refreshToken: 'refresh',
@@ -43,7 +43,7 @@ describe('WebexCredentialManager', () => {
43
43
  expect(token).toBe('valid-token')
44
44
  })
45
45
 
46
- test('getToken returns null when expired and no refresh available', async () => {
46
+ it('getToken returns null when expired and no refresh available', async () => {
47
47
  await credManager.saveConfig({
48
48
  accessToken: 'expired-token',
49
49
  refreshToken: 'bad-refresh',
@@ -53,7 +53,7 @@ describe('WebexCredentialManager', () => {
53
53
  expect(token).toBeNull()
54
54
  })
55
55
 
56
- test('getToken auto-refreshes expired token', async () => {
56
+ it('getToken auto-refreshes expired token', async () => {
57
57
  const originalFetch = globalThis.fetch
58
58
  globalThis.fetch = mock(() =>
59
59
  Promise.resolve(
@@ -87,7 +87,7 @@ describe('WebexCredentialManager', () => {
87
87
  globalThis.fetch = originalFetch
88
88
  })
89
89
 
90
- test('requestDeviceCode calls device authorize endpoint', async () => {
90
+ it('requestDeviceCode calls device authorize endpoint', async () => {
91
91
  const originalFetch = globalThis.fetch
92
92
  globalThis.fetch = mock(() =>
93
93
  Promise.resolve(
@@ -114,7 +114,7 @@ describe('WebexCredentialManager', () => {
114
114
  globalThis.fetch = originalFetch
115
115
  })
116
116
 
117
- test('requestDeviceCode throws on failure', async () => {
117
+ it('requestDeviceCode throws on failure', async () => {
118
118
  const originalFetch = globalThis.fetch
119
119
  globalThis.fetch = mock(() =>
120
120
  Promise.resolve(new Response('{"error":"invalid_client"}', { status: 400 })),
@@ -125,7 +125,7 @@ describe('WebexCredentialManager', () => {
125
125
  globalThis.fetch = originalFetch
126
126
  })
127
127
 
128
- test('pollDeviceToken polls until authorized', async () => {
128
+ it('pollDeviceToken polls until authorized', async () => {
129
129
  const originalFetch = globalThis.fetch
130
130
  let callCount = 0
131
131
  globalThis.fetch = mock(() => {
@@ -152,7 +152,7 @@ describe('WebexCredentialManager', () => {
152
152
  globalThis.fetch = originalFetch
153
153
  })
154
154
 
155
- test('clearCredentials removes the file', async () => {
155
+ it('clearCredentials removes the file', async () => {
156
156
  await credManager.saveConfig({
157
157
  accessToken: 'token',
158
158
  refreshToken: 'refresh',
@@ -162,11 +162,11 @@ describe('WebexCredentialManager', () => {
162
162
  expect(await credManager.loadConfig()).toBeNull()
163
163
  })
164
164
 
165
- test('clearCredentials does nothing when no file', async () => {
165
+ it('clearCredentials does nothing when no file', async () => {
166
166
  await credManager.clearCredentials() // Should not throw
167
167
  })
168
168
 
169
- test('credentials file has 0o600 permissions', async () => {
169
+ it('saves credentials file with 0o600 permissions', async () => {
170
170
  await credManager.saveConfig({
171
171
  accessToken: 'token',
172
172
  refreshToken: 'refresh',
@@ -179,7 +179,7 @@ describe('WebexCredentialManager', () => {
179
179
  expect(mode).toBe(0o600)
180
180
  })
181
181
 
182
- test('pollDeviceToken with undefined clientSecret uses empty Basic auth', async () => {
182
+ it('pollDeviceToken with undefined clientSecret uses empty Basic auth', async () => {
183
183
  const originalFetch = globalThis.fetch
184
184
  let capturedAuth: string | null = null
185
185
  globalThis.fetch = mock((url: string, init?: RequestInit) => {
@@ -202,7 +202,7 @@ describe('WebexCredentialManager', () => {
202
202
  globalThis.fetch = originalFetch
203
203
  })
204
204
 
205
- test('pollDeviceToken does not auto-save config', async () => {
205
+ it('pollDeviceToken does not auto-save config', async () => {
206
206
  const originalFetch = globalThis.fetch
207
207
  globalThis.fetch = mock(() =>
208
208
  Promise.resolve(
@@ -225,7 +225,7 @@ describe('WebexCredentialManager', () => {
225
225
  globalThis.fetch = originalFetch
226
226
  })
227
227
 
228
- test('getToken returns null when expired and no client credentials available', async () => {
228
+ it('getToken returns null when expired and no client credentials available', async () => {
229
229
  await credManager.saveConfig({
230
230
  accessToken: 'expired-token',
231
231
  refreshToken: 'valid-refresh',
@@ -236,7 +236,7 @@ describe('WebexCredentialManager', () => {
236
236
  expect(token).toBeNull()
237
237
  })
238
238
 
239
- test('getToken returns manual token without attempting refresh', async () => {
239
+ it('getToken returns manual token without attempting refresh', async () => {
240
240
  await credManager.saveConfig({
241
241
  accessToken: 'my-bot-token',
242
242
  refreshToken: '',
@@ -248,7 +248,7 @@ describe('WebexCredentialManager', () => {
248
248
  expect(token).toBe('my-bot-token')
249
249
  })
250
250
 
251
- test('getToken uses stored clientId/clientSecret for refresh', async () => {
251
+ it('getToken uses stored clientId/clientSecret for refresh', async () => {
252
252
  const originalFetch = globalThis.fetch
253
253
  globalThis.fetch = mock(() =>
254
254
  Promise.resolve(
@@ -277,7 +277,7 @@ describe('WebexCredentialManager', () => {
277
277
  globalThis.fetch = originalFetch
278
278
  })
279
279
 
280
- test('saveConfig persists clientId and clientSecret', async () => {
280
+ it('saveConfig persists clientId and clientSecret', async () => {
281
281
  await credManager.saveConfig({
282
282
  accessToken: 'token',
283
283
  refreshToken: 'refresh',
@@ -291,7 +291,7 @@ describe('WebexCredentialManager', () => {
291
291
  expect(loaded?.clientSecret).toBe('my-client-secret')
292
292
  })
293
293
 
294
- test('getToken tries refresh for expired extracted tokens', async () => {
294
+ it('getToken tries refresh for expired extracted tokens', async () => {
295
295
  const originalFetch = globalThis.fetch
296
296
  globalThis.fetch = mock(() =>
297
297
  Promise.resolve(
@@ -323,7 +323,7 @@ describe('WebexCredentialManager', () => {
323
323
  globalThis.fetch = originalFetch
324
324
  })
325
325
 
326
- test('getToken returns expired extracted token when refresh fails', async () => {
326
+ it('getToken returns expired extracted token when refresh fails', async () => {
327
327
  const originalFetch = globalThis.fetch
328
328
  globalThis.fetch = mock(() =>
329
329
  Promise.resolve(new Response('{"error":"invalid_grant"}', { status: 400 })),
@@ -342,7 +342,7 @@ describe('WebexCredentialManager', () => {
342
342
  globalThis.fetch = originalFetch
343
343
  })
344
344
 
345
- test('getToken returns non-expired extracted token without refresh', async () => {
345
+ it('getToken returns non-expired extracted token without refresh', async () => {
346
346
  await credManager.saveConfig({
347
347
  accessToken: 'valid-extracted-token',
348
348
  refreshToken: 'refresh',
@@ -354,7 +354,7 @@ describe('WebexCredentialManager', () => {
354
354
  expect(token).toBe('valid-extracted-token')
355
355
  })
356
356
 
357
- test('loadConfig backward compat — old config without clientId/clientSecret', async () => {
357
+ it('loadConfig handles old config without clientId/clientSecret', async () => {
358
358
  // Write raw JSON without clientId/clientSecret fields
359
359
  const credPath = join(tempDir, 'webex-credentials.json')
360
360
  await writeFile(