agent-messenger 2.2.0 → 2.4.0
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.
- package/.claude-plugin/README.md +16 -16
- package/.claude-plugin/marketplace.json +29 -29
- package/.claude-plugin/plugin.json +5 -5
- package/CONTRIBUTING.md +1 -1
- package/README.md +9 -6
- package/bun.lock +89 -105
- package/bunfig.toml +3 -0
- package/dist/package.json +13 -3
- package/dist/src/platforms/discordbot/client.js +2 -2
- package/dist/src/platforms/discordbot/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/cli.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/cli.js +2 -1
- package/dist/src/platforms/kakaotalk/cli.js.map +1 -1
- package/dist/src/platforms/kakaotalk/client.d.ts +2 -1
- package/dist/src/platforms/kakaotalk/client.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/client.js +52 -2
- package/dist/src/platforms/kakaotalk/client.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.d.ts +1 -0
- package/dist/src/platforms/kakaotalk/commands/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/index.js +1 -0
- package/dist/src/platforms/kakaotalk/commands/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts +3 -0
- package/dist/src/platforms/kakaotalk/commands/profile.d.ts.map +1 -0
- package/dist/src/platforms/kakaotalk/commands/profile.js +19 -0
- package/dist/src/platforms/kakaotalk/commands/profile.js.map +1 -0
- package/dist/src/platforms/kakaotalk/index.d.ts +2 -2
- package/dist/src/platforms/kakaotalk/index.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/index.js +1 -1
- package/dist/src/platforms/kakaotalk/index.js.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js +2 -1
- package/dist/src/platforms/kakaotalk/protocol/session.js.map +1 -1
- package/dist/src/platforms/kakaotalk/types.d.ts +16 -0
- package/dist/src/platforms/kakaotalk/types.d.ts.map +1 -1
- package/dist/src/platforms/kakaotalk/types.js +8 -0
- package/dist/src/platforms/kakaotalk/types.js.map +1 -1
- package/dist/src/platforms/line/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/line/commands/auth.js +32 -20
- package/dist/src/platforms/line/commands/auth.js.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -1
- package/dist/src/platforms/teams/commands/reaction.js +2 -0
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -1
- package/dist/src/platforms/webex/client.d.ts +2 -0
- package/dist/src/platforms/webex/client.d.ts.map +1 -1
- package/dist/src/platforms/webex/client.js +66 -23
- package/dist/src/platforms/webex/client.js.map +1 -1
- package/dist/src/platforms/webex/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/commands/auth.js +4 -0
- package/dist/src/platforms/webex/commands/auth.js.map +1 -1
- package/dist/src/platforms/webex/encryption.d.ts +10 -0
- package/dist/src/platforms/webex/encryption.d.ts.map +1 -0
- package/dist/src/platforms/webex/encryption.js +49 -0
- package/dist/src/platforms/webex/encryption.js.map +1 -0
- package/dist/src/platforms/webex/ensure-auth.d.ts.map +1 -1
- package/dist/src/platforms/webex/ensure-auth.js +4 -0
- package/dist/src/platforms/webex/ensure-auth.js.map +1 -1
- package/dist/src/platforms/webex/token-extractor.d.ts +6 -5
- package/dist/src/platforms/webex/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/webex/token-extractor.js +92 -43
- package/dist/src/platforms/webex/token-extractor.js.map +1 -1
- package/dist/src/platforms/webex/types.d.ts +4 -0
- package/dist/src/platforms/webex/types.d.ts.map +1 -1
- package/dist/src/platforms/webex/types.js +2 -0
- package/dist/src/platforms/webex/types.js.map +1 -1
- package/dist/src/platforms/wechatbot/cli.d.ts +5 -0
- package/dist/src/platforms/wechatbot/cli.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/cli.js +18 -0
- package/dist/src/platforms/wechatbot/cli.js.map +1 -0
- package/dist/src/platforms/wechatbot/client.d.ts +36 -0
- package/dist/src/platforms/wechatbot/client.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/client.js +208 -0
- package/dist/src/platforms/wechatbot/client.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/auth.d.ts +28 -0
- package/dist/src/platforms/wechatbot/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/auth.js +164 -0
- package/dist/src/platforms/wechatbot/commands/auth.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/index.d.ts +5 -0
- package/dist/src/platforms/wechatbot/commands/index.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/index.js +5 -0
- package/dist/src/platforms/wechatbot/commands/index.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/message.d.ts +18 -0
- package/dist/src/platforms/wechatbot/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/message.js +80 -0
- package/dist/src/platforms/wechatbot/commands/message.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/shared.d.ts +9 -0
- package/dist/src/platforms/wechatbot/commands/shared.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/shared.js +13 -0
- package/dist/src/platforms/wechatbot/commands/shared.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/template.d.ts +19 -0
- package/dist/src/platforms/wechatbot/commands/template.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/template.js +76 -0
- package/dist/src/platforms/wechatbot/commands/template.js.map +1 -0
- package/dist/src/platforms/wechatbot/commands/user.d.ts +20 -0
- package/dist/src/platforms/wechatbot/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/commands/user.js +53 -0
- package/dist/src/platforms/wechatbot/commands/user.js.map +1 -0
- package/dist/src/platforms/wechatbot/credential-manager.d.ts +17 -0
- package/dist/src/platforms/wechatbot/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/credential-manager.js +121 -0
- package/dist/src/platforms/wechatbot/credential-manager.js.map +1 -0
- package/dist/src/platforms/wechatbot/index.d.ts +5 -0
- package/dist/src/platforms/wechatbot/index.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/index.js +4 -0
- package/dist/src/platforms/wechatbot/index.js.map +1 -0
- package/dist/src/platforms/wechatbot/types.d.ts +94 -0
- package/dist/src/platforms/wechatbot/types.d.ts.map +1 -0
- package/dist/src/platforms/wechatbot/types.js +54 -0
- package/dist/src/platforms/wechatbot/types.js.map +1 -0
- package/dist/src/platforms/whatsapp/client.d.ts +1 -0
- package/dist/src/platforms/whatsapp/client.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/client.js +27 -13
- package/dist/src/platforms/whatsapp/client.js.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/commands/auth.js +21 -18
- package/dist/src/platforms/whatsapp/commands/auth.js.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/whatsapp/credential-manager.js +14 -8
- package/dist/src/platforms/whatsapp/credential-manager.js.map +1 -1
- package/docs/content/docs/agent-skills.mdx +4 -4
- package/docs/content/docs/cli/channeltalk.mdx +1 -1
- package/docs/content/docs/cli/channeltalkbot.mdx +1 -1
- package/docs/content/docs/cli/discord.mdx +1 -1
- package/docs/content/docs/cli/discordbot.mdx +1 -1
- package/docs/content/docs/cli/instagram.mdx +1 -1
- package/docs/content/docs/cli/kakaotalk.mdx +1 -1
- package/docs/content/docs/cli/line.mdx +1 -1
- package/docs/content/docs/cli/meta.json +1 -0
- package/docs/content/docs/cli/slack.mdx +1 -1
- package/docs/content/docs/cli/slackbot.mdx +1 -1
- package/docs/content/docs/cli/teams.mdx +1 -1
- package/docs/content/docs/cli/webex.mdx +5 -3
- package/docs/content/docs/cli/wechatbot.mdx +179 -0
- package/docs/content/docs/cli/whatsapp.mdx +1 -1
- package/docs/content/docs/cli/whatsappbot.mdx +1 -1
- package/docs/content/docs/sdk/meta.json +1 -1
- package/docs/content/docs/sdk/wechatbot.mdx +282 -0
- package/docs/content/docs/tui.mdx +1 -1
- package/docs/src/app/page.tsx +5 -5
- package/package.json +13 -3
- package/skills/agent-channeltalk/SKILL.md +1 -1
- package/skills/agent-channeltalkbot/SKILL.md +1 -1
- package/skills/agent-discord/SKILL.md +1 -1
- package/skills/agent-discordbot/SKILL.md +1 -1
- package/skills/agent-instagram/SKILL.md +1 -1
- package/skills/agent-kakaotalk/SKILL.md +24 -1
- package/skills/agent-line/SKILL.md +7 -11
- package/skills/agent-line/references/authentication.md +13 -4
- package/skills/agent-slack/SKILL.md +1 -1
- package/skills/agent-slackbot/SKILL.md +1 -1
- package/skills/agent-teams/SKILL.md +1 -1
- package/skills/agent-telegram/SKILL.md +1 -1
- package/skills/agent-webex/SKILL.md +1 -1
- package/skills/agent-webex/references/authentication.md +4 -3
- package/skills/agent-webex/references/common-patterns.md +1 -1
- package/skills/agent-wechatbot/SKILL.md +385 -0
- package/skills/agent-whatsapp/SKILL.md +12 -1
- package/skills/agent-whatsappbot/SKILL.md +1 -1
- package/src/platforms/discord/credential-manager.test.ts +18 -1
- package/src/platforms/discordbot/client.ts +2 -2
- package/src/platforms/instagram/commands/auth.test.ts +216 -0
- package/src/platforms/instagram/commands/chat.test.ts +127 -0
- package/src/platforms/instagram/commands/message.test.ts +178 -0
- package/src/platforms/kakaotalk/cli.ts +2 -1
- package/src/platforms/kakaotalk/client.test.ts +157 -0
- package/src/platforms/kakaotalk/client.ts +57 -3
- package/src/platforms/kakaotalk/commands/auth.test.ts +299 -0
- package/src/platforms/kakaotalk/commands/chat.test.ts +97 -0
- package/src/platforms/kakaotalk/commands/index.ts +1 -0
- package/src/platforms/kakaotalk/commands/message.test.ts +113 -0
- package/src/platforms/kakaotalk/commands/profile.test.ts +84 -0
- package/src/platforms/kakaotalk/commands/profile.ts +21 -0
- package/src/platforms/kakaotalk/index.test.ts +5 -0
- package/src/platforms/kakaotalk/index.ts +2 -0
- package/src/platforms/kakaotalk/protocol/session.ts +2 -0
- package/src/platforms/kakaotalk/types.ts +18 -0
- package/src/platforms/line/commands/auth.test.ts +141 -0
- package/src/platforms/line/commands/auth.ts +28 -19
- package/src/platforms/line/commands/chat.test.ts +110 -0
- package/src/platforms/line/commands/friend.test.ts +98 -0
- package/src/platforms/line/commands/message.test.ts +119 -0
- package/src/platforms/line/commands/profile.test.ts +85 -0
- package/src/platforms/slackbot/commands/channel.test.ts +139 -0
- package/src/platforms/slackbot/commands/message.test.ts +226 -0
- package/src/platforms/slackbot/commands/reaction.test.ts +90 -0
- package/src/platforms/slackbot/commands/user.test.ts +143 -0
- package/src/platforms/teams/commands/reaction.test.ts +45 -61
- package/src/platforms/teams/commands/reaction.ts +2 -0
- package/src/platforms/telegram/commands/chat.test.ts +125 -0
- package/src/platforms/telegram/commands/message.test.ts +92 -0
- package/src/platforms/webex/client.ts +98 -26
- package/src/platforms/webex/commands/auth.ts +4 -0
- package/src/platforms/webex/commands/member.test.ts +65 -58
- package/src/platforms/webex/commands/message.test.ts +78 -121
- package/src/platforms/webex/commands/snapshot.test.ts +59 -46
- package/src/platforms/webex/commands/space.test.ts +49 -48
- package/src/platforms/webex/encryption.ts +53 -0
- package/src/platforms/webex/ensure-auth.ts +4 -0
- package/src/platforms/webex/token-extractor.ts +107 -40
- package/src/platforms/webex/types.ts +4 -0
- package/src/platforms/webex/typings/node-jose.d.ts +27 -0
- package/src/platforms/wechatbot/cli.ts +24 -0
- package/src/platforms/wechatbot/client.test.ts +497 -0
- package/src/platforms/wechatbot/client.ts +268 -0
- package/src/platforms/wechatbot/commands/auth.test.ts +211 -0
- package/src/platforms/wechatbot/commands/auth.ts +203 -0
- package/src/platforms/wechatbot/commands/index.ts +4 -0
- package/src/platforms/wechatbot/commands/message.test.ts +155 -0
- package/src/platforms/wechatbot/commands/message.ts +104 -0
- package/src/platforms/wechatbot/commands/shared.ts +22 -0
- package/src/platforms/wechatbot/commands/template.test.ts +199 -0
- package/src/platforms/wechatbot/commands/template.ts +102 -0
- package/src/platforms/wechatbot/commands/user.test.ts +165 -0
- package/src/platforms/wechatbot/commands/user.ts +75 -0
- package/src/platforms/wechatbot/credential-manager.test.ts +255 -0
- package/src/platforms/wechatbot/credential-manager.ts +148 -0
- package/src/platforms/wechatbot/index.test.ts +49 -0
- package/src/platforms/wechatbot/index.ts +19 -0
- package/src/platforms/wechatbot/types.test.ts +223 -0
- package/src/platforms/wechatbot/types.ts +107 -0
- package/src/platforms/whatsapp/client.ts +24 -13
- package/src/platforms/whatsapp/commands/auth.test.ts +311 -0
- package/src/platforms/whatsapp/commands/auth.ts +21 -17
- package/src/platforms/whatsapp/commands/chat.test.ts +198 -0
- package/src/platforms/whatsapp/commands/message.test.ts +231 -0
- package/src/platforms/whatsapp/credential-manager.test.ts +20 -0
- package/src/platforms/whatsapp/credential-manager.ts +17 -8
- package/src/platforms/whatsappbot/commands/auth.test.ts +217 -0
- package/src/platforms/whatsappbot/commands/message.test.ts +198 -0
- package/src/platforms/whatsappbot/commands/template.test.ts +112 -0
|
@@ -1,65 +1,74 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
1
|
+
import { afterAll, afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
2
2
|
|
|
3
|
-
import { WebexClient } from '../client'
|
|
4
3
|
import { WebexError } from '../types'
|
|
4
|
+
|
|
5
|
+
const mockHandleError = mock((err: Error) => {
|
|
6
|
+
throw err
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
mock.module('@/shared/utils/error-handler', () => ({
|
|
10
|
+
handleError: mockHandleError,
|
|
11
|
+
}))
|
|
12
|
+
|
|
13
|
+
const mockMembers = [
|
|
14
|
+
{
|
|
15
|
+
id: 'mem-1',
|
|
16
|
+
roomId: 'room-1',
|
|
17
|
+
personId: 'person-1',
|
|
18
|
+
personEmail: 'alice@example.com',
|
|
19
|
+
personDisplayName: 'Alice',
|
|
20
|
+
isModerator: true,
|
|
21
|
+
created: '2024-01-01T00:00:00.000Z',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
id: 'mem-2',
|
|
25
|
+
roomId: 'room-1',
|
|
26
|
+
personId: 'person-2',
|
|
27
|
+
personEmail: 'bob@example.com',
|
|
28
|
+
personDisplayName: 'Bob',
|
|
29
|
+
isModerator: false,
|
|
30
|
+
created: '2024-01-02T00:00:00.000Z',
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const mockListMemberships = mock(() => Promise.resolve(mockMembers))
|
|
35
|
+
const mockLogin = mock(() => Promise.resolve({ listMemberships: mockListMemberships }))
|
|
36
|
+
|
|
37
|
+
mock.module('../client', () => ({
|
|
38
|
+
WebexClient: class {
|
|
39
|
+
login = mockLogin
|
|
40
|
+
},
|
|
41
|
+
}))
|
|
42
|
+
|
|
5
43
|
import { listAction } from './member'
|
|
6
44
|
|
|
45
|
+
afterAll(() => {
|
|
46
|
+
mock.restore()
|
|
47
|
+
})
|
|
48
|
+
|
|
7
49
|
describe('member commands', () => {
|
|
8
50
|
let consoleSpy: ReturnType<typeof spyOn>
|
|
9
|
-
let consoleErrorSpy: ReturnType<typeof spyOn>
|
|
10
|
-
let processExitSpy: ReturnType<typeof spyOn>
|
|
11
|
-
let stderrOutput: string
|
|
12
|
-
let origStderrWrite: typeof process.stderr.write
|
|
13
|
-
const mockMembers = [
|
|
14
|
-
{
|
|
15
|
-
id: 'mem-1',
|
|
16
|
-
roomId: 'room-1',
|
|
17
|
-
personId: 'person-1',
|
|
18
|
-
personEmail: 'alice@example.com',
|
|
19
|
-
personDisplayName: 'Alice',
|
|
20
|
-
isModerator: true,
|
|
21
|
-
created: '2024-01-01T00:00:00.000Z',
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
id: 'mem-2',
|
|
25
|
-
roomId: 'room-1',
|
|
26
|
-
personId: 'person-2',
|
|
27
|
-
personEmail: 'bob@example.com',
|
|
28
|
-
personDisplayName: 'Bob',
|
|
29
|
-
isModerator: false,
|
|
30
|
-
created: '2024-01-02T00:00:00.000Z',
|
|
31
|
-
},
|
|
32
|
-
]
|
|
33
51
|
|
|
34
52
|
beforeEach(() => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
mockListMemberships.mockReset().mockImplementation(() => Promise.resolve(mockMembers))
|
|
54
|
+
mockLogin.mockReset().mockImplementation(() =>
|
|
55
|
+
Promise.resolve({ listMemberships: mockListMemberships }),
|
|
56
|
+
)
|
|
57
|
+
mockHandleError.mockReset().mockImplementation((err: Error) => {
|
|
58
|
+
throw err
|
|
39
59
|
})
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
43
|
-
stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
|
|
44
|
-
return true
|
|
45
|
-
}) as typeof process.stderr.write
|
|
46
|
-
spyOn(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient() as any)
|
|
47
|
-
spyOn(WebexClient.prototype, 'listMemberships').mockResolvedValue(mockMembers)
|
|
60
|
+
|
|
61
|
+
consoleSpy = spyOn(console, 'log').mockImplementation(() => {})
|
|
48
62
|
})
|
|
49
63
|
|
|
50
64
|
afterEach(() => {
|
|
51
|
-
|
|
52
|
-
mock.restore()
|
|
65
|
+
consoleSpy.mockRestore()
|
|
53
66
|
})
|
|
54
67
|
|
|
55
68
|
test('listAction calls listMemberships with spaceId and outputs mapped members', async () => {
|
|
56
|
-
const listMembershipsSpy = spyOn(WebexClient.prototype, 'listMemberships').mockResolvedValue(
|
|
57
|
-
mockMembers,
|
|
58
|
-
)
|
|
59
|
-
|
|
60
69
|
await listAction('room-1', {})
|
|
61
70
|
|
|
62
|
-
expect(
|
|
71
|
+
expect(mockListMemberships).toHaveBeenCalledWith('room-1', { max: undefined })
|
|
63
72
|
expect(consoleSpy).toHaveBeenCalledWith(
|
|
64
73
|
JSON.stringify([
|
|
65
74
|
{
|
|
@@ -83,30 +92,28 @@ describe('member commands', () => {
|
|
|
83
92
|
})
|
|
84
93
|
|
|
85
94
|
test('listAction passes limit option to listMemberships', async () => {
|
|
86
|
-
const listMembershipsSpy = spyOn(WebexClient.prototype, 'listMemberships').mockResolvedValue(
|
|
87
|
-
mockMembers,
|
|
88
|
-
)
|
|
89
|
-
|
|
90
95
|
await listAction('room-1', { limit: 25 })
|
|
91
96
|
|
|
92
|
-
expect(
|
|
97
|
+
expect(mockListMemberships).toHaveBeenCalledWith('room-1', { max: 25 })
|
|
93
98
|
})
|
|
94
99
|
|
|
95
100
|
test('listAction handles not-authenticated case', async () => {
|
|
96
|
-
|
|
97
|
-
new WebexError('No Webex credentials found.', 'no_credentials')
|
|
98
|
-
)
|
|
101
|
+
mockLogin.mockImplementation(async () => {
|
|
102
|
+
throw new WebexError('No Webex credentials found.', 'no_credentials')
|
|
103
|
+
})
|
|
99
104
|
|
|
100
|
-
await expect(listAction('room-1', {})).rejects.toThrow('
|
|
105
|
+
await expect(listAction('room-1', {})).rejects.toThrow('No Webex credentials found.')
|
|
101
106
|
|
|
102
|
-
expect(
|
|
107
|
+
expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
|
|
103
108
|
})
|
|
104
109
|
|
|
105
110
|
test('listAction handles API error', async () => {
|
|
106
|
-
|
|
111
|
+
mockListMemberships.mockImplementation(async () => {
|
|
112
|
+
throw new Error('API failure')
|
|
113
|
+
})
|
|
107
114
|
|
|
108
|
-
await expect(listAction('room-1', {})).rejects.toThrow('
|
|
115
|
+
await expect(listAction('room-1', {})).rejects.toThrow('API failure')
|
|
109
116
|
|
|
110
|
-
expect(
|
|
117
|
+
expect(mockHandleError).toHaveBeenCalledWith(expect.any(Error))
|
|
111
118
|
})
|
|
112
119
|
})
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import { afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
|
|
1
|
+
import { afterAll, afterEach, beforeEach, expect, mock, spyOn, test } from 'bun:test'
|
|
2
2
|
|
|
3
|
-
import { WebexClient } from '../client'
|
|
4
3
|
import { WebexError } from '../types'
|
|
5
|
-
import { deleteAction, dmAction, editAction, getAction, listAction, sendAction } from './message'
|
|
6
4
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const originalConsoleLog = console.log
|
|
15
|
-
const originalConsoleError = console.error
|
|
5
|
+
const mockHandleError = mock((err: Error) => {
|
|
6
|
+
throw err
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
mock.module('@/shared/utils/error-handler', () => ({
|
|
10
|
+
handleError: mockHandleError,
|
|
11
|
+
}))
|
|
16
12
|
|
|
17
13
|
const mockMessage = {
|
|
18
14
|
id: 'msg_123',
|
|
@@ -34,202 +30,163 @@ const mockMessage2 = {
|
|
|
34
30
|
created: '2025-01-29T10:01:00.000Z',
|
|
35
31
|
}
|
|
36
32
|
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
const mockSendMessage = mock(() => Promise.resolve(mockMessage))
|
|
34
|
+
const mockSendDirectMessage = mock(() => Promise.resolve(mockMessage))
|
|
35
|
+
const mockListMessages = mock(() => Promise.resolve([mockMessage, mockMessage2]))
|
|
36
|
+
const mockGetMessage = mock(() => Promise.resolve(mockMessage))
|
|
37
|
+
const mockDeleteMessage = mock(() => Promise.resolve(undefined))
|
|
38
|
+
const mockEditMessage = mock(() => Promise.resolve({ ...mockMessage, text: 'Updated message' }))
|
|
39
|
+
|
|
40
|
+
const mockClient = {
|
|
41
|
+
sendMessage: mockSendMessage,
|
|
42
|
+
sendDirectMessage: mockSendDirectMessage,
|
|
43
|
+
listMessages: mockListMessages,
|
|
44
|
+
getMessage: mockGetMessage,
|
|
45
|
+
deleteMessage: mockDeleteMessage,
|
|
46
|
+
editMessage: mockEditMessage,
|
|
47
|
+
}
|
|
39
48
|
|
|
40
|
-
|
|
49
|
+
const mockLogin = mock(() => Promise.resolve(mockClient))
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
mock.module('../client', () => ({
|
|
52
|
+
WebexClient: class {
|
|
53
|
+
login = mockLogin
|
|
54
|
+
},
|
|
55
|
+
}))
|
|
43
56
|
|
|
44
|
-
|
|
45
|
-
mockMessage,
|
|
46
|
-
mockMessage2,
|
|
47
|
-
])
|
|
57
|
+
import { deleteAction, dmAction, editAction, getAction, listAction, sendAction } from './message'
|
|
48
58
|
|
|
49
|
-
|
|
59
|
+
afterAll(() => {
|
|
60
|
+
mock.restore()
|
|
61
|
+
})
|
|
50
62
|
|
|
51
|
-
|
|
52
|
-
undefined,
|
|
53
|
-
)
|
|
63
|
+
let consoleLogSpy: ReturnType<typeof spyOn>
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
65
|
+
beforeEach(() => {
|
|
66
|
+
mockSendMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
|
|
67
|
+
mockSendDirectMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
|
|
68
|
+
mockListMessages.mockReset().mockImplementation(() => Promise.resolve([mockMessage, mockMessage2]))
|
|
69
|
+
mockGetMessage.mockReset().mockImplementation(() => Promise.resolve(mockMessage))
|
|
70
|
+
mockDeleteMessage.mockReset().mockImplementation(() => Promise.resolve(undefined))
|
|
71
|
+
mockEditMessage.mockReset().mockImplementation(() => Promise.resolve({ ...mockMessage, text: 'Updated message' }))
|
|
72
|
+
mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
|
|
73
|
+
mockHandleError.mockReset().mockImplementation((err: Error) => {
|
|
74
|
+
throw err
|
|
58
75
|
})
|
|
76
|
+
|
|
77
|
+
consoleLogSpy = spyOn(console, 'log').mockImplementation(() => {})
|
|
59
78
|
})
|
|
60
79
|
|
|
61
80
|
afterEach(() => {
|
|
62
|
-
|
|
63
|
-
clientSendMessageSpy?.mockRestore()
|
|
64
|
-
clientSendDirectMessageSpy?.mockRestore()
|
|
65
|
-
clientListMessagesSpy?.mockRestore()
|
|
66
|
-
clientGetMessageSpy?.mockRestore()
|
|
67
|
-
clientDeleteMessageSpy?.mockRestore()
|
|
68
|
-
clientEditMessageSpy?.mockRestore()
|
|
69
|
-
console.log = originalConsoleLog
|
|
70
|
-
console.error = originalConsoleError
|
|
81
|
+
consoleLogSpy.mockRestore()
|
|
71
82
|
})
|
|
72
83
|
|
|
73
84
|
test('send: calls sendMessage with correct args and outputs result', async () => {
|
|
74
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
75
|
-
console.log = consoleSpy
|
|
76
|
-
|
|
77
85
|
await sendAction('space_456', 'Hello world', { pretty: false })
|
|
78
86
|
|
|
79
|
-
expect(
|
|
87
|
+
expect(mockSendMessage).toHaveBeenCalledWith('space_456', 'Hello world', {
|
|
80
88
|
markdown: undefined,
|
|
81
89
|
})
|
|
82
|
-
expect(
|
|
83
|
-
const output =
|
|
90
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
91
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
84
92
|
expect(output).toContain('msg_123')
|
|
85
93
|
expect(output).toContain('space_456')
|
|
86
94
|
expect(output).toContain('user@example.com')
|
|
87
95
|
})
|
|
88
96
|
|
|
89
97
|
test('send: with --markdown passes markdown option', async () => {
|
|
90
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
91
|
-
console.log = consoleSpy
|
|
92
|
-
|
|
93
98
|
await sendAction('space_456', '**bold**', { markdown: true, pretty: false })
|
|
94
99
|
|
|
95
|
-
expect(
|
|
100
|
+
expect(mockSendMessage).toHaveBeenCalledWith('space_456', '**bold**', { markdown: true })
|
|
96
101
|
})
|
|
97
102
|
|
|
98
103
|
test('send: not authenticated shows error', async () => {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const origWrite = process.stderr.write
|
|
103
|
-
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
104
|
-
stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
|
|
105
|
-
return true
|
|
106
|
-
}) as typeof process.stderr.write
|
|
104
|
+
mockLogin.mockImplementation(async () => {
|
|
105
|
+
throw new WebexError('No Webex credentials found.', 'no_credentials')
|
|
106
|
+
})
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
process.exit = mock((_code?: number) => {
|
|
110
|
-
throw new Error('process.exit called')
|
|
111
|
-
}) as never
|
|
108
|
+
await expect(sendAction('space_456', 'Hello', { pretty: false })).rejects.toThrow('No Webex credentials found.')
|
|
112
109
|
|
|
113
|
-
|
|
114
|
-
await sendAction('space_456', 'Hello', { pretty: false })
|
|
115
|
-
} catch {
|
|
116
|
-
} finally {
|
|
117
|
-
process.exit = originalExit
|
|
118
|
-
process.stderr.write = origWrite
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
expect(stderrOutput).toContain('No Webex credentials found')
|
|
110
|
+
expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
|
|
122
111
|
})
|
|
123
112
|
|
|
124
113
|
test('dm: calls sendDirectMessage with email and text', async () => {
|
|
125
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
126
|
-
console.log = consoleSpy
|
|
127
|
-
|
|
128
114
|
await dmAction('alice@example.com', 'Hello!', { pretty: false })
|
|
129
115
|
|
|
130
|
-
expect(
|
|
116
|
+
expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', 'Hello!', {
|
|
131
117
|
markdown: undefined,
|
|
132
118
|
})
|
|
133
|
-
expect(
|
|
134
|
-
const output =
|
|
119
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
120
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
135
121
|
expect(output).toContain('msg_123')
|
|
136
122
|
})
|
|
137
123
|
|
|
138
124
|
test('dm: with --markdown passes markdown option', async () => {
|
|
139
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
140
|
-
console.log = consoleSpy
|
|
141
|
-
|
|
142
125
|
await dmAction('alice@example.com', '**bold**', { markdown: true, pretty: false })
|
|
143
126
|
|
|
144
|
-
expect(
|
|
127
|
+
expect(mockSendDirectMessage).toHaveBeenCalledWith('alice@example.com', '**bold**', {
|
|
145
128
|
markdown: true,
|
|
146
129
|
})
|
|
147
130
|
})
|
|
148
131
|
|
|
149
132
|
test('list: calls listMessages with limit and outputs array', async () => {
|
|
150
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
151
|
-
console.log = consoleSpy
|
|
152
|
-
|
|
153
133
|
await listAction('space_456', { limit: 50, pretty: false })
|
|
154
134
|
|
|
155
|
-
expect(
|
|
156
|
-
expect(
|
|
157
|
-
const output =
|
|
135
|
+
expect(mockListMessages).toHaveBeenCalledWith('space_456', { max: 50 })
|
|
136
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
137
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
158
138
|
expect(output).toContain('msg_123')
|
|
159
139
|
expect(output).toContain('msg_124')
|
|
160
140
|
})
|
|
161
141
|
|
|
162
142
|
test('get: calls getMessage with correct id and outputs result', async () => {
|
|
163
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
164
|
-
console.log = consoleSpy
|
|
165
|
-
|
|
166
143
|
await getAction('msg_123', { pretty: false })
|
|
167
144
|
|
|
168
|
-
expect(
|
|
169
|
-
expect(
|
|
170
|
-
const output =
|
|
145
|
+
expect(mockGetMessage).toHaveBeenCalledWith('msg_123')
|
|
146
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
147
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
171
148
|
expect(output).toContain('msg_123')
|
|
172
149
|
expect(output).toContain('user@example.com')
|
|
173
150
|
})
|
|
174
151
|
|
|
175
152
|
test('delete: with --force calls deleteMessage and outputs deleted id', async () => {
|
|
176
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
177
|
-
console.log = consoleSpy
|
|
178
|
-
|
|
179
153
|
await deleteAction('msg_123', { force: true, pretty: false })
|
|
180
154
|
|
|
181
|
-
expect(
|
|
182
|
-
expect(
|
|
183
|
-
const output =
|
|
155
|
+
expect(mockDeleteMessage).toHaveBeenCalledWith('msg_123')
|
|
156
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
157
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
184
158
|
expect(output).toContain('deleted')
|
|
185
159
|
expect(output).toContain('msg_123')
|
|
186
160
|
})
|
|
187
161
|
|
|
188
162
|
test('delete: without --force shows warning and does not delete', async () => {
|
|
189
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
190
|
-
console.log = consoleSpy
|
|
191
|
-
|
|
192
|
-
const originalExit = process.exit
|
|
193
|
-
process.exit = mock((_code?: number) => {
|
|
194
|
-
throw new Error('process.exit called')
|
|
195
|
-
}) as never
|
|
196
|
-
|
|
197
163
|
try {
|
|
198
164
|
await deleteAction('msg_123', { force: false, pretty: false })
|
|
199
|
-
} catch {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
expect(clientDeleteMessageSpy).not.toHaveBeenCalled()
|
|
205
|
-
expect(consoleSpy).toHaveBeenCalled()
|
|
206
|
-
const output = consoleSpy.mock.calls[0][0]
|
|
165
|
+
} catch {}
|
|
166
|
+
|
|
167
|
+
expect(mockDeleteMessage).not.toHaveBeenCalled()
|
|
168
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
169
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
207
170
|
expect(output).toContain('warning')
|
|
208
171
|
expect(output).toContain('--force')
|
|
209
172
|
})
|
|
210
173
|
|
|
211
174
|
test('edit: calls editMessage with roomId in args and outputs result', async () => {
|
|
212
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
213
|
-
console.log = consoleSpy
|
|
214
|
-
|
|
215
175
|
await editAction('msg_123', 'space_456', 'Updated message', { pretty: false })
|
|
216
176
|
|
|
217
|
-
expect(
|
|
177
|
+
expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', 'Updated message', {
|
|
218
178
|
markdown: undefined,
|
|
219
179
|
})
|
|
220
|
-
expect(
|
|
221
|
-
const output =
|
|
180
|
+
expect(consoleLogSpy).toHaveBeenCalled()
|
|
181
|
+
const output = consoleLogSpy.mock.calls[0][0]
|
|
222
182
|
expect(output).toContain('msg_123')
|
|
223
183
|
expect(output).toContain('Updated message')
|
|
224
184
|
})
|
|
225
185
|
|
|
226
186
|
test('edit: with --markdown passes markdown option', async () => {
|
|
227
|
-
const consoleSpy = mock((_msg: string) => {})
|
|
228
|
-
console.log = consoleSpy
|
|
229
|
-
|
|
230
187
|
await editAction('msg_123', 'space_456', '**updated**', { markdown: true, pretty: false })
|
|
231
188
|
|
|
232
|
-
expect(
|
|
189
|
+
expect(mockEditMessage).toHaveBeenCalledWith('msg_123', 'space_456', '**updated**', {
|
|
233
190
|
markdown: true,
|
|
234
191
|
})
|
|
235
192
|
})
|
|
@@ -1,44 +1,67 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
2
|
-
import { WebexClient } from '../client'
|
|
1
|
+
import { afterAll, afterEach, beforeEach, describe, expect, mock, spyOn, test } from 'bun:test'
|
|
3
2
|
import { WebexError } from '../types'
|
|
4
|
-
import { snapshotAction } from './snapshot'
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
const mockHandleError = mock((err: Error) => {
|
|
5
|
+
throw err
|
|
6
|
+
})
|
|
7
|
+
|
|
8
|
+
mock.module('@/shared/utils/error-handler', () => ({
|
|
9
|
+
handleError: mockHandleError,
|
|
10
|
+
}))
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
const mockSpaces = [
|
|
13
|
+
{ id: 'space-1', title: 'General', type: 'group', isLocked: false, lastActivity: '2024-01-15T00:00:00.000Z', created: '2024-01-01T00:00:00.000Z', creatorId: 'person-1' },
|
|
14
|
+
]
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const mockMessages = [
|
|
17
|
+
{ id: 'msg-1', roomId: 'space-1', roomType: 'group', text: 'Hello', personId: 'person-1', personEmail: 'alice@example.com', created: '2024-01-15T00:00:00.000Z' },
|
|
18
|
+
]
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const mockMembers = [
|
|
21
|
+
{ id: 'mem-1', roomId: 'space-1', personId: 'person-1', personEmail: 'alice@example.com', personDisplayName: 'Alice', isModerator: true, created: '2024-01-01T00:00:00.000Z' },
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
const mockListSpaces = mock(() => Promise.resolve(mockSpaces as any))
|
|
25
|
+
const mockListMessages = mock(() => Promise.resolve(mockMessages as any))
|
|
26
|
+
const mockListMemberships = mock(() => Promise.resolve(mockMembers as any))
|
|
27
|
+
|
|
28
|
+
const mockClient = {
|
|
29
|
+
listSpaces: mockListSpaces,
|
|
30
|
+
listMessages: mockListMessages,
|
|
31
|
+
listMemberships: mockListMemberships,
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const mockLogin = mock(() => Promise.resolve(mockClient))
|
|
35
|
+
|
|
36
|
+
mock.module('../client', () => ({
|
|
37
|
+
WebexClient: class {
|
|
38
|
+
login = mockLogin
|
|
39
|
+
},
|
|
40
|
+
}))
|
|
41
|
+
|
|
42
|
+
import { snapshotAction } from './snapshot'
|
|
43
|
+
|
|
44
|
+
afterAll(() => {
|
|
45
|
+
mock.restore()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
describe('snapshot command', () => {
|
|
49
|
+
let consoleSpy: ReturnType<typeof spyOn>
|
|
23
50
|
|
|
24
51
|
beforeEach(() => {
|
|
52
|
+
mockListSpaces.mockReset().mockImplementation(() => Promise.resolve(mockSpaces as any))
|
|
53
|
+
mockListMessages.mockReset().mockImplementation(() => Promise.resolve(mockMessages as any))
|
|
54
|
+
mockListMemberships.mockReset().mockImplementation(() => Promise.resolve(mockMembers as any))
|
|
55
|
+
mockLogin.mockReset().mockImplementation(() => Promise.resolve(mockClient))
|
|
56
|
+
mockHandleError.mockReset().mockImplementation((err: Error) => {
|
|
57
|
+
throw err
|
|
58
|
+
})
|
|
59
|
+
|
|
25
60
|
consoleSpy = spyOn(console, 'log').mockImplementation(() => {})
|
|
26
|
-
consoleErrorSpy = spyOn(console, 'error').mockImplementation(() => {})
|
|
27
|
-
stderrOutput = ''
|
|
28
|
-
origStderrWrite = process.stderr.write
|
|
29
|
-
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
30
|
-
stderrOutput += typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk)
|
|
31
|
-
return true
|
|
32
|
-
}) as typeof process.stderr.write
|
|
33
|
-
spyOn(WebexClient.prototype, 'login').mockResolvedValue(new WebexClient() as any)
|
|
34
|
-
spyOn(WebexClient.prototype, 'listSpaces').mockResolvedValue(mockSpaces as any)
|
|
35
|
-
spyOn(WebexClient.prototype, 'listMessages').mockResolvedValue(mockMessages as any)
|
|
36
|
-
spyOn(WebexClient.prototype, 'listMemberships').mockResolvedValue(mockMembers as any)
|
|
37
61
|
})
|
|
38
62
|
|
|
39
63
|
afterEach(() => {
|
|
40
|
-
|
|
41
|
-
mock.restore()
|
|
64
|
+
consoleSpy.mockRestore()
|
|
42
65
|
})
|
|
43
66
|
|
|
44
67
|
test('full snapshot includes spaces, recent_messages, members', async () => {
|
|
@@ -78,28 +101,18 @@ describe('snapshot command', () => {
|
|
|
78
101
|
})
|
|
79
102
|
|
|
80
103
|
test('not authenticated outputs error', async () => {
|
|
81
|
-
|
|
82
|
-
new WebexError('No Webex credentials found.', 'no_credentials')
|
|
83
|
-
)
|
|
104
|
+
mockLogin.mockImplementation(async () => {
|
|
105
|
+
throw new WebexError('No Webex credentials found.', 'no_credentials')
|
|
106
|
+
})
|
|
84
107
|
|
|
85
|
-
|
|
86
|
-
process.exit = mock((_code?: number) => { throw new Error('process.exit called') }) as never
|
|
108
|
+
await expect(snapshotAction({})).rejects.toThrow('No Webex credentials found.')
|
|
87
109
|
|
|
88
|
-
|
|
89
|
-
await snapshotAction({})
|
|
90
|
-
} catch {
|
|
91
|
-
} finally {
|
|
92
|
-
process.exit = originalExit
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
expect(stderrOutput).toContain('No Webex credentials found')
|
|
110
|
+
expect(mockHandleError).toHaveBeenCalledWith(expect.any(WebexError))
|
|
96
111
|
})
|
|
97
112
|
|
|
98
113
|
test('passes limit option to listMessages', async () => {
|
|
99
|
-
const listMessagesSpy = spyOn(WebexClient.prototype, 'listMessages').mockResolvedValue(mockMessages as any)
|
|
100
|
-
|
|
101
114
|
await snapshotAction({ limit: 5 })
|
|
102
115
|
|
|
103
|
-
expect(
|
|
116
|
+
expect(mockListMessages).toHaveBeenCalledWith('space-1', { max: 5 })
|
|
104
117
|
})
|
|
105
118
|
})
|