@hubot-friends/hubot-slack 1.0.10 → 2.0.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/index.js CHANGED
@@ -1,5 +1,5 @@
1
- const SlackBot = require('./src/bot');
2
- require('./src/extensions');
1
+ const SlackBot = require('./src/bot.js').SlackBot;
2
+ require('./src/extensions.js');
3
3
 
4
4
  exports.use = function(robot) {
5
5
  let e;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubot-friends/hubot-slack",
3
- "version": "1.0.10",
3
+ "version": "2.0.0",
4
4
  "description": "A new Slack adapter for Hubot",
5
5
  "homepage": "https://github.com/hubot-friends/hubot-slack#readme",
6
6
  "main": "./index.js",
@@ -27,7 +27,7 @@
27
27
  "@slack/web-api": "^6.8.1"
28
28
  },
29
29
  "peerDependencies": {
30
- "hubot": ">= 7.0.0"
30
+ "hubot": ">= 9.0.0"
31
31
  },
32
32
  "engines": {
33
33
  "node": ">= 18.16.0",
@@ -264,15 +264,12 @@ class SlackAdapter extends Adapter {
264
264
  this.robot.logger.info(`Replying to message in ${envelope.room}`)
265
265
  return this.send(envelope, ...strings)
266
266
  }
267
- run() {
268
- this.#webSocketClient.start().then(async result => {
269
- // const channelResponse = await this.#webClient.conversations.list()
270
- // console.log('channelResponse', channelResponse)
271
- const response = await this.#webClient.auth.test()
272
- this.robot.self = new AuthTestResponse(response).user
273
- this.robot.logger.info('Connected to Slack after starting socket client.')
274
- this.emit('connected')
275
- }).catch(e => this.robot.logger.error(e))
267
+ async run() {
268
+ await this.#webSocketClient.start()
269
+ const response = await this.#webClient.auth.test()
270
+ this.robot.self = new AuthTestResponse(response).user
271
+ this.robot.logger.info('Connected to Slack after starting socket client.')
272
+ this.emit('connected')
276
273
  }
277
274
  }
278
275
 
@@ -237,57 +237,60 @@ describe('Listen to messages', async () => {
237
237
  adapter.emit('authenticated', authenticatedPerson(), null)
238
238
  }
239
239
  })
240
- robot.run()
240
+ await robot.run()
241
241
  })
242
242
  afterEach(async () => {
243
243
  robot.shutdown()
244
244
  })
