Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ jspm_packages

# Optional REPL history
.node_repl_history
/coverage
/.nyc_output
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
"description": "A module for Slack App integrations",
"main": "src/index.js",
"scripts": {
"test": "standard"
"test": "npm run lint && npm run coverage",
"lint": "standard",
"unit": "ava",
"coverage": "nyc ava"
},
"repository": {
"type": "git",
Expand All @@ -30,6 +33,9 @@
"slack": "^7.5.7"
},
"devDependencies": {
"ava": "^0.15.2",
"nyc": "^7.0.0",
"sinon": "^1.17.4",
"standard": "^7.1.2"
}
}
2 changes: 2 additions & 0 deletions src/conversation_store/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const MemoryStore = require('./memory')

module.exports = (opts) => {
Expand Down
2 changes: 2 additions & 0 deletions src/conversation_store/memory.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

/**
* In memory implementation of a ConversationStore, primarily for testing
*/
Expand Down
2 changes: 2 additions & 0 deletions src/message.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const request = require('request')
const slack = require('slack')

Expand Down
2 changes: 2 additions & 0 deletions src/receiver.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const EventEmitter = require('events')
const bodyParser = require('body-parser')
const fs = require('fs')
Expand Down
34 changes: 27 additions & 7 deletions src/slackapp.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict'

const slack = require('slack')
const conversationStore = require('./conversation_store')
const Receiver = require('./receiver')
Expand Down Expand Up @@ -109,15 +111,21 @@ module.exports = class SlackApp {

use (fn) {
this._middleware.push(fn)

return this
}

/**
* Handle new events (slack events, commands, actions, webhooks, etc.)
* Parameters
* - `msg` `Message`
* - `done` `function(err, bool)` Callback called once complete, called with error and boolean indicating message was handled [optional]
*
* @api private
*/

_handle (msg) {
_handle (msg, done) {
done = done || (() => {})
let self = this
msg.attachSlackApp(self)
let idx = 0
Expand All @@ -135,7 +143,11 @@ module.exports = class SlackApp {
if (err) {
this.onError(err)
}
msg.override(msg)
// invoking override w/o context explicitly
// don't want to confuse consumers w/ a msg as `this` scope
msg.override.call(null, msg)

done(err || null, true)
})
return
}
Expand All @@ -145,12 +157,16 @@ module.exports = class SlackApp {
// if match is a regex, text the regex against the text of a message (if it is a message)
let matcher = self._matchers[i]
if (matcher(msg)) {
return
return done(null, true)
}
}

done(null, false)
}

next()

return this
}

