UNPKG

hubot-slack

Version:
506 lines (427 loc) 21.7 kB
should = require 'should' chai = require 'chai' mockery = require 'mockery' hubotSlackMock = require '../slack.coffee' mockery.registerMock('hubot-slack', hubotSlackMock); { EnterMessage, LeaveMessage, TopicMessage, CatchAllMessage, Robot, loadBot } = require.main.require 'hubot' { SlackTextMessage, ReactionMessage, PresenceMessage, FileSharedMessage } = require '../src/message' SlackClient = require '../src/client' _ = require 'lodash' describe 'Adapter', -> before -> mockery.enable({ warnOnUnregistered: false }); after -> mockery.disable() it 'Should initialize with a robot', -> @slackbot.robot.should.eql @stubs.robot it 'Should load an instance of Robot with extended methods', -> loadedRobot = loadBot('', 'slack', false, 'Hubot') # Check to make sure presenceChange and react are loaded to Robot loadedRobot.presenceChange.should.be.an.instanceOf(Function).with.lengthOf(3) loadedRobot.react.should.be.an.instanceOf(Function).with.lengthOf(3) loadedRobot.fileShared.should.be.an.instanceOf(Function).with.lengthOf(3) describe 'Connect', -> it 'Should connect successfully', -> @slackbot.run() @stubs._connected.should.be.true describe 'Authenticate', -> it 'Should authenticate successfully', -> {logger} = @slackbot.robot start = self: { id: @stubs.self.id name: @stubs.self.name }, team: { id: @stubs.team.id, name: @stubs.team.name }, users: [ @stubs.self, @stubs.user ] @slackbot.authenticated start @slackbot.self.id.should.equal @stubs.self.id @slackbot.robot.name.should.equal @stubs.self.name logger.logs["info"].length.should.be.above(0) logger.logs["info"][logger.logs["info"].length-1].should.equal "Logged in as @#{@stubs.self.name} in workspace #{@stubs.team.name}" describe 'Logger', -> it 'It should log missing token error', -> {logger} = @slackbot.robot @slackbot.options.token = null @slackbot.run() logger.logs["error"].length.should.be.above(0) logger.logs["error"][logger.logs["error"].length-1].should.equal 'No token provided to Hubot' it 'It should log invalid token error', -> {logger} = @slackbot.robot @slackbot.options.token = "ABC123" @slackbot.run() - logger.logs["error"].length.should.be.above(0) logger.logs["error"][logger.logs["error"].length-1].should.equal 'Invalid token provided, please follow the upgrade instructions' describe 'Disable Sync', -> it 'Should sync users by default', -> @slackbot.run() @slackbot.robot.brain.data.users.should.have.keys('1','2','3','4') it 'Should not sync users when disabled', -> @slackbot.options.disableUserSync = true @slackbot.run() @slackbot.robot.brain.data.users.should.be.empty() # Test moved to fetchUsers() in client.coffee because of change in code logic #it 'Should still sync interacting users when disabled' describe 'Send Messages', -> it 'Should send a message', -> @slackbot.send {room: @stubs.channel.id}, 'message' @stubs._sendCount.should.equal 1 @stubs._msg.should.equal 'message' it 'Should send multiple messages', -> @slackbot.send {room: @stubs.channel.id}, 'one', 'two', 'three' @stubs._sendCount.should.equal 3 it 'Should not send empty messages', -> @slackbot.send {room: @stubs.channel.id}, 'Hello', '', '', 'world!' @stubs._sendCount.should.equal 2 it 'Should not fail for inexistant user', -> chai.expect(() => @slackbot.send {room: 'U987'}, 'Hello').to.not.throw() it 'Should open a DM channel if needed', -> msg = 'Test' @slackbot.send {room: @stubs.user.id}, msg @stubs._dmmsg.should.eql msg it 'Should send a message to a user', -> @slackbot.send @stubs.user, 'message' @stubs._dmmsg.should.eql 'message' @stubs._room.should.eql @stubs.user.id describe 'Client sending message', -> it 'Should append as_user = true', -> @client.send {room: @stubs.channel.id}, {text: 'foo', user: @stubs.user, channel: @stubs.channel.id} @stubs._opts.as_user.should.eql true it 'Should append as_user = true only as a default', -> @client.send {room: @stubs.channel.id}, {text: 'foo', user: @stubs.user, channel: @stubs.channel.id, as_user: false} @stubs._opts.as_user.should.eql false describe 'Reply to Messages', -> it 'Should mention the user in a reply sent in a channel', -> @slackbot.reply {user: @stubs.user, room: @stubs.channel.id}, 'message' @stubs._sendCount.should.equal 1 @stubs._msg.should.equal "<@#{@stubs.user.id}>: message" it 'Should mention the user in multiple replies sent in a channel', -> @slackbot.reply {user: @stubs.user, room: @stubs.channel.id}, 'one', 'two', 'three' @stubs._sendCount.should.equal 3 @stubs._msg.should.equal "<@#{@stubs.user.id}>: three" it 'Should send nothing if messages are empty', -> @slackbot.reply {user: @stubs.user, room: @stubs.channel.id}, '' @stubs._sendCount.should.equal 0 it 'Should NOT mention the user in a reply sent in a DM', -> @slackbot.reply {user: @stubs.user, room: @stubs.DM.id }, 'message' @stubs._sendCount.should.equal 1 @stubs._dmmsg.should.equal "message" describe 'Setting the channel topic', -> it 'Should set the topic in channels', (done) -> @stubs.receiveMock.onTopic = (topic) -> topic.should.equal 'channel' done() @slackbot.setTopic {room: @stubs.channel.id}, 'channel' return it 'Should NOT set the topic in DMs', -> @slackbot.setTopic {room: 'D1232'}, 'DM' should.not.exists(@stubs._topic) describe 'Receiving an error event', -> it 'Should propagate that error', -> @hit = false @slackbot.robot.on 'error', (error) => error.msg.should.equal 'ohno' @hit = true @hit.should.equal false @slackbot.error {msg: 'ohno', code: -2} @hit.should.equal true it 'Should handle rate limit errors', -> {logger} = @slackbot.robot @slackbot.error {msg: 'ratelimit', code: -1} logger.logs["error"].length.should.be.above(0) describe 'Handling incoming messages', -> it 'Should handle regular messages as hoped and dreamed', (done) -> @stubs.receiveMock.onReceived = (msg) -> msg.text.should.equal 'foo' done() @slackbot.eventHandler {type: 'message', text: 'foo', user: @stubs.user, channel: @stubs.channel.id } return it 'Should prepend our name to a name-lacking message addressed to us in a DM', -> bot_name = @slackbot.robot.name @stubs.receiveMock.onReceived = (msg) -> msg.text.should.equal "#{bot_name} foo" done() @slackbot.eventHandler {type: 'message', text: "foo", user: @stubs.user, channel: @stubs.DM.id} return it 'Should NOT prepend our name to a name-containing message addressed to us in a DM', -> bot_name = @slackbot.robot.name @stubs.receiveMock.onReceived = (msg) -> msg.text.should.equal "#{bot_name} foo" done() @slackbot.eventHandler {type: 'message', text: "#{bot_name} foo", user: @stubs.user, channel: @stubs.DM.id} return it 'Should return a message object with raw text and message', (done) -> #the shape of this data is an RTM message event passed through SlackClient#messageWrapper #see: https://api.slack.com/events/message messageData = { type: 'message' user: @stubs.user, channel: @stubs.channel.id, text: 'foo <http://www.example.com> bar', } @stubs.receiveMock.onReceived = (msg) -> should.equal (msg instanceof SlackTextMessage), true should.equal msg.text, "foo http://www.example.com bar" should.equal msg.rawText, "foo <http://www.example.com> bar" should.equal msg.rawMessage, messageData done() @slackbot.eventHandler messageData return it 'Should handle member_joined_channel events as envisioned', -> @slackbot.eventHandler {type: 'member_joined_channel', user: @stubs.user, channel: @stubs.channel.id} should.equal @stubs._received.constructor.name, "EnterMessage" @stubs._received.user.id.should.equal @stubs.user.id it 'Should handle member_left_channel events as envisioned', -> @slackbot.eventHandler {type: 'member_left_channel', user: @stubs.user, channel: @stubs.channel.id} should.equal @stubs._received.constructor.name, "LeaveMessage" @stubs._received.user.id.should.equal @stubs.user.id it 'Should handle channel_topic events as envisioned', -> @slackbot.eventHandler {type: 'message', subtype: 'channel_topic', user: @stubs.user, channel: @stubs.channel.id} should.equal @stubs._received.constructor.name, "TopicMessage" @stubs._received.user.id.should.equal @stubs.user.id it 'Should handle group_topic events as envisioned', -> @slackbot.eventHandler {type: 'message', subtype: 'group_topic', user: @stubs.user, channel: @stubs.channel.id} should.equal @stubs._received.constructor.name, "TopicMessage" @stubs._received.user.id.should.equal @stubs.user.id it 'Should handle reaction_added events as envisioned', -> reactionMessage = { type: 'reaction_added', user: @stubs.user, item_user: @stubs.self item: { type: 'message', channel: @stubs.channel.id, ts: '1360782804.083113' }, reaction: 'thumbsup', event_ts: '1360782804.083113' } @slackbot.eventHandler reactionMessage should.equal (@stubs._received instanceof ReactionMessage), true should.equal @stubs._received.user.id, @stubs.user.id should.equal @stubs._received.user.room, @stubs.channel.id should.equal @stubs._received.item_user.id, @stubs.self.id should.equal @stubs._received.type, 'added' should.equal @stubs._received.reaction, 'thumbsup' it 'Should handle reaction_removed events as envisioned', -> reactionMessage = { type: 'reaction_removed', user: @stubs.user, item_user: @stubs.self item: { type: 'message', channel: @stubs.channel.id, ts: '1360782804.083113' }, reaction: 'thumbsup', event_ts: '1360782804.083113' } @slackbot.eventHandler reactionMessage should.equal (@stubs._received instanceof ReactionMessage), true should.equal @stubs._received.user.id, @stubs.user.id should.equal @stubs._received.user.room, @stubs.channel.id should.equal @stubs._received.item_user.id, @stubs.self.id should.equal @stubs._received.type, 'removed' should.equal @stubs._received.reaction, 'thumbsup' it 'Should not crash with bot messages', (done) -> @stubs.receiveMock.onReceived = (msg) -> should.equal (msg instanceof SlackTextMessage), true done() @slackbot.eventHandler {type: 'message', subtype: 'bot_message', user: @stubs.user, channel: @stubs.channel.id, text: 'Pushing is the answer', returnRawText: true } return it 'Should handle single user presence_change events as envisioned', -> @slackbot.robot.brain.userForId(@stubs.user.id, @stubs.user) presenceMessage = { type: 'presence_change', user: @stubs.user, presence: 'away' } @slackbot.eventHandler presenceMessage should.equal (@stubs._received instanceof PresenceMessage), true should.equal @stubs._received.users[0].id, @stubs.user.id @stubs._received.users.length.should.equal 1 it 'Should handle presence_change events as envisioned', -> @slackbot.robot.brain.userForId(@stubs.user.id, @stubs.user) presenceMessage = { type: 'presence_change', users: [@stubs.user.id], presence: 'away' } @slackbot.eventHandler presenceMessage should.equal (@stubs._received instanceof PresenceMessage), true should.equal @stubs._received.users[0].id, @stubs.user.id @stubs._received.users.length.should.equal 1 it 'Should ignore messages it sent itself', -> @slackbot.eventHandler {type: 'message', subtype: 'bot_message', user: @stubs.self, channel: @stubs.channel.id, text: 'Ignore me' } should.equal @stubs._received, undefined it 'Should ignore reaction events that it generated itself', -> reactionMessage = { type: 'reaction_removed', user: @stubs.self, reaction: 'thumbsup', event_ts: '1360782804.083113' } @slackbot.eventHandler reactionMessage should.equal @stubs._received, undefined it 'Should handle empty users as envisioned', (done)-> @stubs.receiveMock.onReceived = (msg) -> should.equal (msg instanceof SlackTextMessage), true done() @slackbot.eventHandler {type: 'message', subtype: 'bot_message', user: {}, channel: @stubs.channel.id, text: 'Foo'} return it 'Should handle reaction events from users who are in different workspace in shared channel', -> reactionMessage = { type: 'reaction_added', user: @stubs.org_user_not_in_workspace_in_channel, item_user: @stubs.self item: { type: 'message', channel: @stubs.channel.id, ts: '1360782804.083113' }, reaction: 'thumbsup', event_ts: '1360782804.083113' } @slackbot.eventHandler reactionMessage should.equal (@stubs._received instanceof ReactionMessage), true should.equal @stubs._received.user.id, @stubs.org_user_not_in_workspace_in_channel.id should.equal @stubs._received.user.room, @stubs.channel.id should.equal @stubs._received.item_user.id, @stubs.self.id should.equal @stubs._received.type, 'added' should.equal @stubs._received.reaction, 'thumbsup' it 'Should handle file_shared events as envisioned', -> fileMessage = { type: 'file_shared', user: @stubs.user, file_id: 'F2147483862', event_ts: '1360782804.083113' } @slackbot.eventHandler fileMessage should.equal (@stubs._received instanceof FileSharedMessage), true should.equal @stubs._received.user.id, @stubs.user.id should.equal @stubs._received.file_id, 'F2147483862' describe 'Robot.react DEPRECATED', -> before -> user = { id: @stubs.user.id, room: @stubs.channel.id } item = { type: 'message', channel: @stubs.channel.id, ts: '1360782804.083113' } @reactionMessage = new ReactionMessage( 'reaction_added', user, 'thumbsup', item, '1360782804.083113' ) @handleReaction = (msg) -> "#{msg.reaction} handled" it 'Should register a Listener with callback only', -> @slackbot.robot.react @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with opts and callback', -> @slackbot.robot.react {id: 'foobar'}, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with matcher and callback', -> matcher = (msg) -> msg.type == 'added' @slackbot.robot.react matcher, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with matcher, opts, and callback', -> matcher = (msg) -> msg.type == 'removed' || msg.reaction == 'thumbsup' @slackbot.robot.react matcher, {id: 'foobar'}, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener that does not match the ReactionMessage', -> matcher = (msg) -> msg.type == 'removed' @slackbot.robot.react matcher, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.false describe 'Robot.fileShared', -> before -> user = { id: @stubs.user.id, room: @stubs.channel.id } @fileSharedMessage = new FileSharedMessage(user, "F2147483862", '1360782804.083113') @handleFileShared = (msg) -> "#{msg.file_id} shared" it 'Should register a Listener with callback only', -> @slackbot.robot.fileShared @handleFileShared listener = @slackbot.robot.listeners.shift() listener.matcher(@fileSharedMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@fileSharedMessage).should.eql('F2147483862 shared') it 'Should register a Listener with opts and callback', -> @slackbot.robot.fileShared {id: 'foobar'}, @handleFileShared listener = @slackbot.robot.listeners.shift() listener.matcher(@fileSharedMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@fileSharedMessage).should.eql('F2147483862 shared') it 'Should register a Listener with matcher and callback', -> matcher = (msg) -> msg.file_id == 'F2147483862' @slackbot.robot.fileShared matcher, @handleFileShared listener = @slackbot.robot.listeners.shift() listener.matcher(@fileSharedMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@fileSharedMessage).should.eql('F2147483862 shared') it 'Should register a Listener with matcher, opts, and callback', -> matcher = (msg) -> msg.file_id == 'F2147483862' @slackbot.robot.fileShared matcher, {id: 'foobar'}, @handleFileShared listener = @slackbot.robot.listeners.shift() listener.matcher(@fileSharedMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@fileSharedMessage).should.eql('F2147483862 shared') it 'Should register a Listener that does not match the ReactionMessage', -> matcher = (msg) -> msg.file_id == 'J12387ALDFK' @slackbot.robot.fileShared matcher, @handleFileShared listener = @slackbot.robot.listeners.shift() listener.matcher(@fileSharedMessage).should.be.false describe 'Robot.hearReaction', -> before -> user = { id: @stubs.user.id, room: @stubs.channel.id } item = { type: 'message', channel: @stubs.channel.id, ts: '1360782804.083113' } @reactionMessage = new ReactionMessage( 'reaction_added', user, 'thumbsup', item, '1360782804.083113' ) @handleReaction = (msg) -> "#{msg.reaction} handled" it 'Should register a Listener with callback only', -> @slackbot.robot.hearReaction @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with opts and callback', -> @slackbot.robot.hearReaction {id: 'foobar'}, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with matcher and callback', -> matcher = (msg) -> msg.type == 'added' @slackbot.robot.hearReaction matcher, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: null}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener with matcher, opts, and callback', -> matcher = (msg) -> msg.type == 'removed' || msg.reaction == 'thumbsup' @slackbot.robot.hearReaction matcher, {id: 'foobar'}, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.true listener.options.should.eql({id: 'foobar'}) listener.callback(@reactionMessage).should.eql('thumbsup handled') it 'Should register a Listener that does not match the ReactionMessage', -> matcher = (msg) -> msg.type == 'removed' @slackbot.robot.hearReaction matcher, @handleReaction listener = @slackbot.robot.listeners.shift() listener.matcher(@reactionMessage).should.be.false describe 'Users data', -> it 'Should load users data from web api', -> @slackbot.usersLoaded(null, @stubs.responseUsersList) user = @slackbot.robot.brain.data.users[@stubs.user.id] should.equal user.id, @stubs.user.id should.equal user.name, @stubs.user.name should.equal user.real_name, @stubs.user.real_name should.equal user.email_address, @stubs.user.profile.email should.equal user.slack.misc, @stubs.user.misc userperiod = @slackbot.robot.brain.data.users[@stubs.userperiod.id] should.equal userperiod.id, @stubs.userperiod.id should.equal userperiod.name, @stubs.userperiod.name should.equal userperiod.real_name, @stubs.userperiod.real_name should.equal userperiod.email_address, @stubs.userperiod.profile.email it 'Should merge with user data which is stored by other program', -> originalUser = something: 'something' @slackbot.robot.brain.userForId @stubs.user.id, originalUser @slackbot.usersLoaded(null, @stubs.responseUsersList) user = @slackbot.robot.brain.data.users[@stubs.user.id] should.equal user.id, @stubs.user.id should.equal user.name, @stubs.user.name should.equal user.real_name, @stubs.user.real_name should.equal user.email_address, @stubs.user.profile.email should.equal user.slack.misc, @stubs.user.misc should.equal user.something, originalUser.something it 'Should detect wrong response from web api', -> @slackbot.usersLoaded(null, @stubs.wrongResponseUsersList) should.equal @slackbot.robot.brain.data.users[@stubs.user.id], undefined