@hubot-friends/hubot-slack 0.0.0-development

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 (72) hide show
  1. package/.github/CODE_OF_CONDUCT.md +11 -0
  2. package/.github/contributing.md +60 -0
  3. package/.github/issue_template.md +48 -0
  4. package/.github/maintainers_guide.md +91 -0
  5. package/.github/pull_request_template.md +8 -0
  6. package/.github/workflows/ci-build.yml +74 -0
  7. package/LICENSE +22 -0
  8. package/README.md +29 -0
  9. package/docs/Gemfile +2 -0
  10. package/docs/README.md +15 -0
  11. package/docs/_config.yml +29 -0
  12. package/docs/_includes/analytics.html +7 -0
  13. package/docs/_includes/head.html +33 -0
  14. package/docs/_includes/page_header.html +20 -0
  15. package/docs/_includes/side_nav.html +22 -0
  16. package/docs/_includes/tag_manager.html +13 -0
  17. package/docs/_layouts/changelog.html +15 -0
  18. package/docs/_layouts/default.html +47 -0
  19. package/docs/_layouts/page.html +10 -0
  20. package/docs/_pages/FAQ.md +63 -0
  21. package/docs/_pages/about.md +16 -0
  22. package/docs/_pages/advanced_usage.md +102 -0
  23. package/docs/_pages/auth.md +44 -0
  24. package/docs/_pages/basic_usage.md +302 -0
  25. package/docs/_pages/changelog.html +17 -0
  26. package/docs/_pages/upgrading.md +49 -0
  27. package/docs/_posts/2016-07-15-v4.0.0.md +14 -0
  28. package/docs/_posts/2016-07-19-v4.0.1.md +5 -0
  29. package/docs/_posts/2016-08-03-v4.0.2.md +4 -0
  30. package/docs/_posts/2016-09-12-v4.0.3.md +8 -0
  31. package/docs/_posts/2016-09-12-v4.0.4.md +4 -0
  32. package/docs/_posts/2016-09-14-v4.0.5.md +4 -0
  33. package/docs/_posts/2016-09-21-v4.1.0.md +4 -0
  34. package/docs/_posts/2016-10-12-v4.2.0.md +4 -0
  35. package/docs/_posts/2016-10-12-v4.2.1.md +4 -0
  36. package/docs/_posts/2016-11-05-v4.2.2.md +8 -0
  37. package/docs/_posts/2017-01-05-v4.3.0.md +5 -0
  38. package/docs/_posts/2017-01-09-v4.3.1.md +5 -0
  39. package/docs/_posts/2017-02-15-v4.3.2.md +5 -0
  40. package/docs/_posts/2017-02-17-v4.3.3.md +4 -0
  41. package/docs/_posts/2017-03-29-v4.3.4.md +5 -0
  42. package/docs/_posts/2017-08-24-v4.4.0.md +7 -0
  43. package/docs/_posts/2018-06-08-v4.5.0.md +13 -0
  44. package/docs/_posts/2018-06-14-v4.5.1.md +4 -0
  45. package/docs/_posts/2018-07-03-v4.5.2.md +5 -0
  46. package/docs/_posts/2018-07-17-v4.5.3.md +12 -0
  47. package/docs/_posts/2018-08-10-v4.5.4.md +7 -0
  48. package/docs/_posts/2018-10-01-v4.5.5.md +7 -0
  49. package/docs/_posts/2018-12-21-v4.6.0.md +6 -0
  50. package/docs/_posts/2019-04-29-v4.7.0.md +6 -0
  51. package/docs/_posts/2019-04-30-v4.7.1.md +5 -0
  52. package/docs/_posts/2020-04-03-v4.7.2.md +6 -0
  53. package/docs/_posts/2020-05-19-v4.8.0.md +10 -0
  54. package/docs/_posts/2020-10-19-v4.8.1.md +7 -0
  55. package/docs/_posts/2021-01-26-v4.9.0.md +8 -0
  56. package/docs/_posts/2022-01-12-v4.10.0.md +8 -0
  57. package/docs/index.md +93 -0
  58. package/docs/styles/docs.css +37 -0
  59. package/package.json +50 -0
  60. package/slack.js +20 -0
  61. package/src/SlackAdapter.mjs +302 -0
  62. package/src/SlackAdapter.test.mjs +342 -0
  63. package/src/bot.js +526 -0
  64. package/src/client.js +445 -0
  65. package/src/extensions.js +82 -0
  66. package/src/mention.js +15 -0
  67. package/src/message.js +307 -0
  68. package/src/testing.mjs +24 -0
  69. package/test/bot.js +769 -0
  70. package/test/client.js +446 -0
  71. package/test/message.js +329 -0
  72. package/test/stubs.js +388 -0