245
- it('should listen to a message', (t, done) => {
245
+ it('should listen to a message', async () => {
246
+ let wasCalled = false
246
247
  robot.listen(message => {
247
248
  if(message instanceof TextMessage) {
248
249
  assert.deepEqual(message.text, 'Hello world')
249
- done()
250
+ wasCalled = true
250
251
  return true
251
252
  }
252
253
  assert.fail('expect a message')
253
254
  },
254
255
  {id: 'message listener'},
255
- res => {
256
- res.send('hi')
256
+ async res => {
257
+ await res.send('hi')
257
258
  assert.ok(true, 'should be called for message')
258
259
  })
259
- robot.adapter.mapToHubotMessage(buildSlackMessage({
260
+ const message = await robot.adapter.mapToHubotMessage(buildSlackMessage({
260
261
  "type": "message",
261
262
  "channel": "C123ABC456",
262
263
  "user": "U123ABC456",
263
264
  "text": "Hello world",
264
265
  "ts": "1355517523.000005"
265
- }).event).then(message => {
266
- robot.receive(message)
267
- }).catch(e => console.error)
266
+ }).event)
267
+ await robot.receive(message)
268
+ assert.deepEqual(wasCalled, true)
268
269
  })
269
- it('should hear a message, which uses regex for matching', (t, done) => {
270
+ it('should hear a message, which uses regex for matching', async () => {
271
+ let wasCalled = false
270
272
  robot.hear(/hello/i, {id: 'message listener'},
271
273
  context => {
272
274
  assert.deepEqual(context.message.text, 'hello')
273
- done()
275
+ wasCalled = true
274
276
  return true
275
277
  }
276
278
  )
277
- robot.adapter.mapToHubotMessage(buildSlackMessage({
279
+ const message = await robot.adapter.mapToHubotMessage(buildSlackMessage({
278
280
  "type": "message",
279
281
  "channel": "C123ABC456",
280
282
  "user": "U123ABC456",
281
283
  "text": `hello`,
282
284
  "ts": "1355517523.000005"
283
- }).event).then(message => {
284
- robot.receive(message)
285
- }).catch(e =>console.error)
285
+ }).event)
286
+ await robot.receive(message)
287
+ assert.deepEqual(wasCalled, true)
286
288
  })
287
289
  })
288
290
 
289
291
  describe('Send messages back', async () => {
290
- it('should reply to a message that was sent to Hubot', (t, done) => {
292
+ it('should reply to a message that was sent to Hubot', async () => {
293
+ let wasCalled = false
291
294
  const robot = makeRobot({
292
295
  async start(adapter) {
293
296
  adapter.emit('authenticated', authenticatedPerson(), null)
@@ -297,8 +300,6 @@ describe('Send messages back', async () => {
297
300
  async postMessage({ channel, text }) {
298
301
  assert.deepEqual(channel, 'C123ABC456')
299
302
  assert.deepEqual(text, 'hi')
300
- robot.shutdown()
301
- done()
302
303
  }
303
304
  },
304
305
  users: {
@@ -317,26 +318,24 @@ describe('Send messages back', async () => {
317
318
  }
318
319
  }
319
320
  })
320
- robot.run()
321
-
322
321
  robot.respond(/hello/i, {id: 'message responder'},
323
322
  context => {
324
323
  assert.deepEqual(context.message.text, '@hubot hello')
325
324
  context.reply('hi')
326
- done()
327
325
  robot.shutdown()
326
+ wasCalled = true
328
327
  })
329
- robot.adapter.on('connected', () => {
330
- robot.adapter.mapToHubotMessage(buildSlackMessage({
331
- "type": "message",
332
- "channel": "C123ABC456",
333
- "user": "U123ABC456",
334
- "text": `<@${BOT_ID}> hello`,
335
- "ts": "1355517523.000005"
336
- }).event).then(message => {
337
- message.text = robot.adapter.replaceBotIdWithName(message)
338
- robot.receive(message)
339
- }).catch(e => console.error)
340
- })
328
+ await robot.run()
329
+ const message = await robot.adapter.mapToHubotMessage(buildSlackMessage({
330
+ "type": "message",
331
+ "channel": "C123ABC456",
332
+ "user": "U123ABC456",
333
+ "text": `<@${BOT_ID}> hello`,
334
+ "ts": "1355517523.000005"
335
+ }).event)
336
+ message.text = robot.adapter.replaceBotIdWithName(message)
337
+ await robot.receive(message)
338
+ assert.deepEqual(wasCalled, true)
339
+ robot.shutdown()
341
340
  })
342
341
  })
package/src/bot.js CHANGED
@@ -20,7 +20,7 @@ class SlackClient {
20
20
  this.apiPageSize = parseInt(options.apiPageSize, 10);
21
21
  }
22
22
 
23
- this.robot.logger.debug(`SocketModeClient initialized with options: ${JSON.stringify(options.socketModeOptions)}`);
23
+ this.robot.logger.debug(`SocketModeClient initialized with options: ${JSON.stringify(options.socketModeOptions) ?? ''}`);
24
24
 
25
25
  // Map to convert bot user IDs (BXXXXXXXX) to user representations for events from custom
26
26
  // integrations and apps without a bot user
@@ -58,23 +58,21 @@ class SlackClient {
58
58
  return this.socket.removeAllListeners();
59
59
  }
60
60
 
61
- setTopic(conversationId, topic) {
61
+ async setTopic(conversationId, topic) {
62
62
  this.robot.logger.debug(`SlackClient#setTopic() with topic ${topic}`);
63
- return this.web.conversations.info({channel: conversationId})
64
- .then(res => {
65
- const conversation = res.channel;
66
- if (!conversation.is_im && !conversation.is_mpim) {
67
- return this.web.conversations.setTopic({channel: conversationId, topic});
68
- } else {
69
- return this.robot.logger.debug(`Conversation ${conversationId} is a DM or MPDM. ` +
70
- "These conversation types do not have topics."
71
- );
72
- }
73
- }).catch(error => {
74
- return this.robot.logger.error(error, `Error setting topic in conversation ${conversationId}: ${error.message}`);
75
- });
63
+ try {
64
+ const res = await this.web.conversations.info({channel: conversationId})
65
+ const conversation = res.channel;
66
+ if (!conversation.is_im && !conversation.is_mpim) {
67
+ return this.web.conversations.setTopic({channel: conversationId, topic});
68
+ } else {
69
+ return this.robot.logger.debug(`Conversation ${conversationId} is a DM or MPDM. These conversation types do not have topics.`);
70
+ }
71
+ } catch (error) {
72
+ this.robot.logger.error(error, `Error setting topic in conversation ${conversationId}: ${error.message}`);
73
+ }
76
74
  }
77
- send(envelope, message) {
75
+ async send(envelope, message) {
78
76
  const room = envelope.room || envelope.id;
79
77
  if (room == null) {
80
78
  this.robot.logger.error("Cannot send message without a valid room. Envelopes should contain a room property set to a Slack conversation ID.");
@@ -83,13 +81,19 @@ class SlackClient {
83
81
  this.robot.logger.debug(`SlackClient#send() room: ${room}, message: ${message}`);
84
82
  if (typeof message !== "string") {
85
83
  message.channel = room
86
- return this.web.chat.postMessage(message).then(result => {
84
+ try {
85
+ const result = await this.web.chat.postMessage(message)
87
86
  this.robot.logger.debug(`Successfully sent message to ${room}`)
88
- }).catch(e => this.robot.logger.error(e, `SlackClient#send(message) error: ${e.message}`))
87
+ } catch (e) {
88
+ this.robot.logger.error(e, `SlackClient#send(message) error: ${e.message}`)
89
+ }
89
90
  } else {
90
- return this.web.chat.postMessage({ channel: room, text: message }).then(result => {
91
+ try {
92
+ const result = await this.web.chat.postMessage({ channel: room, text: message })
91
93
  this.robot.logger.debug(`Successfully sent message (string) to ${room}`)
92
- }).catch(e => this.robot.logger.error(e, `SlackClient#send(string) error: ${e.message}`))
94
+ } catch (e) {
95
+ this.robot.logger.error(e, `SlackClient#send(string) error: ${e.message}`)
96
+ }
93
97
  }
94
98
  }
95
99
  loadUsers(callback) {
@@ -121,20 +125,19 @@ class SlackClient {
121
125
  this.updateUserInBrain(r.user);
122
126
  return r.user;
123
127
  }
124
- fetchConversation(conversationId) {
128
+ async fetchConversation(conversationId) {
125
129
  const expiration = Date.now() - SlackClient.CONVERSATION_CACHE_TTL_MS;
126
130
  if (((this.channelData[conversationId] != null ? this.channelData[conversationId].channel : undefined) != null) &&
127
131
  (expiration < (this.channelData[conversationId] != null ? this.channelData[conversationId].updated : undefined))) { return Promise.resolve(this.channelData[conversationId].channel); }
128
132
  if (this.channelData[conversationId] != null) { delete this.channelData[conversationId]; }
129
- return this.web.conversations.info({channel: conversationId}).then(r => {
130
- if (r.channel != null) {
131
- this.channelData[conversationId] = {
132
- channel: r.channel,
133
- updated: Date.now()
134
- };
135
- }
136
- return r.channel;
137
- });
133
+ const r = await this.web.conversations.info({channel: conversationId})
134
+ if (r.channel != null) {
135
+ this.channelData[conversationId] = {
136
+ channel: r.channel,
137
+ updated: Date.now()
138
+ };
139
+ }
140
+ return r.channel;
138
141
  }
139
142
  updateUserInBrain(event_or_user) {
140
143
  let key, value;
@@ -246,7 +249,7 @@ class SlackBot extends Adapter {
246
249
  * @param {Object} envelope - fully documented in SlackClient
247
250
  * @param {...(string|Object)} messages - fully documented in SlackClient
248
251
  */
249
- send(envelope, ...messages) {
252
+ async send(envelope, ...messages) {
250
253
  this.robot.logger.debug('Sending message to Slack');
251
254
  let callback = function() {};
252
255
  if (typeof(messages[messages.length - 1]) === "function") {
@@ -257,7 +260,15 @@ class SlackBot extends Adapter {
257
260
  // NOTE: perhaps do envelope manipulation here instead of in the client (separation of concerns)
258
261
  if (message !== "") { return this.client.send(envelope, message); }
259
262
  });
260
- return Promise.all(messagePromises).then(callback.bind(null, null), callback);
263
+ let results = [];
264
+ try {
265
+ results = await Promise.all(messagePromises)
266
+ callback(null, null)
267
+ } catch (e) {
268
+ this.robot.logger.error(e);
269
+ callback(e, null);
270
+ }
271
+ return results;
261
272
  }
262
273
 
263
274
  /**
@@ -266,7 +277,7 @@ class SlackBot extends Adapter {
266
277
  * @param {Object} envelope - fully documented in SlackClient
267
278
  * @param {...(string|Object)} messages - fully documented in SlackClient
268
279
  */
269
- reply(envelope, ...messages) {
280
+ async reply(envelope, ...messages) {
270
281
  this.robot.logger.debug('replying to message');
271
282
  let callback = function() {};
272
283
  if (typeof(messages[messages.length - 1]) === "function") {
@@ -283,7 +294,15 @@ class SlackBot extends Adapter {
283
294
  return this.client.send(envelope, message);
284
295
  }
285
296
  });
286
- return Promise.all(messagePromises).then(callback.bind(null, null), callback);
297
+ let results = [];
298
+ try {
299
+ results = await Promise.all(messagePromises)
300
+ callback(null, null)
301
+ } catch (e) {
302
+ this.robot.logger.error(e);
303
+ callback(e, null);
304
+ }
305
+ return results;
287
306
  }
288
307
 
289
308
  /**
@@ -292,10 +311,8 @@ class SlackBot extends Adapter {
292
311
  * @param {Object} envelope - fully documented in SlackClient
293
312
  * @param {...string} strings - strings that will be newline separated and set to the conversation topic
294
313
  */
295
- setTopic(envelope, ...strings) {
296
- // TODO: if the sender is interested in the completion, the last item in `messages` will be a function
297
- // TODO: this will fail if sending an object as a value in strings
298
- return this.client.setTopic(envelope.room, strings.join("\n"));
314
+ async setTopic(envelope, ...strings) {
315
+ return await this.client.setTopic(envelope.room, strings.join("\n"));
299
316
  }
300
317
 
301
318
  /**
@@ -457,12 +474,13 @@ class SlackBot extends Adapter {
457
474
  // Hubot expects all user objects to have a room property that is used in the envelope for the message after it
458
475
  // is received
459
476
  from.room = channel ?? '';
460
- from.name = from.profile.display_name;
477
+ from.name = from?.profile?.display_name ?? null;
461
478
 
462
479
  // add the bot id to the message if it's a direct message
463
480
  message.body.event.text = this.addBotIdToMessage(message.body.event);
464
481
  message.body.event.text = this.replaceBotIdWithName(message.body.event);
465
482
  this.robot.logger.debug(`Text = ${message.body.event.text}`);
483
+ this.robot.logger.debug(`Event subtype = ${message.body.event?.subtype}`);
466
484
  try {
467
485
  switch (message.event.type) {
468
486
  case "member_joined_channel":
@@ -470,13 +488,13 @@ class SlackBot extends Adapter {
470
488
  this.robot.logger.debug(`Received enter message for user: ${from.id}, joining: ${channel}`);
471
489
  msg = new EnterMessage(from);
472
490
  msg.ts = message.event.ts;
473
- this.receive(msg);
491
+ await this.receive(msg);
474
492
  break;
475
493
  case "member_left_channel":
476
494
  this.robot.logger.debug(`Received leave message for user: ${from.id}, joining: ${channel}`);
477
495
  msg = new LeaveMessage(user);
478
496
  msg.ts = message.ts;
479
- this.receive(msg);
497
+ await this.receive(msg);
480
498
  break;
481
499
  case "reaction_added": case "reaction_removed":
482
500
  // Once again Hubot expects all user objects to have a room property that is used in the envelope for the message
@@ -490,18 +508,20 @@ class SlackBot extends Adapter {
490
508
  const item_user = (message.body.event.item_user != null) ? this.robot.brain.userForId(message.body.event.item_user.id, message.body.event.item_user) : {};
491
509
 
492
510
  this.robot.logger.debug(`Received reaction message from: ${from.id}, reaction: ${message.body.event.reaction}, item type: ${message.body.event.item.type}`);
493
- this.receive(new ReactionMessage(message.body.event.type, from, message.body.event.reaction, item_user, message.body.event.item, message.body.event.event_ts));
511
+ await this.receive(new ReactionMessage(message.body.event.type, from, message.body.event.reaction, item_user, message.body.event.item, message.body.event.event_ts));
494
512
  break;
495
513
  case "file_shared":
496
514
  this.robot.logger.debug(`Received file_shared message from: ${message.body.event.user_id}, file_id: ${message.body.event.file_id}`);
497
- this.receive(new FileSharedMessage(from, message.body.event.file_id, message.body.event.event_ts));
515
+ await this.receive(new FileSharedMessage(from, message.body.event.file_id, message.body.event.event_ts));
498
516
  break;
499
517
  default:
500
518
  this.robot.logger.debug(`Received generic message: ${message.event.type}`);
501
- SlackTextMessage.makeSlackTextMessage(from, null, message?.body?.event.text, message?.body?.event, channel, this.robot.name, this.robot.alias, this.client, (error, message) => {
502
- if (error) { return this.robot.logger.error(error, `Dropping message due to error ${error.message}`); }
503
- return this.receive(message);
504
- });
519
+ try {
520
+ const msg = await SlackTextMessage.makeSlackTextMessage(from, null, message?.body?.event.text, message?.body?.event, channel, this.robot.name, this.robot.alias, this.client)
521
+ await this.receive(msg);
522
+ } catch (error) {
523
+ this.robot.logger.error(error, `Dropping message due to error ${error.message}`);
524
+ }
505
525
  break;
506
526
  }
507
527
  } catch (e) {
@@ -528,5 +548,5 @@ class SlackBot extends Adapter {
528
548
  return res.members.map((member) => this.client.updateUserInBrain(member));
529
549
  }
530
550
  }
531
-
532
- module.exports = SlackBot;
551
+ module.exports.SlackClient = SlackClient;
552
+ module.exports.SlackBot = SlackBot;
package/src/message.js CHANGED
@@ -1,5 +1,5 @@
1
- const {Message, TextMessage} = require.main.require("hubot/es2015.js");
2
- const SlackClient = require("./client");
1
+ const { Message, TextMessage, TopicMessage } = require.main.require("hubot/es2015.js");
2
+ const SlackClient = require("./bot.js");
3
3
  const SlackMention = require("./mention");
4
4
 
5
5
  class ReactionMessage extends Message {
@@ -114,10 +114,9 @@ class SlackTextMessage extends TextMessage {
114
114
  * @param {SlackClient} client - a client that can be used to get more data needed to build the text
115
115
  * @param {function} cb - callback for the result
116
116
  */
117
- buildText(client, cb) {
117
+ async buildText(client) {
118
118
  // base text
119
119
  let text = (this.rawMessage.text != null) ? this.rawMessage.text : "";
120
-
121
120
  // flatten any attachments into text
122
121
  if (this.rawMessage.attachments) {
123
122
  const attachment_text = this.rawMessage.attachments.map(a => a.fallback).join("\n");
@@ -128,19 +127,18 @@ class SlackTextMessage extends TextMessage {
128
127
  const mentionFormatting = this.replaceLinks(client, text);
129
128
  // Fetch conversation info
130
129
  const fetchingConversationInfo = client.fetchConversation(this._channel_id);
131
- return Promise.all([mentionFormatting, fetchingConversationInfo])
132
- .then(results => {
133
- const [ replacedText, conversationInfo ] = results;
134
- text = replacedText;
135
- text = text.replace(/&lt;/g, "<");
136
- text = text.replace(/&gt;/g, ">");
137
- text = text.replace(/&amp;/g, "&");
138
- this.text = text;
139
- return cb();
140
- }).catch(error => {
141
- client.robot.logger.error(error, `An error occurred while building text: ${error.message}`);
142
- return cb(error);
143
- });
130
+ let results = [];
131
+ try {
132
+ results = await Promise.all([mentionFormatting, fetchingConversationInfo]);
133
+ const [ replacedText, conversationInfo ] = results;
134
+ text = replacedText;
135
+ text = text.replace(/&lt;/g, "<");
136
+ text = text.replace(/&gt;/g, ">");
137
+ text = text.replace(/&amp;/g, "&");
138
+ } catch (e) {
139
+ client.robot.logger.error(e, `An error occurred while building text: ${e.message}`);
140
+ }
141
+ return text;
144
142
  }
145
143
 
146
144
  /**
@@ -271,22 +269,14 @@ class SlackTextMessage extends TextMessage {
271
269
  * @param {SlackClient} client - client used to fetch more data
272
270
  * @param {function} cb - callback to return the result
273
271
  */
274
- static makeSlackTextMessage(user, text, rawText, rawMessage, channel_id, robot_name, robot_alias, client, cb) {
275
- const message = new SlackTextMessage(user, text, rawText, rawMessage, channel_id, robot_name, robot_alias);
276
-
277
- // creates a completion function that consistently calls the callback after this function has returned
278
- const done = message => setImmediate(() => cb(null, message));
279
-
280
- if ((message.text == null)) {
281
- return message.buildText(client, function(error) {
282
- if (error) {
283
- return cb(error);
284
- }
285
- return done(message);
286
- });
287
- } else {
288
- return done(message);
272
+ static async makeSlackTextMessage(user, text, rawText, rawMessage, channel_id, robot_name, robot_alias, client) {
273
+ if(rawMessage?.subtype) {
274
+ return new TopicMessage(user, rawMessage.text, rawMessage.event_ts)
289
275
  }
276
+ const message = new SlackTextMessage(user, text, rawText, rawMessage, channel_id, robot_name, robot_alias);
277
+ if (message.text !== null) return message;
278
+ message.text = await message.buildText(client);
279
+ return message;
290
280
  }
291
281
  }
292
282
 
package/test/bot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  const {describe, it, beforeEach, before, after} = require('node:test');
2
2
  const assert = require('node:assert/strict');
3
3
  const Module = require('module');
4
- const SlackBot = require('../src/bot.js');
4
+ const SlackBot = require('../src/bot.js').SlackBot;
5
5
 
6
6
  const hookModuleToReturnMockFromRequire = (module, mock) => {
7
7
  const originalRequire = Module.prototype.require;
@@ -208,23 +208,6 @@ describe('Send Messages', function() {
208
208
  });
209
209
  });
210
210
 
211
- describe('Client sending message', function() {
212
- let stubs, client;
213
- beforeEach(function() {
214
- ({stubs, client} = require('./stubs.js')());
215
- });
216
-
217
- it('Should append as_user = true', function() {
218
- client.send({room: stubs.channel.id}, {text: 'foo', user: stubs.user, channel: stubs.channel.id});
219
- assert.ok(stubs._opts.as_user);
220
- });
221
-
222
- it('Should append as_user = true only as a default', function() {
223
- client.send({room: stubs.channel.id}, {text: 'foo', user: stubs.user, channel: stubs.channel.id, as_user: false});
224
- assert.deepEqual(stubs._opts.as_user, true);
225
- });
226
- });
227
-
228
211
  describe('Reply to Messages', function() {
229
212
  let stubs, slackbot;
230
213
  beforeEach(function() {
@@ -290,16 +273,18 @@ describe('Setting the channel topic', function() {
290
273
  ({stubs, slackbot} = require('./stubs.js')());
291
274
  });
292
275
 
293
- it('Should set the topic in channels', function(t, done) {
276
+ it('Should set the topic in channels', async () => {
277
+ let wasCalled = false;
294
278
  stubs.receiveMock.onTopic = function(topic) {
295
279
  assert.deepEqual(topic, 'channel');
296
- done();
280
+ wasCalled = true;
297
281
  };
298
- slackbot.setTopic({room: stubs.channel.id}, 'channel');
282
+ await slackbot.setTopic({room: stubs.channel.id}, 'channel');
283
+ assert.deepEqual(wasCalled, true);
299
284
  });
300
285
 
301
- it('Should NOT set the topic in DMs', function() {
302
- slackbot.setTopic({room: 'D1232'}, 'DM');
286
+ it('Should NOT set the topic in DMs', async () => {
287
+ await slackbot.setTopic({room: 'D1232'}, 'DM');
303
288
  assert.equal(stubs._topic, undefined);
304
289
  });
305
290
  });