@urugus/slack-cli 0.2.11 → 0.2.13

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 (97) hide show
  1. package/README.md +4 -0
  2. package/dist/commands/history-display.d.ts +5 -1
  3. package/dist/commands/history-display.d.ts.map +1 -1
  4. package/dist/commands/history-display.js +3 -3
  5. package/dist/commands/history-display.js.map +1 -1
  6. package/dist/commands/history.d.ts.map +1 -1
  7. package/dist/commands/history.js +28 -11
  8. package/dist/commands/history.js.map +1 -1
  9. package/dist/types/commands.d.ts +1 -0
  10. package/dist/types/commands.d.ts.map +1 -1
  11. package/dist/utils/slack-api-client.d.ts +1 -0
  12. package/dist/utils/slack-api-client.d.ts.map +1 -1
  13. package/dist/utils/slack-api-client.js +3 -0
  14. package/dist/utils/slack-api-client.js.map +1 -1
  15. package/dist/utils/slack-operations/message-operations.d.ts +1 -0
  16. package/dist/utils/slack-operations/message-operations.d.ts.map +1 -1
  17. package/dist/utils/slack-operations/message-operations.js +21 -0
  18. package/dist/utils/slack-operations/message-operations.js.map +1 -1
  19. package/package.json +5 -2
  20. package/.claude/settings.local.json +0 -75
  21. package/.github/dependabot.yml +0 -18
  22. package/.github/workflows/ci.yml +0 -70
  23. package/.github/workflows/pr-validation.yml +0 -41
  24. package/.prettierignore +0 -11
  25. package/.prettierrc +0 -10
  26. package/CHANGELOG.md +0 -61
  27. package/CLAUDE.md +0 -16
  28. package/eslint.config.js +0 -38
  29. package/src/commands/channels.ts +0 -50
  30. package/src/commands/config-subcommands.ts +0 -63
  31. package/src/commands/config.ts +0 -50
  32. package/src/commands/history-display.ts +0 -19
  33. package/src/commands/history-validators.ts +0 -46
  34. package/src/commands/history.ts +0 -61
  35. package/src/commands/scheduled.ts +0 -71
  36. package/src/commands/send.ts +0 -69
  37. package/src/commands/unread.ts +0 -122
  38. package/src/index.ts +0 -27
  39. package/src/types/commands.ts +0 -58
  40. package/src/types/config.ts +0 -20
  41. package/src/utils/channel-formatter.ts +0 -45
  42. package/src/utils/channel-resolver.ts +0 -82
  43. package/src/utils/client-factory.ts +0 -10
  44. package/src/utils/command-wrapper.ts +0 -27
  45. package/src/utils/config/config-file-manager.ts +0 -56
  46. package/src/utils/config/profile-manager.ts +0 -79
  47. package/src/utils/config/token-crypto-service.ts +0 -80
  48. package/src/utils/config-helper.ts +0 -21
  49. package/src/utils/constants.ts +0 -78
  50. package/src/utils/date-utils.ts +0 -8
  51. package/src/utils/error-utils.ts +0 -6
  52. package/src/utils/errors.ts +0 -33
  53. package/src/utils/format-utils.ts +0 -9
  54. package/src/utils/formatters/base-formatter.ts +0 -34
  55. package/src/utils/formatters/channel-formatters.ts +0 -71
  56. package/src/utils/formatters/channels-list-formatters.ts +0 -55
  57. package/src/utils/formatters/history-formatters.ts +0 -123
  58. package/src/utils/formatters/message-formatters.ts +0 -85
  59. package/src/utils/mention-utils.ts +0 -47
  60. package/src/utils/option-parsers.ts +0 -100
  61. package/src/utils/profile-config.ts +0 -161
  62. package/src/utils/schedule-utils.ts +0 -41
  63. package/src/utils/slack-api-client.ts +0 -135
  64. package/src/utils/slack-operations/base-client.ts +0 -30
  65. package/src/utils/slack-operations/channel-operations.ts +0 -161
  66. package/src/utils/slack-operations/index.ts +0 -3
  67. package/src/utils/slack-operations/message-operations.ts +0 -176
  68. package/src/utils/slack-patterns.ts +0 -9
  69. package/src/utils/token-utils.ts +0 -17
  70. package/src/utils/validators.ts +0 -263
  71. package/tests/commands/channels.test.ts +0 -250
  72. package/tests/commands/config.test.ts +0 -158
  73. package/tests/commands/history.test.ts +0 -403
  74. package/tests/commands/scheduled.test.ts +0 -131
  75. package/tests/commands/send.test.ts +0 -414
  76. package/tests/commands/unread.test.ts +0 -492
  77. package/tests/index.test.ts +0 -40
  78. package/tests/test-utils.ts +0 -28
  79. package/tests/utils/channel-resolver.test.ts +0 -161
  80. package/tests/utils/config/config-file-manager.test.ts +0 -118
  81. package/tests/utils/config/profile-manager.test.ts +0 -266
  82. package/tests/utils/config/token-crypto-service.test.ts +0 -98
  83. package/tests/utils/config.test.ts +0 -400
  84. package/tests/utils/date-utils.test.ts +0 -30
  85. package/tests/utils/error-utils.test.ts +0 -34
  86. package/tests/utils/format-utils.test.ts +0 -61
  87. package/tests/utils/mention-utils.test.ts +0 -100
  88. package/tests/utils/option-parsers.test.ts +0 -173
  89. package/tests/utils/profile-config.test.ts +0 -282
  90. package/tests/utils/schedule-utils.test.ts +0 -63
  91. package/tests/utils/slack-api-client.test.ts +0 -313
  92. package/tests/utils/slack-operations/channel-operations.test.ts +0 -248
  93. package/tests/utils/slack-operations/message-operations.test.ts +0 -163
  94. package/tests/utils/token-utils.test.ts +0 -33
  95. package/tests/utils/validators.test.ts +0 -307
  96. package/tsconfig.json +0 -22
  97. package/vitest.config.ts +0 -27