package/test/stubs.js ADDED
@@ -0,0 +1,388 @@
1
+ /*
2
+ * decaffeinate suggestions:
3
+ * DS101: Remove unnecessary use of Array.from
4
+ * DS102: Remove unnecessary code created because of implicit returns
5
+ * DS207: Consider shorter variations of null checks
6
+ * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
7
+ */
8
+ // Setup stubs used by the other tests
9
+
10
+ const SlackBot = require('../src/bot');
11
+ const SlackClient = require('../src/client');
12
+ const {EventEmitter} = require('events');
13
+ const { SlackTextMessage } = require('../src/message');
14
+ // Use Hubot's brain in our stubs
15
+ const {Brain, Robot} = require('hubot');
16
+
17
+ require('../src/extensions');
18
+
19
+ // Stub a few interfaces to grease the skids for tests. These are intentionally
20
+ // as minimal as possible and only provide enough to make the tests possible.
21
+ // Stubs are recreated before each test.
22
+ module.exports = function() {
23
+ const stubs = {};
24
+
25
+ stubs._sendCount = 0;
26
+ stubs.send = (envelope, text, opts) => {
27
+ stubs._room = envelope.room;
28
+ stubs._opts = opts;
29
+ if ((/^[UD@][\d\w]+/.test(stubs._room)) || (stubs._room === stubs.DM.id)) {
30
+ stubs._dmmsg = text;
31
+ } else {
32
+ stubs._msg = text;
33
+ }
34
+ return stubs._sendCount = stubs._sendCount + 1;
35
+ };
36
+
37
+ // These objects are of conversation shape: https://api.slack.com/types/conversation
38
+ stubs.channel = {
39
+ id: 'C123',
40
+ name: 'general'
41
+ };
42
+ stubs.DM = {
43
+ id: 'D1232',
44
+ is_im: true
45
+ };
46
+ stubs.group = {
47
+ id: 'G12324',
48
+ is_mpim: true
49
+ };
50
+
51
+ // These objects are conversation IDs used to siwtch behavior of another stub
52
+ stubs.channelWillFailChatPost = "BAD_CHANNEL";
53
+
54
+ // These objects are of user shape: https://api.slack.com/types/user
55
+ stubs.user = {
56
+ id: 'U123',
57
+ name: 'name', // NOTE: this property is dynamic and should only be used for display purposes
58
+ real_name: 'real_name',
59
+ profile: {
60
+ email: 'email@example.com'
61
+ },
62
+ misc: 'misc'
63
+ };
64
+ stubs.userperiod = {
65
+ name: 'name.lname',
66
+ id: 'U124',
67
+ profile: {
68
+ email: 'name.lname@example.com'
69
+ }
70
+ };
71
+ stubs.userhyphen = {
72
+ name: 'name-lname',
73
+ id: 'U125',
74
+ profile: {
75
+ email: 'name-lname@example.com'
76
+ }
77
+ };
78
+ stubs.usernoprofile = {
79
+ name: 'name',
80
+ real_name: 'real_name',
81
+ id: 'U126',
82
+ misc: 'misc'
83
+ };
84
+ stubs.usernoemail = {
85
+ name: 'name',
86
+ real_name: 'real_name',
87
+ id: 'U126',
88
+ profile: {
89
+ foo: 'bar'
90
+ },
91
+ misc: 'misc'
92
+ };
93
+ stubs.userdeleted = {
94
+ name: 'name',
95
+ id: 'U127',
96
+ deleted: true
97
+ };
98
+
99
+ stubs.bot = {
100
+ name: 'testbot',
101
+ user: 'testbot',
102
+ id: 'B123',
103
+ user_id: 'U123'
104
+ };
105
+ stubs.undefined_user_bot = {
106
+ name: 'testbot',
107
+ id: 'B789'
108
+ };
109
+ stubs.slack_bot = {
110
+ name: 'slackbot',
111
+ user: 'slackbot',
112
+ id: 'B01',
113
+ user_id: 'USLACKBOT'
114
+ };
115
+ stubs.self = {
116
+ name: 'self',
117
+ user: 'self',
118
+ user_id: 'U456',
119
+ bot_id: 'B456',
120
+ profile: {
121
+ email: 'self@example.com'
122
+ }
123
+ };
124
+ stubs.self_bot = {
125
+ name: 'self',
126
+ user: 'self',
127
+ user_id: 'B456',
128
+ profile: {
129
+ email: 'self@example.com'
130
+ }
131
+ };
132
+ stubs.org_user_not_in_workspace = {
133
+ name: 'name',
134
+ id: 'W123',
135
+ profile: {
136
+ email: 'org_not_in_workspace@example.com'
137
+ }
138
+ };
139
+ stubs.org_user_not_in_workspace_in_channel = {
140
+ name: 'name',
141
+ id: 'W123',
142
+ profile: {
143
+ email: 'org_not_in_workspace@example.com'
144
+ }
145
+ };
146
+ stubs.team = {
147
+ name: 'Example Team',
148
+ id: 'T123'
149
+ };
150
+ stubs.expired_timestamp = 1528238205453;
151
+ stubs.event_timestamp = '1360782804.083113';
152
+
153
+ // Slack client
154
+ stubs.client = {
155
+ dataStore: {
156
+ getUserById: id => {
157
+ for (let user of stubs.client.dataStore.users) {
158
+ if (user.id === id) { return user; }
159
+ }
160
+ },
161
+ getBotById: id => {
162
+ for (let bot of stubs.client.dataStore.bots) {
163
+ if (bot.id === id) { return bot; }
164
+ }
165
+ },
166
+ getUserByName: name => {
167
+ for (let user of stubs.client.dataStore.users) {
168
+ if (user.name === name) { return user; }
169
+ }
170
+ },
171
+ getChannelById: id => {
172
+ if (stubs.channel.id === id) { return stubs.channel; }
173
+ },
174
+ getChannelGroupOrDMById: id => {
175
+ if (stubs.channel.id === id) { return stubs.channel; }
176
+ },
177
+ getChannelGroupOrDMByName: name => {
178
+ if (stubs.channel.name === name) { return stubs.channel; }
179
+ for (let dm of stubs.client.dataStore.dms) {
180
+ if (dm.name === name) { return dm; }
181
+ }
182
+ },
183
+ users: [stubs.user, stubs.self, stubs.userperiod, stubs.userhyphen],
184
+ bots: [stubs.bot],
185
+ dms: [{
186
+ name: 'user2',
187
+ id: 'D5432'
188
+ }
189
+ ]
190
+ }
191
+ };
192
+
193
+ stubs.authMock = {
194
+ test: () => {
195
+ return Promise.resolve({
196
+ user_id: stubs.self.id,
197
+ user: stubs.self.name,
198
+ team: stubs.team.name,
199
+ });
200
+ }
201
+ };
202
+
203
+
204
+ stubs.socket = {
205
+ connected: false,
206
+ async start() {
207
+ this.connected = true;
208
+ },
209
+ disconnect() {
210
+ this.connected = false;
211
+ },
212
+ sendMessage(msg, room) {
213
+ return stubs.send(room, msg);
214
+ },
215
+ dataStore: {
216
+ getUserById(id) {
217
+ switch (id) {
218
+ case stubs.user.user_id: return stubs.user;
219
+ case stubs.bot.user_id: return stubs.bot;
220
+ case stubs.self.user_id: return stubs.self;
221
+ case stubs.self_bot.user_id: return stubs.self_bot;
222
+ default: return undefined;
223
+ }
224
+ },
225
+ getChannelGroupOrDMById(id) {
226
+ switch (id) {
227
+ case stubs.channel.id: return stubs.channel;
228
+ case stubs.DM.id: return stubs.DM;
229
+ }
230
+ }
231
+ }
232
+ };
233
+
234
+ stubs.chatMock = {
235
+ postMessage({channel, text}, opts) {
236
+ if (channel === stubs.channelWillFailChatPost) { return Promise.reject(new Error("stub error")); }
237
+ stubs.send({room: channel, text}, text, opts);
238
+ return Promise.resolve();
239
+ }
240
+ };
241
+ stubs.conversationsMock = {
242
+ setTopic: (id, topic) => {
243
+ stubs._topic = topic;
244
+ if (stubs.receiveMock.onTopic != null) {
245
+ stubs.receiveMock.onTopic(stubs._topic);
246
+ }
247
+ return Promise.resolve();
248
+ },
249
+ info: conversationId => {
250
+ if (conversationId === stubs.channel.id) {
251
+ return Promise.resolve({ok: true, channel: stubs.channel});
252
+ } else if (conversationId === stubs.DM.id) {
253
+ return Promise.resolve({ok: true, channel: stubs.DM});
254
+ } else if (conversationId === 'C789') {
255
+ return Promise.resolve();
256
+ } else {
257
+ return Promise.reject(new Error('conversationsMock could not match conversation ID'));
258
+ }
259
+ }
260
+ };
261
+ stubs.botsMock = {
262
+ info: event => {
263
+ const botId = event.bot;
264
+ if (botId === stubs.bot.id) {
265
+ return Promise.resolve({ok: true, bot: stubs.bot});
266
+ } else if (botId === stubs.undefined_user_bot.id) {
267
+ return Promise.resolve({ok: true, bot: stubs.undefined_user_bot});
268
+ } else {
269
+ return Promise.reject(new Error('botsMock could not match bot ID'));
270
+ }
271
+ }
272
+ };
273
+ stubs.usersMock = {
274
+ list: (opts, cb) => {
275
+ stubs._listCount = (stubs != null ? stubs._listCount : undefined) ? stubs._listCount + 1 : 1;
276
+ if (stubs != null ? stubs._listError : undefined) { return cb(new Error('mock error')); }
277
+ if ((opts != null ? opts.cursor : undefined) === 'mock_cursor') {
278
+ return cb(null, stubs.userListPageLast);
279
+ } else {
280
+ return cb(null, stubs.userListPageWithNextCursor);
281
+ }
282
+ },
283
+ info(params) {
284
+ if (params.user === stubs.user.id) {
285
+ return Promise.resolve({ok: true, user: stubs.user});
286
+ } else if (params.user === stubs.org_user_not_in_workspace.id) {
287
+ return Promise.resolve({ok: true, user: stubs.org_user_not_in_workspace});
288
+ } else if (params.user === 'U789') {
289
+ return Promise.resolve();
290
+ } else {
291
+ return Promise.reject(new Error('usersMock could not match user ID'));
292
+ }
293
+ }
294
+ };
295
+ stubs.userListPageWithNextCursor = {
296
+ members: [{ id: 1 }, { id: 2 }, { id: 4, profile: { bot_id: 'B1' } }],
297
+ response_metadata: {
298
+ next_cursor: 'mock_cursor'
299
+ }
300
+ };
301
+ stubs.userListPageLast = {
302
+ members: [{ id: 3 }],
303
+ response_metadata: {
304
+ next_cursor: ''
305
+ }
306
+ };
307
+
308
+ stubs.responseUsersList = {
309
+ ok: true,
310
+ members: [stubs.user, stubs.userperiod]
311
+ };
312
+ stubs.wrongResponseUsersList = {
313
+ ok: false,
314
+ members: []
315
+ };
316
+ // Hubot.Robot instance
317
+ stubs.robot = new EventEmitter;
318
+ // noop the logging
319
+ stubs.robot.logger = {
320
+ logs: {},
321
+ log(type, message) {
322
+ if (!this.logs[type]) {
323
+ this.logs[type] = [];
324
+ }
325
+ return this.logs[type].push(message);
326
+ },
327
+ info(message) {
328
+ return this.log('info', message);
329
+ },
330
+ debug(message) {
331
+ return this.log('debug', message);
332
+ },
333
+ error(message) {
334
+ return this.log('error', message);
335
+ },
336
+ warning(message) {
337
+ return this.log('warning', message);
338
+ }
339
+ };
340
+ // attach a real Brain to the robot
341
+ stubs.robot.brain = new Brain(stubs.robot);
342
+ stubs.robot.name = 'self';
343
+ stubs.robot.listeners = [];
344
+ stubs.robot.listen = Robot.prototype.listen.bind(stubs.robot);
345
+ stubs.robot.hearReaction = Robot.prototype.hearReaction.bind(stubs.robot);
346
+ stubs.robot.fileShared = Robot.prototype.fileShared.bind(stubs.robot);
347
+ stubs.callback = ((() => "done"))();
348
+
349
+ stubs.receiveMock = {
350
+ receive: (message, user) => {
351
+ stubs._received = message;
352
+ if (stubs.receiveMock.onReceived != null) {
353
+ return stubs.receiveMock.onReceived(message);
354
+ }
355
+ }
356
+ };
357
+
358
+ // Generate a new slack instance for each test.
359
+ let slackbot = new SlackBot(stubs.robot, {botToken: 'xoxb-faketoken', appToken: 'xapp-faketoken'});
360
+
361
+ Object.assign(slackbot.client, stubs.client);
362
+ Object.assign(slackbot.client.socket, stubs.socket);
363
+ Object.assign(slackbot.client.web.auth, stubs.authMock);
364
+ Object.assign(slackbot.client.web.chat, stubs.chatMock);
365
+ Object.assign(slackbot.client.web.users, stubs.usersMock);
366
+ Object.assign(slackbot.client.web.conversations, stubs.conversationsMock);
367
+ Object.assign(slackbot, stubs.receiveMock);
368
+ slackbot.self = stubs.self;
369
+
370
+ let slacktextmessage = new SlackTextMessage(stubs.self, undefined, undefined, {text: undefined}, stubs.channel.id, undefined, slackbot.client);
371
+
372
+ let slacktextmessage_invalid_conversation = new SlackTextMessage(stubs.self, undefined, undefined, {text: undefined}, 'C888', undefined, slackbot.client);
373
+
374
+ let client = new SlackClient({botToken: 'xoxb-faketoken', appToken: 'xapp-faketoken'}, stubs.robot);
375
+ Object.assign(client.socket, stubs.socket);
376
+ Object.assign(client.web.auth, stubs.authMock);
377
+ Object.assign(client.web.chat, stubs.chatMock);
378
+ Object.assign(client.web.conversations, stubs.conversationsMock);
379
+ Object.assign(client.web.users, stubs.usersMock);
380
+ Object.assign(client.web.bots, stubs.botsMock);
381
+ return {
382
+ client,
383
+ slacktextmessage,
384
+ slackbot,
385
+ stubs,
386
+ slacktextmessage_invalid_conversation
387
+ };
388
+ };