/**
Expand All @@ -176,6 +192,8 @@ module.exports = class SlackApp {

route (fnKey, fn) {
this._registry[fnKey] = fn

return this
}

/**
Expand Down Expand Up @@ -209,6 +227,8 @@ module.exports = class SlackApp {

match (fn) {
this._matchers.push(fn)

return this
}

/**
Expand Down Expand Up @@ -266,7 +286,7 @@ module.exports = class SlackApp {
}
}
}
this.match(fn)
return this.match(fn)
}

/**
Expand Down Expand Up @@ -311,7 +331,7 @@ module.exports = class SlackApp {
}
}

this.match(fn)
return this.match(fn)
}

/**
Expand Down Expand Up @@ -412,7 +432,7 @@ module.exports = class SlackApp {
}
}

this.match(fn)
return this.match(fn)
}

/**
Expand Down Expand Up @@ -469,6 +489,6 @@ module.exports = class SlackApp {
}
}

this.match(fn)
return this.match(fn)
}
}
202 changes: 202 additions & 0 deletions test/slackapp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
'use strict'

const test = require('ava').test
const sinon = require('sinon')
const SlackApp = require('../src/slackapp')

test('SlackApp()', t => {
let options = {
app_token: 'token',
app_user_id: 'app_user_id',
bot_token: 'bot_token',
bot_user_id: 'bot_user_id',
debug: true,
convo_store: () => {},
error: () => {}
}

let app = new SlackApp(options)

t.is(app.app_token, options.app_token)
t.is(app.app_user_id, options.app_user_id)
t.is(app.bot_token, options.bot_token)
t.is(app.bot_user_id, options.bot_user_id)
t.is(app.debug, options.debug)
t.is(app.convoStore, options.convo_store)
t.is(app.onError, options.error)
t.is(typeof app.client, 'object')
t.is(typeof app.receiver, 'object')
t.true(Array.isArray(app._middleware))
t.is(app._middleware.length, 0)
})

test('Slackapp.use()', t => {
let mw = () => {}
let app = new SlackApp()

t.is(app._middleware.length, 0)

app.use(mw)

t.is(app._middleware.length, 1)
t.deepEqual(app._middleware, [mw])
})

test('Slackapp.attachToExpress()', t => {
let app = new SlackApp()
let stub = sinon.stub(app.receiver, 'attachToExpress')

app.attachToExpress({})

t.true(stub.calledOnce)
})

test('SlackApp.route()', t => {
let app = new SlackApp()
let key = 'routeKey'
let fn = () => {}

app.route(key, fn)

t.deepEqual(app._registry[key], fn)
})

test('SlackApp.getRoute()', t => {
let app = new SlackApp()
let key = 'routeKey'
let fn = () => {}

app.route(key, fn)

t.deepEqual(app.getRoute(key), fn)
})

test('SlackApp.match()', t => {
let app = new SlackApp()
let fn = () => {}

t.is(app._matchers.length, 0)

app.match(fn)

t.is(app._matchers.length, 1)
t.deepEqual(app._matchers, [fn])
})

test.cb('SlackApp._handle() 1 mw, no override, no matchers', t => {
t.plan(4)

let app = new SlackApp()
let message = {
override: false,
attachSlackApp: () => {}
}
let attachSlackAppStub = sinon.stub(message, 'attachSlackApp')

app.use((msg, next) => {
t.deepEqual(msg, message)

next()
})

app._handle(message, (err, handled) => {
t.true(attachSlackAppStub.calledOnce)
t.is(err, null)
t.false(handled)
t.end()
})
})

test('SlackApp._handle() no callback provided', t => {
let app = new SlackApp()
let message = {
override: false,
attachSlackApp: () => {}
}
let attachSlackAppStub = sinon.stub(message, 'attachSlackApp')

app._handle(message)

t.true(attachSlackAppStub.calledOnce)
})

test.cb('SlackApp._handle() 1 mw, no override, 1 matchers', t => {
t.plan(4)

let app = new SlackApp()
let message = {
override: false,
attachSlackApp: () => {}
}
let attachSlackAppStub = sinon.stub(message, 'attachSlackApp')

app
.use((msg, next) => {
t.deepEqual(msg, message)

next()
})
.match((msg) => {
return true
})

app._handle(message, (err, handled) => {
t.true(attachSlackAppStub.calledOnce)
t.is(err, null)
t.true(handled)
t.end()
})
})

test.cb('SlackApp._handle() no mw, with override, no matchers', t => {
t.plan(5)

let app = new SlackApp()
let message = {
override: (msg) => {
t.deepEqual(msg, message)
},
conversation_id: 'asdf',
attachSlackApp: () => {}
}
let attachSlackAppStub = sinon.stub(message, 'attachSlackApp')
let delSpy = sinon.spy(app.convoStore, 'del')

app._handle(message, (err, handled) => {
t.true(attachSlackAppStub.calledOnce)
t.is(err, null)
t.true(handled)
t.true(delSpy.calledWith(message.conversation_id))

t.end()
})
})

test.cb('SlackApp._handle() with override and del error', t => {
t.plan(6)

let app = new SlackApp()
let message = {
onError: () => {},
override: (msg) => {
t.deepEqual(msg, message)
},
conversation_id: 'asdf',
attachSlackApp: () => {}
}
let attachSlackAppStub = sinon.stub(message, 'attachSlackApp')
let onErrorSpy = sinon.stub(app, 'onError')
let delStub = sinon.stub(app.convoStore, 'del', (id, cb) => {
cb(new Error('kaboom'))
})

app._handle(message, (err, handled) => {
t.true(attachSlackAppStub.calledOnce)
t.is(err.message, 'kaboom')
t.true(handled)
t.true(delStub.calledWith(message.conversation_id))
t.true(onErrorSpy.calledOnce)

t.end()
})
})