agent-messenger 1.0.0 → 1.1.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/commands/release.md +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/e2e.yml.disabled +69 -0
- package/README.md +16 -14
- package/biome.json +33 -1
- package/bun.lock +63 -0
- package/dist/package.json +8 -4
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +4 -1
- package/dist/src/cli.js.map +1 -1
- package/dist/src/platforms/discord/cli.js +1 -1
- package/dist/src/platforms/discord/client.d.ts.map +1 -1
- package/dist/src/platforms/discord/client.js +3 -3
- package/dist/src/platforms/discord/client.js.map +1 -1
- package/dist/src/platforms/discord/commands/user.d.ts.map +1 -1
- package/dist/src/platforms/discord/commands/user.js +10 -1
- package/dist/src/platforms/discord/commands/user.js.map +1 -1
- package/dist/src/platforms/discord/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/discord/credential-manager.js +18 -12
- package/dist/src/platforms/discord/credential-manager.js.map +1 -1
- package/dist/src/platforms/slack/cli.js +1 -1
- package/dist/src/platforms/slack/credential-manager.d.ts.map +1 -1
- package/dist/src/platforms/slack/credential-manager.js +20 -6
- package/dist/src/platforms/slack/credential-manager.js.map +1 -1
- package/dist/src/platforms/slack/token-extractor.d.ts.map +1 -1
- package/dist/src/platforms/slack/token-extractor.js +34 -9
- package/dist/src/platforms/slack/token-extractor.js.map +1 -1
- package/dist/src/platforms/teams/cli.d.ts.map +1 -0
- package/dist/{cli.js → src/platforms/teams/cli.js} +11 -10
- package/dist/src/platforms/teams/cli.js.map +1 -0
- package/dist/src/platforms/teams/client.d.ts +32 -0
- package/dist/src/platforms/teams/client.d.ts.map +1 -0
- package/dist/src/platforms/teams/client.js +202 -0
- package/dist/src/platforms/teams/client.js.map +1 -0
- package/dist/src/platforms/teams/commands/auth.d.ts +14 -0
- package/dist/src/platforms/teams/commands/auth.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/auth.js +176 -0
- package/dist/src/platforms/teams/commands/auth.js.map +1 -0
- package/dist/src/platforms/teams/commands/channel.d.ts +13 -0
- package/dist/src/platforms/teams/commands/channel.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/channel.js +97 -0
- package/dist/src/platforms/teams/commands/channel.js.map +1 -0
- package/dist/src/platforms/teams/commands/file.d.ts +12 -0
- package/dist/src/platforms/teams/commands/file.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/file.js +104 -0
- package/dist/src/platforms/teams/commands/file.js.map +1 -0
- package/dist/{commands → src/platforms/teams/commands}/index.d.ts +5 -2
- package/dist/src/platforms/teams/commands/index.d.ts.map +1 -0
- package/dist/{commands → src/platforms/teams/commands}/index.js +5 -2
- package/dist/src/platforms/teams/commands/index.js.map +1 -0
- package/dist/src/platforms/teams/commands/message.d.ts +17 -0
- package/dist/src/platforms/teams/commands/message.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/message.js +133 -0
- package/dist/src/platforms/teams/commands/message.js.map +1 -0
- package/dist/src/platforms/teams/commands/reaction.d.ts +9 -0
- package/dist/src/platforms/teams/commands/reaction.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/reaction.js +68 -0
- package/dist/src/platforms/teams/commands/reaction.js.map +1 -0
- package/dist/src/platforms/teams/commands/snapshot.d.ts +10 -0
- package/dist/src/platforms/teams/commands/snapshot.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/snapshot.js +85 -0
- package/dist/src/platforms/teams/commands/snapshot.js.map +1 -0
- package/dist/src/platforms/teams/commands/team.d.ts +18 -0
- package/dist/src/platforms/teams/commands/team.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/team.js +130 -0
- package/dist/src/platforms/teams/commands/team.js.map +1 -0
- package/dist/src/platforms/teams/commands/user.d.ts.map +1 -0
- package/dist/src/platforms/teams/commands/user.js +88 -0
- package/dist/src/platforms/teams/commands/user.js.map +1 -0
- package/dist/src/platforms/teams/credential-manager.d.ts +18 -0
- package/dist/src/platforms/teams/credential-manager.d.ts.map +1 -0
- package/dist/src/platforms/teams/credential-manager.js +81 -0
- package/dist/src/platforms/teams/credential-manager.js.map +1 -0
- package/dist/src/platforms/teams/index.d.ts +4 -0
- package/dist/src/platforms/teams/index.d.ts.map +1 -0
- package/dist/src/platforms/teams/index.js +6 -0
- package/dist/src/platforms/teams/index.js.map +1 -0
- package/dist/src/platforms/teams/token-extractor.d.ts +36 -0
- package/dist/src/platforms/teams/token-extractor.d.ts.map +1 -0
- package/dist/src/platforms/teams/token-extractor.js +335 -0
- package/dist/src/platforms/teams/token-extractor.js.map +1 -0
- package/dist/src/platforms/teams/types.d.ts +209 -0
- package/dist/src/platforms/teams/types.d.ts.map +1 -0
- package/dist/src/platforms/teams/types.js +65 -0
- package/dist/src/platforms/teams/types.js.map +1 -0
- package/docs/teams.md +321 -0
- package/e2e/README.md +256 -0
- package/e2e/config.ts +45 -0
- package/e2e/discord.e2e.test.ts +252 -0
- package/e2e/helpers.ts +107 -0
- package/e2e/slack.e2e.test.ts +309 -0
- package/package.json +8 -4
- package/scripts/postbuild.ts +15 -0
- package/skills/agent-teams/SKILL.md +292 -0
- package/skills/agent-teams/references/authentication.md +375 -0
- package/skills/agent-teams/references/common-patterns.md +596 -0
- package/skills/agent-teams/templates/monitor-channel.sh +239 -0
- package/skills/agent-teams/templates/post-message.sh +224 -0
- package/skills/agent-teams/templates/team-summary.sh +210 -0
- package/src/cli.ts +4 -0
- package/src/platforms/discord/client.ts +3 -3
- package/src/platforms/discord/commands/auth.test.ts +48 -32
- package/src/platforms/discord/commands/channel.test.ts +54 -42
- package/src/platforms/discord/commands/file.test.ts +40 -53
- package/src/platforms/discord/commands/guild.test.ts +47 -27
- package/src/platforms/discord/commands/message.test.ts +54 -51
- package/src/platforms/discord/commands/reaction.test.ts +54 -42
- package/src/platforms/discord/commands/user.ts +12 -1
- package/src/platforms/discord/credential-manager.test.ts +137 -136
- package/src/platforms/discord/credential-manager.ts +20 -13
- package/src/platforms/discord/token-extractor.test.ts +133 -383
- package/{tests → src/platforms/slack}/cli.test.ts +3 -3
- package/{tests/slack-client.test.ts → src/platforms/slack/client.test.ts} +1 -1
- package/{tests → src/platforms/slack}/commands/auth.test.ts +25 -13
- package/{tests → src/platforms/slack}/commands/channel.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/file.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/message.test.ts +2 -2
- package/{tests → src/platforms/slack}/commands/reaction.test.ts +1 -1
- package/{tests → src/platforms/slack}/commands/snapshot.test.ts +117 -105
- package/{tests → src/platforms/slack}/commands/user.test.ts +3 -3
- package/{tests → src/platforms/slack}/commands/workspace.test.ts +44 -95
- package/{tests → src/platforms/slack}/credential-manager.test.ts +2 -2
- package/src/platforms/slack/credential-manager.ts +22 -7
- package/src/platforms/slack/token-extractor-node-test.ts +40 -0
- package/src/platforms/slack/token-extractor-node.test.ts +10 -0
- package/src/platforms/slack/token-extractor.ts +36 -10
- package/{tests → src/platforms/slack}/types.test.ts +1 -1
- package/src/platforms/teams/cli.ts +36 -0
- package/src/platforms/teams/client.test.ts +500 -0
- package/src/platforms/teams/client.ts +365 -0
- package/src/platforms/teams/commands/auth.test.ts +99 -0
- package/src/platforms/teams/commands/auth.ts +232 -0
- package/src/platforms/teams/commands/channel.test.ts +147 -0
- package/src/platforms/teams/commands/channel.ts +129 -0
- package/src/platforms/teams/commands/file.test.ts +88 -0
- package/src/platforms/teams/commands/file.ts +144 -0
- package/src/platforms/teams/commands/index.ts +12 -0
- package/src/platforms/teams/commands/message.test.ts +110 -0
- package/src/platforms/teams/commands/message.ts +188 -0
- package/src/platforms/teams/commands/reaction.test.ts +87 -0
- package/src/platforms/teams/commands/reaction.ts +104 -0
- package/src/platforms/teams/commands/snapshot.test.ts +35 -0
- package/src/platforms/teams/commands/snapshot.ts +115 -0
- package/src/platforms/teams/commands/team.test.ts +157 -0
- package/src/platforms/teams/commands/team.ts +164 -0
- package/src/platforms/teams/commands/user.test.ts +83 -0
- package/src/platforms/teams/commands/user.ts +112 -0
- package/src/platforms/teams/credential-manager.test.ts +178 -0
- package/src/platforms/teams/credential-manager.ts +92 -0
- package/src/platforms/teams/index.ts +5 -0
- package/src/platforms/teams/token-extractor.test.ts +429 -0
- package/src/platforms/teams/token-extractor.ts +462 -0
- package/src/platforms/teams/types.test.ts +226 -0
- package/src/platforms/teams/types.ts +140 -0
- package/tsconfig.json +1 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/auth.d.ts +0 -3
- package/dist/commands/auth.d.ts.map +0 -1
- package/dist/commands/auth.js +0 -140
- package/dist/commands/auth.js.map +0 -1
- package/dist/commands/channel.d.ts +0 -3
- package/dist/commands/channel.d.ts.map +0 -1
- package/dist/commands/channel.js +0 -118
- package/dist/commands/channel.js.map +0 -1
- package/dist/commands/file.d.ts +0 -3
- package/dist/commands/file.d.ts.map +0 -1
- package/dist/commands/file.js +0 -113
- package/dist/commands/file.js.map +0 -1
- package/dist/commands/index.d.ts.map +0 -1
- package/dist/commands/index.js.map +0 -1
- package/dist/commands/message.d.ts +0 -3
- package/dist/commands/message.d.ts.map +0 -1
- package/dist/commands/message.js +0 -214
- package/dist/commands/message.js.map +0 -1
- package/dist/commands/reaction.d.ts +0 -3
- package/dist/commands/reaction.d.ts.map +0 -1
- package/dist/commands/reaction.js +0 -100
- package/dist/commands/reaction.js.map +0 -1
- package/dist/commands/snapshot.d.ts +0 -3
- package/dist/commands/snapshot.d.ts.map +0 -1
- package/dist/commands/snapshot.js +0 -88
- package/dist/commands/snapshot.js.map +0 -1
- package/dist/commands/user.d.ts.map +0 -1
- package/dist/commands/user.js +0 -96
- package/dist/commands/user.js.map +0 -1
- package/dist/commands/workspace.d.ts +0 -3
- package/dist/commands/workspace.d.ts.map +0 -1
- package/dist/commands/workspace.js +0 -89
- package/dist/commands/workspace.js.map +0 -1
- package/dist/lib/credential-manager.d.ts +0 -13
- package/dist/lib/credential-manager.d.ts.map +0 -1
- package/dist/lib/credential-manager.js +0 -58
- package/dist/lib/credential-manager.js.map +0 -1
- package/dist/lib/index.d.ts +0 -3
- package/dist/lib/index.d.ts.map +0 -1
- package/dist/lib/index.js +0 -3
- package/dist/lib/index.js.map +0 -1
- package/dist/lib/ref-manager.d.ts +0 -26
- package/dist/lib/ref-manager.d.ts.map +0 -1
- package/dist/lib/ref-manager.js +0 -92
- package/dist/lib/ref-manager.js.map +0 -1
- package/dist/lib/slack-client.d.ts +0 -37
- package/dist/lib/slack-client.d.ts.map +0 -1
- package/dist/lib/slack-client.js +0 -379
- package/dist/lib/slack-client.js.map +0 -1
- package/dist/lib/token-extractor.d.ts +0 -28
- package/dist/lib/token-extractor.d.ts.map +0 -1
- package/dist/lib/token-extractor.js +0 -401
- package/dist/lib/token-extractor.js.map +0 -1
- package/dist/src/platforms/discord/client.test.d.ts +0 -2
- package/dist/src/platforms/discord/client.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/client.test.js +0 -367
- package/dist/src/platforms/discord/client.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/auth.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/auth.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/auth.test.js +0 -65
- package/dist/src/platforms/discord/commands/auth.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/channel.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/channel.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/channel.test.js +0 -136
- package/dist/src/platforms/discord/commands/channel.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/file.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/file.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/file.test.js +0 -83
- package/dist/src/platforms/discord/commands/file.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/guild.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/guild.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/guild.test.js +0 -100
- package/dist/src/platforms/discord/commands/guild.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/message.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/message.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/message.test.js +0 -91
- package/dist/src/platforms/discord/commands/message.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/reaction.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/reaction.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/reaction.test.js +0 -115
- package/dist/src/platforms/discord/commands/reaction.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/snapshot.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/snapshot.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/snapshot.test.js +0 -25
- package/dist/src/platforms/discord/commands/snapshot.test.js.map +0 -1
- package/dist/src/platforms/discord/commands/user.test.d.ts +0 -2
- package/dist/src/platforms/discord/commands/user.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/commands/user.test.js +0 -103
- package/dist/src/platforms/discord/commands/user.test.js.map +0 -1
- package/dist/src/platforms/discord/credential-manager.test.d.ts +0 -2
- package/dist/src/platforms/discord/credential-manager.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/credential-manager.test.js +0 -136
- package/dist/src/platforms/discord/credential-manager.test.js.map +0 -1
- package/dist/src/platforms/discord/token-extractor.test.d.ts +0 -2
- package/dist/src/platforms/discord/token-extractor.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/token-extractor.test.js +0 -789
- package/dist/src/platforms/discord/token-extractor.test.js.map +0 -1
- package/dist/src/platforms/discord/types.test.d.ts +0 -2
- package/dist/src/platforms/discord/types.test.d.ts.map +0 -1
- package/dist/src/platforms/discord/types.test.js +0 -211
- package/dist/src/platforms/discord/types.test.js.map +0 -1
- package/dist/src/shared/utils/concurrency.test.d.ts +0 -2
- package/dist/src/shared/utils/concurrency.test.d.ts.map +0 -1
- package/dist/src/shared/utils/concurrency.test.js +0 -39
- package/dist/src/shared/utils/concurrency.test.js.map +0 -1
- package/dist/tests/cli.test.d.ts +0 -2
- package/dist/tests/cli.test.d.ts.map +0 -1
- package/dist/tests/cli.test.js +0 -83
- package/dist/tests/cli.test.js.map +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/CURRENT +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOCK +0 -0
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG +0 -3
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/LOG.old +0 -1
- package/dist/tests/commands/.test-slack-data/Local Storage/leveldb/MANIFEST-000004 +0 -0
- package/dist/tests/commands/auth.test.d.ts +0 -2
- package/dist/tests/commands/auth.test.d.ts.map +0 -1
- package/dist/tests/commands/auth.test.js +0 -304
- package/dist/tests/commands/auth.test.js.map +0 -1
- package/dist/tests/commands/channel.test.d.ts +0 -2
- package/dist/tests/commands/channel.test.d.ts.map +0 -1
- package/dist/tests/commands/channel.test.js +0 -166
- package/dist/tests/commands/channel.test.js.map +0 -1
- package/dist/tests/commands/file.test.d.ts +0 -2
- package/dist/tests/commands/file.test.d.ts.map +0 -1
- package/dist/tests/commands/file.test.js +0 -175
- package/dist/tests/commands/file.test.js.map +0 -1
- package/dist/tests/commands/message.test.d.ts +0 -2
- package/dist/tests/commands/message.test.d.ts.map +0 -1
- package/dist/tests/commands/message.test.js +0 -293
- package/dist/tests/commands/message.test.js.map +0 -1
- package/dist/tests/commands/reaction.test.d.ts +0 -2
- package/dist/tests/commands/reaction.test.d.ts.map +0 -1
- package/dist/tests/commands/reaction.test.js +0 -84
- package/dist/tests/commands/reaction.test.js.map +0 -1
- package/dist/tests/commands/snapshot.test.d.ts +0 -2
- package/dist/tests/commands/snapshot.test.d.ts.map +0 -1
- package/dist/tests/commands/snapshot.test.js +0 -280
- package/dist/tests/commands/snapshot.test.js.map +0 -1
- package/dist/tests/commands/user.test.d.ts +0 -2
- package/dist/tests/commands/user.test.d.ts.map +0 -1
- package/dist/tests/commands/user.test.js +0 -117
- package/dist/tests/commands/user.test.js.map +0 -1
- package/dist/tests/commands/workspace.test.d.ts +0 -2
- package/dist/tests/commands/workspace.test.d.ts.map +0 -1
- package/dist/tests/commands/workspace.test.js +0 -453
- package/dist/tests/commands/workspace.test.js.map +0 -1
- package/dist/tests/credential-manager.test.d.ts +0 -2
- package/dist/tests/credential-manager.test.d.ts.map +0 -1
- package/dist/tests/credential-manager.test.js +0 -199
- package/dist/tests/credential-manager.test.js.map +0 -1
- package/dist/tests/slack-client.test.d.ts +0 -2
- package/dist/tests/slack-client.test.d.ts.map +0 -1
- package/dist/tests/slack-client.test.js +0 -741
- package/dist/tests/slack-client.test.js.map +0 -1
- package/dist/tests/types.test.d.ts +0 -2
- package/dist/tests/types.test.d.ts.map +0 -1
- package/dist/tests/types.test.js +0 -215
- package/dist/tests/types.test.js.map +0 -1
- package/dist/types/index.d.ts +0 -369
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js +0 -92
- package/dist/types/index.js.map +0 -1
- package/dist/utils/error-handler.d.ts +0 -2
- package/dist/utils/error-handler.d.ts.map +0 -1
- package/dist/utils/error-handler.js +0 -5
- package/dist/utils/error-handler.js.map +0 -1
- package/dist/utils/output.d.ts +0 -2
- package/dist/utils/output.d.ts.map +0 -1
- package/dist/utils/output.js +0 -4
- package/dist/utils/output.js.map +0 -1
- /package/dist/{cli.d.ts → src/platforms/teams/cli.d.ts} +0 -0
- /package/dist/{commands → src/platforms/teams/commands}/user.d.ts +0 -0
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { describe, test, expect, beforeAll, afterEach } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
runCLI, parseJSON, generateTestId, createTestMessage,
|
|
4
|
+
deleteTestMessage, waitForRateLimit, cleanupMessages
|
|
5
|
+
} from './helpers'
|
|
6
|
+
import {
|
|
7
|
+
DISCORD_TEST_CHANNEL_ID,
|
|
8
|
+
DISCORD_TEST_GUILD_ID,
|
|
9
|
+
validateDiscordEnvironment
|
|
10
|
+
} from './config'
|
|
11
|
+
|
|
12
|
+
// Track messages created during tests for cleanup
|
|
13
|
+
let testMessages: string[] = []
|
|
14
|
+
|
|
15
|
+
describe('Discord E2E Tests', () => {
|
|
16
|
+
beforeAll(async () => {
|
|
17
|
+
await validateDiscordEnvironment()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
if (testMessages.length > 0) {
|
|
22
|
+
await cleanupMessages('discord', DISCORD_TEST_CHANNEL_ID, testMessages)
|
|
23
|
+
testMessages = []
|
|
24
|
+
}
|
|
25
|
+
await waitForRateLimit()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('auth', () => {
|
|
29
|
+
test('auth status returns authenticated status', async () => {
|
|
30
|
+
const result = await runCLI('discord', ['auth', 'status'])
|
|
31
|
+
expect(result.exitCode).toBe(0)
|
|
32
|
+
|
|
33
|
+
const data = parseJSON<{ authenticated: boolean }>(result.stdout)
|
|
34
|
+
expect(data?.authenticated).toBe(true)
|
|
35
|
+
})
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
describe('guild', () => {
|
|
39
|
+
test('guild list returns array', async () => {
|
|
40
|
+
const result = await runCLI('discord', ['guild', 'list'])
|
|
41
|
+
expect(result.exitCode).toBe(0)
|
|
42
|
+
|
|
43
|
+
const data = parseJSON<Array<{ guild_id: string }>>(result.stdout)
|
|
44
|
+
expect(Array.isArray(data)).toBe(true)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test('guild current returns current guild', async () => {
|
|
48
|
+
const result = await runCLI('discord', ['guild', 'current'])
|
|
49
|
+
expect(result.exitCode).toBe(0)
|
|
50
|
+
|
|
51
|
+
const data = parseJSON<{ guild_id: string }>(result.stdout)
|
|
52
|
+
expect(data?.guild_id).toBe(DISCORD_TEST_GUILD_ID)
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
test('guild info returns guild details', async () => {
|
|
56
|
+
const result = await runCLI('discord', ['guild', 'info', DISCORD_TEST_GUILD_ID])
|
|
57
|
+
expect(result.exitCode).toBe(0)
|
|
58
|
+
|
|
59
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
60
|
+
expect(data?.id).toBeTruthy()
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
describe('message', () => {
|
|
65
|
+
test('message send creates message', async () => {
|
|
66
|
+
const testId = generateTestId()
|
|
67
|
+
const result = await runCLI('discord', ['message', 'send', DISCORD_TEST_CHANNEL_ID, `Test message ${testId}`])
|
|
68
|
+
expect(result.exitCode).toBe(0)
|
|
69
|
+
|
|
70
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
71
|
+
expect(data?.id).toBeTruthy()
|
|
72
|
+
|
|
73
|
+
if (data?.id) testMessages.push(data.id)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('message list returns messages array', async () => {
|
|
77
|
+
const result = await runCLI('discord', ['message', 'list', DISCORD_TEST_CHANNEL_ID, '--limit', '5'])
|
|
78
|
+
expect(result.exitCode).toBe(0)
|
|
79
|
+
|
|
80
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
81
|
+
expect(Array.isArray(data)).toBe(true)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
test.skip('message get retrieves specific message (requires bot token)', async () => {
|
|
85
|
+
const testId = generateTestId()
|
|
86
|
+
const { id } = await createTestMessage('discord', DISCORD_TEST_CHANNEL_ID, `Get test ${testId}`)
|
|
87
|
+
testMessages.push(id)
|
|
88
|
+
|
|
89
|
+
await waitForRateLimit()
|
|
90
|
+
|
|
91
|
+
const result = await runCLI('discord', ['message', 'get', DISCORD_TEST_CHANNEL_ID, id])
|
|
92
|
+
expect(result.exitCode).toBe(0)
|
|
93
|
+
|
|
94
|
+
const data = parseJSON<{ content: string }>(result.stdout)
|
|
95
|
+
expect(data?.content).toContain(testId)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
test('message delete removes message', async () => {
|
|
99
|
+
const testId = generateTestId()
|
|
100
|
+
const { id } = await createTestMessage('discord', DISCORD_TEST_CHANNEL_ID, `Delete me ${testId}`)
|
|
101
|
+
|
|
102
|
+
await waitForRateLimit()
|
|
103
|
+
|
|
104
|
+
const result = await runCLI('discord', ['message', 'delete', DISCORD_TEST_CHANNEL_ID, id, '--force'])
|
|
105
|
+
expect(result.exitCode).toBe(0)
|
|
106
|
+
})
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
describe('channel', () => {
|
|
110
|
+
test('channel list returns channels array', async () => {
|
|
111
|
+
const result = await runCLI('discord', ['channel', 'list'])
|
|
112
|
+
expect(result.exitCode).toBe(0)
|
|
113
|
+
|
|
114
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
115
|
+
expect(Array.isArray(data)).toBe(true)
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
test('channel info returns channel details', async () => {
|
|
119
|
+
const result = await runCLI('discord', ['channel', 'info', DISCORD_TEST_CHANNEL_ID])
|
|
120
|
+
expect(result.exitCode).toBe(0)
|
|
121
|
+
|
|
122
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
123
|
+
expect(data?.id).toBe(DISCORD_TEST_CHANNEL_ID)
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
test('channel history returns messages', async () => {
|
|
127
|
+
const result = await runCLI('discord', ['channel', 'history', DISCORD_TEST_CHANNEL_ID, '--limit', '5'])
|
|
128
|
+
expect(result.exitCode).toBe(0)
|
|
129
|
+
|
|
130
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
131
|
+
expect(Array.isArray(data)).toBe(true)
|
|
132
|
+
})
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
describe('user', () => {
|
|
136
|
+
test.skip('user list returns users array (requires bot token)', async () => {
|
|
137
|
+
const result = await runCLI('discord', ['user', 'list'])
|
|
138
|
+
expect(result.exitCode).toBe(0)
|
|
139
|
+
|
|
140
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
141
|
+
expect(Array.isArray(data)).toBe(true)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test('user me returns current user', async () => {
|
|
145
|
+
const result = await runCLI('discord', ['user', 'me'])
|
|
146
|
+
expect(result.exitCode).toBe(0)
|
|
147
|
+
|
|
148
|
+
const data = parseJSON<{ id: string; username: string }>(result.stdout)
|
|
149
|
+
expect(data?.id).toBeTruthy()
|
|
150
|
+
expect(data?.username).toBeTruthy()
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
test('user info returns user details', async () => {
|
|
154
|
+
// First get current user ID
|
|
155
|
+
const meResult = await runCLI('discord', ['user', 'me'])
|
|
156
|
+
expect(meResult.exitCode).toBe(0)
|
|
157
|
+
|
|
158
|
+
const me = parseJSON<{ id: string }>(meResult.stdout)
|
|
159
|
+
expect(me?.id).toBeTruthy()
|
|
160
|
+
|
|
161
|
+
await waitForRateLimit()
|
|
162
|
+
|
|
163
|
+
const result = await runCLI('discord', ['user', 'info', me!.id])
|
|
164
|
+
expect(result.exitCode).toBe(0)
|
|
165
|
+
|
|
166
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
167
|
+
expect(data?.id).toBe(me?.id)
|
|
168
|
+
})
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
describe('reaction', () => {
|
|
172
|
+
test.skip('reaction add/list/remove lifecycle (requires bot token)', async () => {
|
|
173
|
+
const testId = generateTestId()
|
|
174
|
+
const { id } = await createTestMessage('discord', DISCORD_TEST_CHANNEL_ID, `Reaction test ${testId}`)
|
|
175
|
+
testMessages.push(id)
|
|
176
|
+
|
|
177
|
+
await waitForRateLimit()
|
|
178
|
+
|
|
179
|
+
// Add reaction (using emoji name without colons)
|
|
180
|
+
const addResult = await runCLI('discord', ['reaction', 'add', DISCORD_TEST_CHANNEL_ID, id, '👍'])
|
|
181
|
+
expect(addResult.exitCode).toBe(0)
|
|
182
|
+
|
|
183
|
+
await waitForRateLimit()
|
|
184
|
+
|
|
185
|
+
// List reactions
|
|
186
|
+
const listResult = await runCLI('discord', ['reaction', 'list', DISCORD_TEST_CHANNEL_ID, id])
|
|
187
|
+
expect(listResult.exitCode).toBe(0)
|
|
188
|
+
|
|
189
|
+
await waitForRateLimit()
|
|
190
|
+
|
|
191
|
+
// Remove reaction
|
|
192
|
+
const removeResult = await runCLI('discord', ['reaction', 'remove', DISCORD_TEST_CHANNEL_ID, id, '👍'])
|
|
193
|
+
expect(removeResult.exitCode).toBe(0)
|
|
194
|
+
}, 15000) // Longer timeout for multiple operations
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
describe('file', () => {
|
|
198
|
+
test('file list returns files array', async () => {
|
|
199
|
+
const result = await runCLI('discord', ['file', 'list', DISCORD_TEST_CHANNEL_ID])
|
|
200
|
+
expect(result.exitCode).toBe(0)
|
|
201
|
+
|
|
202
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
203
|
+
expect(Array.isArray(data)).toBe(true)
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
test('file upload uploads file', async () => {
|
|
207
|
+
const testId = generateTestId()
|
|
208
|
+
const testFilePath = `/tmp/discord-e2e-${testId}.txt`
|
|
209
|
+
await Bun.write(testFilePath, `Discord E2E test file ${testId}`)
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
const result = await runCLI('discord', ['file', 'upload', DISCORD_TEST_CHANNEL_ID, testFilePath])
|
|
213
|
+
expect(result.exitCode).toBe(0)
|
|
214
|
+
|
|
215
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
216
|
+
expect(data?.id).toBeTruthy()
|
|
217
|
+
|
|
218
|
+
// Track message for cleanup (file uploads create messages)
|
|
219
|
+
if (data?.id) testMessages.push(data.id)
|
|
220
|
+
} finally {
|
|
221
|
+
await Bun.$`rm -f ${testFilePath}`.quiet()
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
describe('snapshot', () => {
|
|
227
|
+
test.skip('snapshot returns full guild data (requires bot token)', async () => {
|
|
228
|
+
const result = await runCLI('discord', ['snapshot', '--limit', '2'])
|
|
229
|
+
expect(result.exitCode).toBe(0)
|
|
230
|
+
|
|
231
|
+
const data = parseJSON<{ channels: unknown[]; users: unknown[] }>(result.stdout)
|
|
232
|
+
expect(data?.channels).toBeDefined()
|
|
233
|
+
expect(data?.users).toBeDefined()
|
|
234
|
+
})
|
|
235
|
+
|
|
236
|
+
test('snapshot --channels-only returns only channels', async () => {
|
|
237
|
+
const result = await runCLI('discord', ['snapshot', '--channels-only'])
|
|
238
|
+
expect(result.exitCode).toBe(0)
|
|
239
|
+
|
|
240
|
+
const data = parseJSON<{ channels: unknown[] }>(result.stdout)
|
|
241
|
+
expect(data?.channels).toBeDefined()
|
|
242
|
+
})
|
|
243
|
+
|
|
244
|
+
test.skip('snapshot --users-only returns only users (requires bot token)', async () => {
|
|
245
|
+
const result = await runCLI('discord', ['snapshot', '--users-only'])
|
|
246
|
+
expect(result.exitCode).toBe(0)
|
|
247
|
+
|
|
248
|
+
const data = parseJSON<{ users: unknown[] }>(result.stdout)
|
|
249
|
+
expect(data?.users).toBeDefined()
|
|
250
|
+
})
|
|
251
|
+
})
|
|
252
|
+
})
|
package/e2e/helpers.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { $ } from 'bun'
|
|
2
|
+
|
|
3
|
+
export interface CLIResult {
|
|
4
|
+
exitCode: number
|
|
5
|
+
stdout: string
|
|
6
|
+
stderr: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function runCLI(platform: string, args: string[]): Promise<CLIResult> {
|
|
10
|
+
const command = platform === 'slack' ? 'agent-slack' : 'agent-discord'
|
|
11
|
+
|
|
12
|
+
try {
|
|
13
|
+
const result = await $`${command} ${args}`.quiet()
|
|
14
|
+
return {
|
|
15
|
+
exitCode: result.exitCode,
|
|
16
|
+
stdout: result.stdout.toString(),
|
|
17
|
+
stderr: result.stderr.toString(),
|
|
18
|
+
}
|
|
19
|
+
} catch (error: any) {
|
|
20
|
+
return {
|
|
21
|
+
exitCode: error.exitCode || 1,
|
|
22
|
+
stdout: error.stdout?.toString() || '',
|
|
23
|
+
stderr: error.stderr?.toString() || '',
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function parseJSON<T>(output: string): T | null {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(output) as T
|
|
31
|
+
} catch {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function generateTestId(): string {
|
|
37
|
+
return `e2e-${Date.now()}-${Math.random().toString(36).substring(7)}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function createTestMessage(
|
|
41
|
+
platform: string,
|
|
42
|
+
channel: string,
|
|
43
|
+
text: string
|
|
44
|
+
): Promise<{ id: string }> {
|
|
45
|
+
const result = await runCLI(platform, ['message', 'send', channel, text])
|
|
46
|
+
if (result.exitCode !== 0) {
|
|
47
|
+
throw new Error(`Failed to create test message: ${result.stderr}`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const data = parseJSON<{ ts?: string; id?: string }>(result.stdout)
|
|
51
|
+
const messageId = data?.ts || data?.id
|
|
52
|
+
if (!messageId) {
|
|
53
|
+
throw new Error('No message ID returned')
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return { id: messageId }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function deleteTestMessage(
|
|
60
|
+
platform: string,
|
|
61
|
+
channel: string,
|
|
62
|
+
messageId: string
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
// For Slack, check for thread replies and delete them first
|
|
65
|
+
if (platform === 'slack') {
|
|
66
|
+
try {
|
|
67
|
+
const repliesResult = await runCLI(platform, ['message', 'replies', channel, messageId])
|
|
68
|
+
if (repliesResult.exitCode === 0) {
|
|
69
|
+
const replies = parseJSON<Array<{ ts?: string; id?: string }>>(repliesResult.stdout)
|
|
70
|
+
if (replies && replies.length > 0) {
|
|
71
|
+
// Delete replies in reverse order (newest first), skip parent
|
|
72
|
+
const threadReplies = replies.filter(r => (r.ts || r.id) !== messageId)
|
|
73
|
+
for (const reply of threadReplies.reverse()) {
|
|
74
|
+
const replyId = reply.ts || reply.id
|
|
75
|
+
if (replyId) {
|
|
76
|
+
await runCLI(platform, ['message', 'delete', channel, replyId, '--force'])
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
} catch {
|
|
82
|
+
// Continue with parent deletion even if replies fail
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Delete the parent message
|
|
87
|
+
await runCLI(platform, ['message', 'delete', channel, messageId, '--force'])
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export async function waitForRateLimit(ms: number = 1000): Promise<void> {
|
|
91
|
+
await new Promise(resolve => setTimeout(resolve, ms))
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export async function cleanupMessages(
|
|
95
|
+
platform: string,
|
|
96
|
+
channel: string,
|
|
97
|
+
messageIds: string[]
|
|
98
|
+
): Promise<void> {
|
|
99
|
+
for (const id of messageIds) {
|
|
100
|
+
try {
|
|
101
|
+
await deleteTestMessage(platform, channel, id)
|
|
102
|
+
await waitForRateLimit(500)
|
|
103
|
+
} catch (error) {
|
|
104
|
+
console.warn(`Failed to cleanup message ${id}:`, error)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
import { describe, test, expect, beforeAll, afterEach } from 'bun:test'
|
|
2
|
+
import {
|
|
3
|
+
runCLI, parseJSON, generateTestId, createTestMessage,
|
|
4
|
+
deleteTestMessage, waitForRateLimit, cleanupMessages
|
|
5
|
+
} from './helpers'
|
|
6
|
+
import {
|
|
7
|
+
SLACK_TEST_CHANNEL, SLACK_TEST_CHANNEL_ID,
|
|
8
|
+
validateSlackEnvironment
|
|
9
|
+
} from './config'
|
|
10
|
+
|
|
11
|
+
// Track messages created during tests for cleanup
|
|
12
|
+
let testMessages: string[] = []
|
|
13
|
+
|
|
14
|
+
describe('Slack E2E Tests', () => {
|
|
15
|
+
beforeAll(async () => {
|
|
16
|
+
// Validate we're in the correct workspace
|
|
17
|
+
await validateSlackEnvironment()
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterEach(async () => {
|
|
21
|
+
if (testMessages.length > 0) {
|
|
22
|
+
await cleanupMessages('slack', SLACK_TEST_CHANNEL_ID, testMessages)
|
|
23
|
+
testMessages = []
|
|
24
|
+
}
|
|
25
|
+
await waitForRateLimit()
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
describe('auth', () => {
|
|
29
|
+
test('auth status returns authenticated workspace info', async () => {
|
|
30
|
+
const result = await runCLI('slack', ['auth', 'status'])
|
|
31
|
+
expect(result.exitCode).toBe(0)
|
|
32
|
+
|
|
33
|
+
const data = parseJSON<{ workspace_id: string; workspace_name: string }>(result.stdout)
|
|
34
|
+
expect(data).not.toBeNull()
|
|
35
|
+
expect(data?.workspace_id).toBeTruthy()
|
|
36
|
+
expect(data?.workspace_name).toBeTruthy()
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
describe('workspace', () => {
|
|
41
|
+
test('workspace list returns array', async () => {
|
|
42
|
+
const result = await runCLI('slack', ['workspace', 'list'])
|
|
43
|
+
expect(result.exitCode).toBe(0)
|
|
44
|
+
|
|
45
|
+
const data = parseJSON<Array<{ id: string; name: string }>>(result.stdout)
|
|
46
|
+
expect(Array.isArray(data)).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('workspace current returns current workspace', async () => {
|
|
50
|
+
const result = await runCLI('slack', ['workspace', 'current'])
|
|
51
|
+
expect(result.exitCode).toBe(0)
|
|
52
|
+
|
|
53
|
+
const data = parseJSON<{ workspace_id: string }>(result.stdout)
|
|
54
|
+
expect(data?.workspace_id).toBeTruthy()
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('message', () => {
|
|
59
|
+
test('message send creates message and returns ts', async () => {
|
|
60
|
+
const testId = generateTestId()
|
|
61
|
+
const result = await runCLI('slack', ['message', 'send', SLACK_TEST_CHANNEL_ID, `Test message ${testId}`])
|
|
62
|
+
expect(result.exitCode).toBe(0)
|
|
63
|
+
|
|
64
|
+
const data = parseJSON<{ ts: string }>(result.stdout)
|
|
65
|
+
expect(data?.ts).toBeTruthy()
|
|
66
|
+
|
|
67
|
+
if (data?.ts) testMessages.push(data.ts)
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
test('message list returns messages array', async () => {
|
|
71
|
+
const result = await runCLI('slack', ['message', 'list', SLACK_TEST_CHANNEL_ID, '--limit', '5'])
|
|
72
|
+
expect(result.exitCode).toBe(0)
|
|
73
|
+
|
|
74
|
+
const data = parseJSON<Array<{ ts: string }>>(result.stdout)
|
|
75
|
+
expect(Array.isArray(data)).toBe(true)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
test('message get retrieves specific message', async () => {
|
|
79
|
+
const testId = generateTestId()
|
|
80
|
+
const { id: ts } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Get test ${testId}`)
|
|
81
|
+
testMessages.push(ts)
|
|
82
|
+
|
|
83
|
+
await waitForRateLimit()
|
|
84
|
+
|
|
85
|
+
const result = await runCLI('slack', ['message', 'get', SLACK_TEST_CHANNEL_ID, ts])
|
|
86
|
+
expect(result.exitCode).toBe(0)
|
|
87
|
+
|
|
88
|
+
const data = parseJSON<{ text: string }>(result.stdout)
|
|
89
|
+
expect(data?.text).toContain(testId)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test('message update modifies message', async () => {
|
|
93
|
+
const testId = generateTestId()
|
|
94
|
+
const { id: ts } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Original ${testId}`)
|
|
95
|
+
testMessages.push(ts)
|
|
96
|
+
|
|
97
|
+
await waitForRateLimit()
|
|
98
|
+
|
|
99
|
+
const result = await runCLI('slack', ['message', 'update', SLACK_TEST_CHANNEL_ID, ts, `Updated ${testId}`])
|
|
100
|
+
expect(result.exitCode).toBe(0)
|
|
101
|
+
|
|
102
|
+
await waitForRateLimit()
|
|
103
|
+
const getResult = await runCLI('slack', ['message', 'get', SLACK_TEST_CHANNEL_ID, ts])
|
|
104
|
+
const data = parseJSON<{ text: string }>(getResult.stdout)
|
|
105
|
+
expect(data?.text).toContain('Updated')
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
test('message search finds messages', async () => {
|
|
109
|
+
const result = await runCLI('slack', ['message', 'search', 'test', '--limit', '5'])
|
|
110
|
+
expect(result.exitCode).toBe(0)
|
|
111
|
+
|
|
112
|
+
const data = parseJSON<Array<{ ts: string }>>(result.stdout)
|
|
113
|
+
expect(Array.isArray(data)).toBe(true)
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
test('message send with thread creates reply', async () => {
|
|
117
|
+
const testId = generateTestId()
|
|
118
|
+
const { id: parentTs } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Parent ${testId}`)
|
|
119
|
+
testMessages.push(parentTs)
|
|
120
|
+
|
|
121
|
+
await waitForRateLimit()
|
|
122
|
+
|
|
123
|
+
const result = await runCLI('slack', ['message', 'send', SLACK_TEST_CHANNEL_ID, `Reply ${testId}`, '--thread', parentTs])
|
|
124
|
+
expect(result.exitCode).toBe(0)
|
|
125
|
+
|
|
126
|
+
const data = parseJSON<{ ts: string; thread_ts: string }>(result.stdout)
|
|
127
|
+
expect(data?.thread_ts).toBe(parentTs)
|
|
128
|
+
|
|
129
|
+
if (data?.ts) testMessages.push(data.ts)
|
|
130
|
+
}, 30000)
|
|
131
|
+
|
|
132
|
+
test('message replies gets thread replies', async () => {
|
|
133
|
+
const testId = generateTestId()
|
|
134
|
+
const { id: parentTs } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Thread parent ${testId}`)
|
|
135
|
+
testMessages.push(parentTs)
|
|
136
|
+
|
|
137
|
+
await waitForRateLimit()
|
|
138
|
+
|
|
139
|
+
await runCLI('slack', ['message', 'send', SLACK_TEST_CHANNEL_ID, `Thread reply ${testId}`, '--thread', parentTs])
|
|
140
|
+
|
|
141
|
+
await waitForRateLimit()
|
|
142
|
+
|
|
143
|
+
const result = await runCLI('slack', ['message', 'replies', SLACK_TEST_CHANNEL_ID, parentTs])
|
|
144
|
+
expect(result.exitCode).toBe(0)
|
|
145
|
+
|
|
146
|
+
const data = parseJSON<Array<{ ts: string }>>(result.stdout)
|
|
147
|
+
expect(Array.isArray(data)).toBe(true)
|
|
148
|
+
expect(data?.length).toBeGreaterThanOrEqual(1)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
test('message delete removes message', async () => {
|
|
152
|
+
const testId = generateTestId()
|
|
153
|
+
const { id: ts } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Delete me ${testId}`)
|
|
154
|
+
|
|
155
|
+
await waitForRateLimit()
|
|
156
|
+
|
|
157
|
+
const result = await runCLI('slack', ['message', 'delete', SLACK_TEST_CHANNEL_ID, ts, '--force'])
|
|
158
|
+
expect(result.exitCode).toBe(0)
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
describe('channel', () => {
|
|
163
|
+
test('channel list returns channels array', async () => {
|
|
164
|
+
const result = await runCLI('slack', ['channel', 'list'])
|
|
165
|
+
expect(result.exitCode).toBe(0)
|
|
166
|
+
|
|
167
|
+
const data = parseJSON<Array<{ id: string; name: string }>>(result.stdout)
|
|
168
|
+
expect(Array.isArray(data)).toBe(true)
|
|
169
|
+
expect(data?.length).toBeGreaterThan(0)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
test('channel list --type public filters channels', async () => {
|
|
173
|
+
const result = await runCLI('slack', ['channel', 'list', '--type', 'public'])
|
|
174
|
+
expect(result.exitCode).toBe(0)
|
|
175
|
+
|
|
176
|
+
const data = parseJSON<Array<{ is_private: boolean }>>(result.stdout)
|
|
177
|
+
expect(Array.isArray(data)).toBe(true)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
test('channel info returns channel details', async () => {
|
|
181
|
+
const result = await runCLI('slack', ['channel', 'info', SLACK_TEST_CHANNEL_ID])
|
|
182
|
+
expect(result.exitCode).toBe(0)
|
|
183
|
+
|
|
184
|
+
const data = parseJSON<{ id: string; name: string }>(result.stdout)
|
|
185
|
+
expect(data?.id).toBeTruthy()
|
|
186
|
+
expect(data?.name).toBe('e2e-test')
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
|
|
190
|
+
describe('user', () => {
|
|
191
|
+
test('user list returns users array', async () => {
|
|
192
|
+
const result = await runCLI('slack', ['user', 'list'])
|
|
193
|
+
expect(result.exitCode).toBe(0)
|
|
194
|
+
|
|
195
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
196
|
+
expect(Array.isArray(data)).toBe(true)
|
|
197
|
+
})
|
|
198
|
+
|
|
199
|
+
test('user me returns current user', async () => {
|
|
200
|
+
const result = await runCLI('slack', ['user', 'me'])
|
|
201
|
+
expect(result.exitCode).toBe(0)
|
|
202
|
+
|
|
203
|
+
const data = parseJSON<{ id: string; name: string }>(result.stdout)
|
|
204
|
+
expect(data?.id).toBeTruthy()
|
|
205
|
+
expect(data?.name).toBeTruthy()
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
test('user info returns user details', async () => {
|
|
209
|
+
// First get current user ID
|
|
210
|
+
const meResult = await runCLI('slack', ['user', 'me'])
|
|
211
|
+
const me = parseJSON<{ id: string }>(meResult.stdout)
|
|
212
|
+
expect(me?.id).toBeTruthy()
|
|
213
|
+
|
|
214
|
+
await waitForRateLimit()
|
|
215
|
+
|
|
216
|
+
// Get user info
|
|
217
|
+
const result = await runCLI('slack', ['user', 'info', me!.id])
|
|
218
|
+
expect(result.exitCode).toBe(0)
|
|
219
|
+
|
|
220
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
221
|
+
expect(data?.id).toBe(me?.id)
|
|
222
|
+
})
|
|
223
|
+
})
|
|
224
|
+
|
|
225
|
+
describe('reaction', () => {
|
|
226
|
+
test('reaction add/list/remove lifecycle', async () => {
|
|
227
|
+
const testId = generateTestId()
|
|
228
|
+
const { id: ts } = await createTestMessage('slack', SLACK_TEST_CHANNEL_ID, `Reaction test ${testId}`)
|
|
229
|
+
testMessages.push(ts)
|
|
230
|
+
|
|
231
|
+
await waitForRateLimit(2000)
|
|
232
|
+
|
|
233
|
+
const addResult = await runCLI('slack', ['reaction', 'add', SLACK_TEST_CHANNEL_ID, ts, 'thumbsup'])
|
|
234
|
+
expect(addResult.exitCode).toBe(0)
|
|
235
|
+
|
|
236
|
+
await waitForRateLimit(2000)
|
|
237
|
+
|
|
238
|
+
const listResult = await runCLI('slack', ['reaction', 'list', SLACK_TEST_CHANNEL_ID, ts])
|
|
239
|
+
expect(listResult.exitCode).toBe(0)
|
|
240
|
+
|
|
241
|
+
const data = parseJSON<{ reactions: Array<{ name: string }> }>(listResult.stdout)
|
|
242
|
+
expect(Array.isArray(data?.reactions)).toBe(true)
|
|
243
|
+
|
|
244
|
+
await waitForRateLimit(2000)
|
|
245
|
+
|
|
246
|
+
const removeResult = await runCLI('slack', ['reaction', 'remove', SLACK_TEST_CHANNEL_ID, ts, 'thumbsup'])
|
|
247
|
+
expect(removeResult.exitCode).toBe(0)
|
|
248
|
+
}, 15000)
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
describe('file', () => {
|
|
252
|
+
test('file list returns files array', async () => {
|
|
253
|
+
const result = await runCLI('slack', ['file', 'list'])
|
|
254
|
+
expect(result.exitCode).toBe(0)
|
|
255
|
+
|
|
256
|
+
const data = parseJSON<Array<{ id: string }>>(result.stdout)
|
|
257
|
+
expect(Array.isArray(data)).toBe(true)
|
|
258
|
+
})
|
|
259
|
+
|
|
260
|
+
test.skip('file upload uploads file', async () => {
|
|
261
|
+
const testId = generateTestId()
|
|
262
|
+
const testFilePath = `/tmp/slack-e2e-${testId}.txt`
|
|
263
|
+
await Bun.write(testFilePath, `E2E test file content ${testId}`)
|
|
264
|
+
|
|
265
|
+
try {
|
|
266
|
+
const result = await runCLI('slack', ['file', 'upload', SLACK_TEST_CHANNEL_ID, testFilePath])
|
|
267
|
+
expect(result.exitCode).toBe(0)
|
|
268
|
+
|
|
269
|
+
const data = parseJSON<{ id: string }>(result.stdout)
|
|
270
|
+
expect(data?.id).toBeTruthy()
|
|
271
|
+
|
|
272
|
+
if (data?.id) {
|
|
273
|
+
await waitForRateLimit()
|
|
274
|
+
const infoResult = await runCLI('slack', ['file', 'info', data.id])
|
|
275
|
+
expect(infoResult.exitCode).toBe(0)
|
|
276
|
+
}
|
|
277
|
+
} finally {
|
|
278
|
+
await Bun.$`rm -f ${testFilePath}`.quiet()
|
|
279
|
+
}
|
|
280
|
+
})
|
|
281
|
+
})
|
|
282
|
+
|
|
283
|
+
describe('snapshot', () => {
|
|
284
|
+
test('snapshot returns full workspace data', async () => {
|
|
285
|
+
const result = await runCLI('slack', ['snapshot', '--limit', '2'])
|
|
286
|
+
expect(result.exitCode).toBe(0)
|
|
287
|
+
|
|
288
|
+
const data = parseJSON<{ channels: unknown[]; users: unknown[] }>(result.stdout)
|
|
289
|
+
expect(data?.channels).toBeDefined()
|
|
290
|
+
expect(data?.users).toBeDefined()
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
test('snapshot --channels-only returns only channels', async () => {
|
|
294
|
+
const result = await runCLI('slack', ['snapshot', '--channels-only'])
|
|
295
|
+
expect(result.exitCode).toBe(0)
|
|
296
|
+
|
|
297
|
+
const data = parseJSON<{ channels: unknown[] }>(result.stdout)
|
|
298
|
+
expect(data?.channels).toBeDefined()
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
test('snapshot --users-only returns only users', async () => {
|
|
302
|
+
const result = await runCLI('slack', ['snapshot', '--users-only'])
|
|
303
|
+
expect(result.exitCode).toBe(0)
|
|
304
|
+
|
|
305
|
+
const data = parseJSON<{ users: unknown[] }>(result.stdout)
|
|
306
|
+
expect(data?.users).toBeDefined()
|
|
307
|
+
})
|
|
308
|
+
})
|
|
309
|
+
})
|