@@ -1,400 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
- import * as fs from 'fs/promises';
3
- import * as path from 'path';
4
- import * as os from 'os';
5
- import { ProfileConfigManager } from '../../src/utils/profile-config';
6
- import type { Config, ConfigStore } from '../../src/types/config';
7
-
8
- vi.mock('fs/promises');
9
- vi.mock('os');
10
-
11
- describe('ProfileConfigManager', () => {
12
- let configManager: ProfileConfigManager;
13
- const mockHomeDir = '/mock/home';
14
- const mockConfigPath = path.join(mockHomeDir, '.slack-cli', 'config.json');
15
-
16
- beforeEach(() => {
17
- vi.clearAllMocks();
18
- vi.mocked(os.homedir).mockReturnValue(mockHomeDir);
19
- configManager = new ProfileConfigManager();
20
- });
21
-
22
- afterEach(() => {
23
- vi.restoreAllMocks();
24
- });
25
-
26
- describe('setToken', () => {
27
- it('should save token to default profile when no profile specified and no default set', async () => {
28
- vi.mocked(fs.mkdir).mockResolvedValue(undefined);
29
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
30
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
31
- vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' });
32
-
33
- await configManager.setToken('test-token-123');
34
-
35
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
36
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
37
-
38
- expect(writtenData.profiles.default).toBeDefined();
39
- expect(writtenData.profiles.default.token).toBe('test-token-123');
40
- expect(writtenData.defaultProfile).toBe('default');
41
- });
42
-
43
- it('should save token to current default profile when no profile specified', async () => {
44
- const existingStore: ConfigStore = {
45
- profiles: {
46
- personal: {
47
- token: 'personal-token',
48
- updatedAt: '2025-01-01T00:00:00.000Z'
49
- }
50
- },
51
- defaultProfile: 'personal'
52
- };
53
-
54
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(existingStore));
55
- vi.mocked(fs.mkdir).mockResolvedValue(undefined);
56
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
57
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
58
-
59
- await configManager.setToken('updated-token-123');
60
-
61
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
62
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
63
-
64
- expect(writtenData.profiles.personal.token).toBe('updated-token-123');
65
- expect(writtenData.defaultProfile).toBe('personal');
66
- });
67
-
68
- it('should save token to specified profile', async () => {
69
- vi.mocked(fs.mkdir).mockResolvedValue(undefined);
70
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
71
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
72
- vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' });
73
-
74
- await configManager.setToken('work-token-123', 'work');
75
-
76
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
77
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
78
-
79
- expect(writtenData.profiles.work).toBeDefined();
80
- expect(writtenData.profiles.work.token).toBe('work-token-123');
81
- });
82
-
83
- it('should preserve existing profiles when adding new one', async () => {
84
- const existingStore: ConfigStore = {
85
- profiles: {
86
- personal: {
87
- token: 'personal-token',
88
- updatedAt: '2025-01-01T00:00:00.000Z'
89
- }
90
- },
91
- defaultProfile: 'personal'
92
- };
93
-
94
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(existingStore));
95
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
96
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
97
-
98
- await configManager.setToken('work-token-123', 'work');
99
-
100
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
101
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
102
-
103
- expect(writtenData.profiles.personal).toBeDefined();
104
- expect(writtenData.profiles.work).toBeDefined();
105
- expect(writtenData.profiles.work.token).toBe('work-token-123');
106
- expect(writtenData.defaultProfile).toBe('personal'); // default unchanged
107
- });
108
- });
109
-
110
- describe('getConfig', () => {
111
- it('should return config from default profile', async () => {
112
- const mockStore: ConfigStore = {
113
- profiles: {
114
- default: {
115
- token: 'default-token',
116
- updatedAt: '2025-06-21T10:00:00.000Z'
117
- },
118
- work: {
119
- token: 'work-token',
120
- updatedAt: '2025-06-21T11:00:00.000Z'
121
- }
122
- },
123
- defaultProfile: 'default'
124
- };
125
-
126
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
127
-
128
- const config = await configManager.getConfig();
129
-
130
- expect(config).toEqual(mockStore.profiles.default);
131
- });
132
-
133
- it('should return config from specified profile', async () => {
134
- const mockStore: ConfigStore = {
135
- profiles: {
136
- default: {
137
- token: 'default-token',
138
- updatedAt: '2025-06-21T10:00:00.000Z'
139
- },
140
- work: {
141
- token: 'work-token',
142
- updatedAt: '2025-06-21T11:00:00.000Z'
143
- }
144
- },
145
- defaultProfile: 'default'
146
- };
147
-
148
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
149
-
150
- const config = await configManager.getConfig('work');
151
-
152
- expect(config).toEqual(mockStore.profiles.work);
153
- });
154
-
155
- it('should return null when profile does not exist', async () => {
156
- const mockStore: ConfigStore = {
157
- profiles: {
158
- default: {
159
- token: 'default-token',
160
- updatedAt: '2025-06-21T10:00:00.000Z'
161
- }
162
- },
163
- defaultProfile: 'default'
164
- };
165
-
166
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
167
-
168
- const config = await configManager.getConfig('nonexistent');
169
-
170
- expect(config).toBeNull();
171
- });
172
- });
173
-
174
- describe('listProfiles', () => {
175
- it('should return all profiles with current profile marked', async () => {
176
- const mockStore: ConfigStore = {
177
- profiles: {
178
- default: {
179
- token: 'default-token',
180
- updatedAt: '2025-06-21T10:00:00.000Z'
181
- },
182
- work: {
183
- token: 'work-token',
184
- updatedAt: '2025-06-21T11:00:00.000Z'
185
- },
186
- personal: {
187
- token: 'personal-token',
188
- updatedAt: '2025-06-21T12:00:00.000Z'
189
- }
190
- },
191
- defaultProfile: 'work'
192
- };
193
-
194
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
195
-
196
- const profiles = await configManager.listProfiles();
197
-
198
- expect(profiles).toHaveLength(3);
199
- expect(profiles.find(p => p.name === 'work')?.isDefault).toBe(true);
200
- expect(profiles.find(p => p.name === 'default')?.isDefault).toBe(false);
201
- });
202
-
203
- it('should return empty array when no profiles exist', async () => {
204
- vi.mocked(fs.readFile).mockRejectedValue({ code: 'ENOENT' });
205
-
206
- const profiles = await configManager.listProfiles();
207
-
208
- expect(profiles).toEqual([]);
209
- });
210
- });
211
-
212
- describe('useProfile', () => {
213
- it('should set default profile', async () => {
214
- const mockStore: ConfigStore = {
215
- profiles: {
216
- default: {
217
- token: 'default-token',
218
- updatedAt: '2025-06-21T10:00:00.000Z'
219
- },
220
- work: {
221
- token: 'work-token',
222
- updatedAt: '2025-06-21T11:00:00.000Z'
223
- }
224
- },
225
- defaultProfile: 'default'
226
- };
227
-
228
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
229
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
230
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
231
-
232
- await configManager.useProfile('work');
233
-
234
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
235
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
236
-
237
- expect(writtenData.defaultProfile).toBe('work');
238
- });
239
-
240
- it('should throw error when profile does not exist', async () => {
241
- const mockStore: ConfigStore = {
242
- profiles: {
243
- default: {
244
- token: 'default-token',
245
- updatedAt: '2025-06-21T10:00:00.000Z'
246
- }
247
- },
248
- defaultProfile: 'default'
249
- };
250
-
251
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
252
-
253
- await expect(configManager.useProfile('nonexistent')).rejects.toThrow('Profile "nonexistent" does not exist');
254
- });
255
- });
256
-
257
- describe('getCurrentProfile', () => {
258
- it('should return current default profile name', async () => {
259
- const mockStore: ConfigStore = {
260
- profiles: {
261
- default: {
262
- token: 'default-token',
263
- updatedAt: '2025-06-21T10:00:00.000Z'
264
- },
265
- work: {
266
- token: 'work-token',
267
- updatedAt: '2025-06-21T11:00:00.000Z'
268
- }
269
- },
270
- defaultProfile: 'work'
271
- };
272
-
273
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
274
-
275
- const currentProfile = await configManager.getCurrentProfile();
276
-
277
- expect(currentProfile).toBe('work');
278
- });
279
-
280
- it('should return "default" when no default profile set', async () => {
281
- const mockStore: ConfigStore = {
282
- profiles: {
283
- default: {
284
- token: 'default-token',
285
- updatedAt: '2025-06-21T10:00:00.000Z'
286
- }
287
- }
288
- };
289
-
290
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
291
-
292
- const currentProfile = await configManager.getCurrentProfile();
293
-
294
- expect(currentProfile).toBe('default');
295
- });
296
- });
297
-
298
- describe('clearConfig', () => {
299
- it('should clear specific profile', async () => {
300
- const mockStore: ConfigStore = {
301
- profiles: {
302
- default: {
303
- token: 'default-token',
304
- updatedAt: '2025-06-21T10:00:00.000Z'
305
- },
306
- work: {
307
- token: 'work-token',
308
- updatedAt: '2025-06-21T11:00:00.000Z'
309
- }
310
- },
311
- defaultProfile: 'work'
312
- };
313
-
314
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
315
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
316
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
317
-
318
- await configManager.clearConfig('work');
319
-
320
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
321
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
322
-
323
- expect(writtenData.profiles.work).toBeUndefined();
324
- expect(writtenData.profiles.default).toBeDefined();
325
- expect(writtenData.defaultProfile).toBe('default'); // fallback to default
326
- });
327
-
328
- it('should clear default profile and reset defaultProfile', async () => {
329
- const mockStore: ConfigStore = {
330
- profiles: {
331
- default: {
332
- token: 'default-token',
333
- updatedAt: '2025-06-21T10:00:00.000Z'
334
- },
335
- work: {
336
- token: 'work-token',
337
- updatedAt: '2025-06-21T11:00:00.000Z'
338
- }
339
- },
340
- defaultProfile: 'default'
341
- };
342
-
343
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
344
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
345
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
346
-
347
- await configManager.clearConfig('default');
348
-
349
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
350
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
351
-
352
- expect(writtenData.profiles.default).toBeUndefined();
353
- expect(writtenData.profiles.work).toBeDefined();
354
- expect(writtenData.defaultProfile).toBe('work'); // switch to remaining profile
355
- });
356
-
357
- it('should delete config file when clearing last profile', async () => {
358
- const mockStore: ConfigStore = {
359
- profiles: {
360
- default: {
361
- token: 'default-token',
362
- updatedAt: '2025-06-21T10:00:00.000Z'
363
- }
364
- },
365
- defaultProfile: 'default'
366
- };
367
-
368
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(mockStore));
369
- vi.mocked(fs.unlink).mockResolvedValue(undefined);
370
-
371
- await configManager.clearConfig('default');
372
-
373
- expect(fs.unlink).toHaveBeenCalledWith(mockConfigPath);
374
- });
375
- });
376
-
377
- describe('migration from old config', () => {
378
- it('should automatically migrate old single-token config to profile format', async () => {
379
- const oldConfig = {
380
- token: 'old-token-123',
381
- updatedAt: '2025-01-01T00:00:00.000Z'
382
- };
383
-
384
- vi.mocked(fs.readFile).mockResolvedValue(JSON.stringify(oldConfig));
385
- vi.mocked(fs.writeFile).mockResolvedValue(undefined);
386
- vi.mocked(fs.chmod).mockResolvedValue(undefined);
387
-
388
- const config = await configManager.getConfig();
389
-
390
- expect(config).toEqual(oldConfig);
391
-
392
- // Verify migration happened
393
- const writeCall = vi.mocked(fs.writeFile).mock.calls[0];
394
- const writtenData = JSON.parse(writeCall[1] as string) as ConfigStore;
395
-
396
- expect(writtenData.profiles.default).toEqual(oldConfig);
397
- expect(writtenData.defaultProfile).toBe('default');
398
- });
399
- });
400
- });
@@ -1,30 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { formatUnixTimestamp, formatSlackTimestamp } from '../../src/utils/date-utils';
3
-
4
- describe('date-utils', () => {
5
- describe('formatUnixTimestamp', () => {
6
- it('should format unix timestamp to ISO date string', () => {
7
- const timestamp = 1640995200; // 2022-01-01 00:00:00 UTC
8
- expect(formatUnixTimestamp(timestamp)).toBe('2022-01-01');
9
- });
10
-
11
- it('should handle different timestamps correctly', () => {
12
- const timestamp = 1672531200; // 2023-01-01 00:00:00 UTC
13
- expect(formatUnixTimestamp(timestamp)).toBe('2023-01-01');
14
- });
15
- });
16
-
17
- describe('formatSlackTimestamp', () => {
18
- it('should format Slack timestamp to locale string', () => {
19
- const slackTimestamp = '1640995200.000000';
20
- const result = formatSlackTimestamp(slackTimestamp);
21
- expect(result).toContain('2022');
22
- });
23
-
24
- it('should handle timestamps with milliseconds', () => {
25
- const slackTimestamp = '1640995200.123456';
26
- const result = formatSlackTimestamp(slackTimestamp);
27
- expect(result).toContain('2022');
28
- });
29
- });
30
- });
@@ -1,34 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { extractErrorMessage } from '../../src/utils/error-utils';
3
-
4
- describe('extractErrorMessage', () => {
5
- it('should extract message from Error instance', () => {
6
- const error = new Error('Test error message');
7
- expect(extractErrorMessage(error)).toBe('Test error message');
8
- });
9
-
10
- it('should convert string to string', () => {
11
- const error = 'String error';
12
- expect(extractErrorMessage(error)).toBe('String error');
13
- });
14
-
15
- it('should convert number to string', () => {
16
- const error = 404;
17
- expect(extractErrorMessage(error)).toBe('404');
18
- });
19
-
20
- it('should convert object to string', () => {
21
- const error = { code: 'ERROR_CODE', detail: 'Some detail' };
22
- expect(extractErrorMessage(error)).toBe('[object Object]');
23
- });
24
-
25
- it('should handle null', () => {
26
- const error = null;
27
- expect(extractErrorMessage(error)).toBe('null');
28
- });
29
-
30
- it('should handle undefined', () => {
31
- const error = undefined;
32
- expect(extractErrorMessage(error)).toBe('undefined');
33
- });
34
- });
@@ -1,61 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { formatMessageWithMentions } from '../../src/utils/format-utils';
3
-
4
- describe('formatMessageWithMentions', () => {
5
- it('should replace user ID mentions with usernames', () => {
6
- const message = 'Hello <@U784E34>, please check this';
7
- const users = new Map([['U784E34', 'sakashita']]);
8
-
9
- const result = formatMessageWithMentions(message, users);
10
-
11
- expect(result).toBe('Hello @sakashita, please check this');
12
- });
13
-
14
- it('should handle multiple mentions', () => {
15
- const message = '<@U784E34> and <@U123456> are working on this';
16
- const users = new Map([
17
- ['U784E34', 'sakashita'],
18
- ['U123456', 'tanaka']
19
- ]);
20
-
21
- const result = formatMessageWithMentions(message, users);
22
-
23
- expect(result).toBe('@sakashita and @tanaka are working on this');
24
- });
25
-
26
- it('should keep user ID if username is not found', () => {
27
- const message = 'Hello <@U784E34>, please check this';
28
- const users = new Map<string, string>();
29
-
30
- const result = formatMessageWithMentions(message, users);
31
-
32
- expect(result).toBe('Hello @U784E34, please check this');
33
- });
34
-
35
- it('should handle messages without mentions', () => {
36
- const message = 'This is a regular message';
37
- const users = new Map<string, string>();
38
-
39
- const result = formatMessageWithMentions(message, users);
40
-
41
- expect(result).toBe('This is a regular message');
42
- });
43
-
44
- it('should handle empty message', () => {
45
- const message = '';
46
- const users = new Map<string, string>();
47
-
48
- const result = formatMessageWithMentions(message, users);
49
-
50
- expect(result).toBe('');
51
- });
52
-
53
- it('should handle malformed mentions', () => {
54
- const message = 'Hello <@>, <@ >, <@invalid';
55
- const users = new Map<string, string>();
56
-
57
- const result = formatMessageWithMentions(message, users);
58
-
59
- expect(result).toBe('Hello <@>, <@ >, <@invalid');
60
- });
61
- });
@@ -1,100 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { extractUserIdsFromMentions, extractAllUserIds } from '../../src/utils/mention-utils';
3
-
4
- describe('mention-utils', () => {
5
- describe('extractUserIdsFromMentions', () => {
6
- it('should extract single user ID from mention', () => {
7
- const text = 'Hello <@U123456789>';
8
- const userIds = extractUserIdsFromMentions(text);
9
- expect(userIds).toEqual(['U123456789']);
10
- });
11
-
12
- it('should extract multiple user IDs from mentions', () => {
13
- const text = 'Hey <@U123456789> and <@U987654321>, please check this';
14
- const userIds = extractUserIdsFromMentions(text);
15
- expect(userIds).toEqual(['U123456789', 'U987654321']);
16
- });
17
-
18
- it('should handle duplicate mentions', () => {
19
- const text = '<@U123456789> mentioned <@U123456789> again';
20
- const userIds = extractUserIdsFromMentions(text);
21
- expect(userIds).toEqual(['U123456789', 'U123456789']);
22
- });
23
-
24
- it('should return empty array for text without mentions', () => {
25
- const text = 'No mentions here';
26
- const userIds = extractUserIdsFromMentions(text);
27
- expect(userIds).toEqual([]);
28
- });
29
-
30
- it('should handle empty text', () => {
31
- const userIds = extractUserIdsFromMentions('');
32
- expect(userIds).toEqual([]);
33
- });
34
-
35
- it('should ignore malformed mentions', () => {
36
- const text = 'Invalid <@> mention and <@lowercase> mention';
37
- const userIds = extractUserIdsFromMentions(text);
38
- expect(userIds).toEqual([]);
39
- });
40
- });
41
-
42
- describe('extractAllUserIds', () => {
43
- it('should extract user IDs from message authors only', () => {
44
- const messages = [
45
- { user: 'U111111111', text: 'Hello world' },
46
- { user: 'U222222222', text: 'Hi there' },
47
- ];
48
- const userIds = extractAllUserIds(messages);
49
- expect(userIds).toEqual(['U111111111', 'U222222222']);
50
- });
51
-
52
- it('should extract user IDs from mentions only', () => {
53
- const messages = [
54
- { text: 'Hello <@U333333333>' },
55
- { text: 'Hi <@U444444444>' },
56
- ];
57
- const userIds = extractAllUserIds(messages);
58
- expect(userIds).toEqual(['U333333333', 'U444444444']);
59
- });
60
-
61
- it('should extract both authors and mentioned users', () => {
62
- const messages = [
63
- { user: 'U111111111', text: 'Hello <@U222222222>' },
64
- { user: 'U333333333', text: 'Hi <@U444444444> and <@U555555555>' },
65
- ];
66
- const userIds = extractAllUserIds(messages);
67
- expect(userIds.sort()).toEqual([
68
- 'U111111111',
69
- 'U222222222',
70
- 'U333333333',
71
- 'U444444444',
72
- 'U555555555',
73
- ]);
74
- });
75
-
76
- it('should remove duplicate user IDs', () => {
77
- const messages = [
78
- { user: 'U111111111', text: 'Hello <@U111111111>' },
79
- { user: 'U111111111', text: 'Another message' },
80
- ];
81
- const userIds = extractAllUserIds(messages);
82
- expect(userIds).toEqual(['U111111111']);
83
- });
84
-
85
- it('should handle messages without user or text', () => {
86
- const messages = [
87
- { user: 'U111111111' },
88
- { text: 'No user here' },
89
- {},
90
- ];
91
- const userIds = extractAllUserIds(messages);
92
- expect(userIds).toEqual(['U111111111']);
93
- });
94
-
95
- it('should handle empty messages array', () => {
96
- const userIds = extractAllUserIds([]);
97
- expect(userIds).toEqual([]);
98
- });
99
- });
100
- });