hubot 5.0.4 → 5.0.6
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/package.json +1 -1
- package/src/robot.js +0 -11
- package/.editorconfig +0 -14
- package/.github/stale.yml +0 -23
- package/.github/workflows/nodejs-macos.yml +0 -26
- package/.github/workflows/nodejs-ubuntu.yml +0 -28
- package/.github/workflows/nodejs-windows.yml +0 -26
- package/.github/workflows/release.yml +0 -37
- package/bin/e2e-test.sh +0 -47
- package/docs/adapters/campfire.md +0 -79
- package/docs/adapters/development.md +0 -125
- package/docs/adapters/shell.md +0 -24
- package/docs/adapters.md +0 -27
- package/docs/deploying/azure.md +0 -97
- package/docs/deploying/bluemix.md +0 -111
- package/docs/deploying/heroku.md +0 -66
- package/docs/deploying/unix.md +0 -72
- package/docs/deploying/windows.md +0 -66
- package/docs/deploying.md +0 -11
- package/docs/implementation.md +0 -55
- package/docs/index.md +0 -125
- package/docs/patterns.md +0 -265
- package/docs/scripting.md +0 -1051
- package/examples/hubot-start.ps1 +0 -12
- package/examples/hubot.service +0 -27
- package/script/bootstrap +0 -3
- package/script/release +0 -44
- package/script/server +0 -3
- package/script/smoke-test +0 -3
- package/script/test +0 -3
- package/test/adapter_test.js +0 -97
- package/test/brain_test.js +0 -336
- package/test/datastore_test.js +0 -154
- package/test/es2015_test.js +0 -199
- package/test/fixtures/MockAdapter.coffee +0 -10
- package/test/fixtures/MockAdapter.mjs +0 -43
- package/test/fixtures/TestScript.coffee +0 -9
- package/test/fixtures/TestScript.js +0 -13
- package/test/fixtures/mock-adapter.js +0 -35
- package/test/listener_test.js +0 -379
- package/test/message_test.js +0 -46
- package/test/middleware_test.js +0 -507
- package/test/robot_test.js +0 -1153
- package/test/shell_test.js +0 -73
- package/test/user_test.js +0 -29
package/examples/hubot-start.ps1
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
#Hubot PowerShell Start Script
|
|
2
|
-
#Invoke from the PowerShell prompt or start via automated tools
|
|
3
|
-
|
|
4
|
-
$HubotPath = "drive:\path\to\hubot"
|
|
5
|
-
$HubotAdapter = "Hubot adapter"
|
|
6
|
-
|
|
7
|
-
Write-Host "Starting Hubot Watcher"
|
|
8
|
-
While (1)
|
|
9
|
-
{
|
|
10
|
-
Write-Host "Starting Hubot"
|
|
11
|
-
Start-Process powershell -ArgumentList "$HubotPath\bin\hubot –adapter $HubotAdapter" -wait
|
|
12
|
-
}
|
package/examples/hubot.service
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
; Hubot systemd service unit file
|
|
2
|
-
; Place in e.g. `/etc/systemd/system/hubot.service`, then `systemctl daemon-reload` and `service hubot start`.
|
|
3
|
-
|
|
4
|
-
[Unit]
|
|
5
|
-
Description=Hubot
|
|
6
|
-
Requires=network.target
|
|
7
|
-
After=network.target
|
|
8
|
-
|
|
9
|
-
[Service]
|
|
10
|
-
Type=simple
|
|
11
|
-
WorkingDirectory=/path/to/hubot
|
|
12
|
-
User=change-to-hubot-user
|
|
13
|
-
|
|
14
|
-
Restart=always
|
|
15
|
-
RestartSec=10
|
|
16
|
-
|
|
17
|
-
; Configure Hubot environment variables, use quotes around vars with whitespace as shown below.
|
|
18
|
-
Environment="HUBOT_aaa=xxx"
|
|
19
|
-
Environment="HUBOT_bbb='yyy yyy'"
|
|
20
|
-
|
|
21
|
-
; Alternatively multiple environment variables can loaded from an external file
|
|
22
|
-
;EnvironmentFile=/etc/hubot-environment
|
|
23
|
-
|
|
24
|
-
ExecStart=/path/to/hubot/bin/hubot --adapter zzz
|
|
25
|
-
|
|
26
|
-
[Install]
|
|
27
|
-
WantedBy=multi-user.target
|
package/script/bootstrap
DELETED
package/script/release
DELETED
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Tag and push a release.
|
|
3
|
-
|
|
4
|
-
set -e
|
|
5
|
-
|
|
6
|
-
# Make sure we're in the project root.
|
|
7
|
-
|
|
8
|
-
cd $(dirname "$0")/..
|
|
9
|
-
|
|
10
|
-
# Make sure the darn thing works
|
|
11
|
-
|
|
12
|
-
npm update && script/smoke-test
|
|
13
|
-
|
|
14
|
-
# Make sure we're on the main branch.
|
|
15
|
-
|
|
16
|
-
(git branch | grep -q '* main') || {
|
|
17
|
-
echo "Only release from the main branch."
|
|
18
|
-
exit 1
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
# Figure out what version we're releasing.
|
|
22
|
-
|
|
23
|
-
tag=v`node -e 'console.log(require("./package.json").version)'`
|
|
24
|
-
|
|
25
|
-
# Ensure there's a line in the CHANGELOG
|
|
26
|
-
|
|
27
|
-
grep "$tag" CHANGELOG.md || {
|
|
28
|
-
echo "No entry for '$tag' found in the CHANGELOG."
|
|
29
|
-
exit 1
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
# Make sure we haven't released this version before.
|
|
33
|
-
|
|
34
|
-
git fetch -t origin
|
|
35
|
-
|
|
36
|
-
(git tag -l | grep -q "$tag") && {
|
|
37
|
-
echo "Whoops, there's already a '${tag}' tag."
|
|
38
|
-
exit 1
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
# Tag it and bag it.
|
|
42
|
-
|
|
43
|
-
npm publish && git tag "$tag" &&
|
|
44
|
-
git push origin main --tags
|
package/script/server
DELETED
package/script/smoke-test
DELETED
package/script/test
DELETED
package/test/adapter_test.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global describe, beforeEach, it */
|
|
4
|
-
|
|
5
|
-
const chai = require('chai')
|
|
6
|
-
const sinon = require('sinon')
|
|
7
|
-
chai.use(require('sinon-chai'))
|
|
8
|
-
|
|
9
|
-
const expect = chai.expect
|
|
10
|
-
|
|
11
|
-
const Adapter = require('../src/adapter')
|
|
12
|
-
|
|
13
|
-
describe('Adapter', function () {
|
|
14
|
-
beforeEach(function () {
|
|
15
|
-
this.robot = { receive: sinon.spy() }
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
describe('Public API', function () {
|
|
19
|
-
beforeEach(function () {
|
|
20
|
-
this.adapter = new Adapter(this.robot)
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
it('assigns robot', function () {
|
|
24
|
-
expect(this.adapter.robot).to.equal(this.robot)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
describe('send', function () {
|
|
28
|
-
it('is a function', function () {
|
|
29
|
-
expect(this.adapter.send).to.be.a('function')
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
it('does nothing', function () {
|
|
33
|
-
this.adapter.send({}, 'nothing')
|
|
34
|
-
})
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
describe('reply', function () {
|
|
38
|
-
it('is a function', function () {
|
|
39
|
-
expect(this.adapter.reply).to.be.a('function')
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
it('does nothing', function () {
|
|
43
|
-
this.adapter.reply({}, 'nothing')
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
describe('topic', function () {
|
|
48
|
-
it('is a function', function () {
|
|
49
|
-
expect(this.adapter.topic).to.be.a('function')
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('does nothing', function () {
|
|
53
|
-
this.adapter.topic({}, 'nothing')
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
describe('play', function () {
|
|
58
|
-
it('is a function', function () {
|
|
59
|
-
expect(this.adapter.play).to.be.a('function')
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('does nothing', function () {
|
|
63
|
-
this.adapter.play({}, 'nothing')
|
|
64
|
-
})
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
describe('run', function () {
|
|
68
|
-
it('is a function', function () {
|
|
69
|
-
expect(this.adapter.run).to.be.a('function')
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
it('does nothing', function () {
|
|
73
|
-
this.adapter.run()
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
describe('close', function () {
|
|
78
|
-
it('is a function', function () {
|
|
79
|
-
expect(this.adapter.close).to.be.a('function')
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
it('does nothing', function () {
|
|
83
|
-
this.adapter.close()
|
|
84
|
-
})
|
|
85
|
-
})
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
it('dispatches received messages to the robot', function () {
|
|
89
|
-
this.robot.receive = sinon.spy()
|
|
90
|
-
this.adapter = new Adapter(this.robot)
|
|
91
|
-
this.message = sinon.spy()
|
|
92
|
-
|
|
93
|
-
this.adapter.receive(this.message)
|
|
94
|
-
|
|
95
|
-
expect(this.robot.receive).to.have.been.calledWith(this.message)
|
|
96
|
-
})
|
|
97
|
-
})
|
package/test/brain_test.js
DELETED
|
@@ -1,336 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global describe, beforeEach, afterEach, it */
|
|
4
|
-
/* eslint-disable no-unused-expressions */
|
|
5
|
-
|
|
6
|
-
// Assertions and Stubbing
|
|
7
|
-
const chai = require('chai')
|
|
8
|
-
const sinon = require('sinon')
|
|
9
|
-
chai.use(require('sinon-chai'))
|
|
10
|
-
|
|
11
|
-
const expect = chai.expect
|
|
12
|
-
|
|
13
|
-
const isCircular = require('is-circular')
|
|
14
|
-
|
|
15
|
-
// Hubot classes
|
|
16
|
-
const Brain = require('../src/brain')
|
|
17
|
-
const User = require('../src/user')
|
|
18
|
-
|
|
19
|
-
describe('Brain', function () {
|
|
20
|
-
beforeEach(function () {
|
|
21
|
-
this.clock = sinon.useFakeTimers()
|
|
22
|
-
this.mockRobot = {
|
|
23
|
-
emit () {},
|
|
24
|
-
on () {}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// This *should* be callsArgAsync to match the 'on' API, but that makes
|
|
28
|
-
// the tests more complicated and seems irrelevant.
|
|
29
|
-
sinon.stub(this.mockRobot, 'on').withArgs('running').callsArg(1)
|
|
30
|
-
|
|
31
|
-
this.brain = new Brain(this.mockRobot)
|
|
32
|
-
|
|
33
|
-
this.user1 = this.brain.userForId('1', { name: 'Guy One' })
|
|
34
|
-
this.user2 = this.brain.userForId('2', { name: 'Guy One Two' })
|
|
35
|
-
this.user3 = this.brain.userForId('3', { name: 'Girl Three' })
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
afterEach(function () {
|
|
39
|
-
this.clock.restore()
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
describe('Unit Tests', function () {
|
|
43
|
-
describe('#mergeData', function () {
|
|
44
|
-
it('performs a proper merge with the new data taking precedent', function () {
|
|
45
|
-
this.brain.data = {
|
|
46
|
-
1: 'old',
|
|
47
|
-
2: 'old'
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this.brain.mergeData({ 2: 'new' })
|
|
51
|
-
|
|
52
|
-
expect(this.brain.data).to.deep.equal({
|
|
53
|
-
1: 'old',
|
|
54
|
-
2: 'new'
|
|
55
|
-
})
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
it('emits a loaded event with the new data', function () {
|
|
59
|
-
sinon.spy(this.brain, 'emit')
|
|
60
|
-
this.brain.mergeData({})
|
|
61
|
-
expect(this.brain.emit).to.have.been.calledWith('loaded', this.brain.data)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
it('coerces loaded data into User objects', function () {
|
|
65
|
-
this.brain.mergeData({ users: { 4: { name: 'new', id: '4' } } })
|
|
66
|
-
const user = this.brain.userForId('4')
|
|
67
|
-
expect(user.constructor.name).to.equal('User')
|
|
68
|
-
expect(user.id).to.equal('4')
|
|
69
|
-
expect(user.name).to.equal('new')
|
|
70
|
-
expect(isCircular(this.brain)).to.be.false
|
|
71
|
-
})
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
describe('#save', () => it('emits a save event', function () {
|
|
75
|
-
sinon.spy(this.brain, 'emit')
|
|
76
|
-
this.brain.save()
|
|
77
|
-
expect(this.brain.emit).to.have.been.calledWith('save', this.brain.data)
|
|
78
|
-
}))
|
|
79
|
-
|
|
80
|
-
describe('#resetSaveInterval', () => it('updates the auto-save interval', function () {
|
|
81
|
-
sinon.spy(this.brain, 'save')
|
|
82
|
-
// default is 5s
|
|
83
|
-
this.brain.resetSaveInterval(10)
|
|
84
|
-
// make sure autosave is on
|
|
85
|
-
this.brain.setAutoSave(true)
|
|
86
|
-
|
|
87
|
-
this.clock.tick(5000)
|
|
88
|
-
// old interval has passed
|
|
89
|
-
expect(this.brain.save).to.not.have.been.called
|
|
90
|
-
this.clock.tick(5000)
|
|
91
|
-
// new interval has passed
|
|
92
|
-
expect(this.brain.save).to.have.been.calledOnce
|
|
93
|
-
}))
|
|
94
|
-
|
|
95
|
-
describe('#close', function () {
|
|
96
|
-
it('saves', function () {
|
|
97
|
-
sinon.spy(this.brain, 'save')
|
|
98
|
-
this.brain.close()
|
|
99
|
-
expect(this.brain.save).to.have.been.calledOnce
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('emits a close event', function () {
|
|
103
|
-
sinon.spy(this.brain, 'emit')
|
|
104
|
-
this.brain.close()
|
|
105
|
-
expect(this.brain.emit).to.have.been.calledWith('close')
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
it('saves before emitting the close event', function () {
|
|
109
|
-
sinon.spy(this.brain, 'save')
|
|
110
|
-
sinon.spy(this.brain, 'emit').withArgs('close')
|
|
111
|
-
this.brain.close()
|
|
112
|
-
expect(this.brain.save).to.have.been.calledBefore(this.brain.emit)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
it('stops auto-saving', function () {
|
|
116
|
-
// make sure autosave is on
|
|
117
|
-
this.brain.setAutoSave(true)
|
|
118
|
-
this.brain.close()
|
|
119
|
-
|
|
120
|
-
// set up the spy after because 'close' calls 'save'
|
|
121
|
-
sinon.spy(this.brain, 'save')
|
|
122
|
-
|
|
123
|
-
this.clock.tick(2 * 5000)
|
|
124
|
-
expect(this.brain.save).to.not.have.been.called
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
describe('#get', function () {
|
|
129
|
-
it('returns the saved value', function () {
|
|
130
|
-
this.brain.data._private['test-key'] = 'value'
|
|
131
|
-
expect(this.brain.get('test-key')).to.equal('value')
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
it('returns null if object is not found', function () {
|
|
135
|
-
expect(this.brain.get('not a real key')).to.be.null
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
describe('#set', function () {
|
|
140
|
-
it('saves the value', function () {
|
|
141
|
-
this.brain.set('test-key', 'value')
|
|
142
|
-
expect(this.brain.data._private['test-key']).to.equal('value')
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('sets multiple keys at once if an object is provided', function () {
|
|
146
|
-
this.brain.data._private = {
|
|
147
|
-
key1: 'val1',
|
|
148
|
-
key2: 'val1'
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
this.brain.set({
|
|
152
|
-
key2: 'val2',
|
|
153
|
-
key3: 'val2'
|
|
154
|
-
})
|
|
155
|
-
|
|
156
|
-
expect(this.brain.data._private).to.deep.equal({
|
|
157
|
-
key1: 'val1',
|
|
158
|
-
key2: 'val2',
|
|
159
|
-
key3: 'val2'
|
|
160
|
-
})
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
// Unable to understand why this behavior is needed, but adding a test
|
|
164
|
-
// case to protect it
|
|
165
|
-
it('emits loaded', function () {
|
|
166
|
-
sinon.spy(this.brain, 'emit')
|
|
167
|
-
this.brain.set('test-key', 'value')
|
|
168
|
-
expect(this.brain.emit).to.have.been.calledWith('loaded', this.brain.data)
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
it('returns the brain', function () {
|
|
172
|
-
expect(this.brain.set('test-key', 'value')).to.equal(this.brain)
|
|
173
|
-
})
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
describe('#remove', () => it('removes the specified key', function () {
|
|
177
|
-
this.brain.data._private['test-key'] = 'value'
|
|
178
|
-
this.brain.remove('test-key')
|
|
179
|
-
expect(this.brain.data._private).to.not.include.keys('test-key')
|
|
180
|
-
}))
|
|
181
|
-
|
|
182
|
-
describe('#userForId', function () {
|
|
183
|
-
it('returns the user object', function () {
|
|
184
|
-
expect(this.brain.userForId(1)).to.equal(this.user1)
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
it('does an exact match', function () {
|
|
188
|
-
const user4 = this.brain.userForId('FOUR')
|
|
189
|
-
expect(this.brain.userForId('four')).to.not.equal(user4)
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
// Cannot understand why this behavior is needed, but adding a test case
|
|
193
|
-
// to protect it
|
|
194
|
-
it('recreates the user if the room option differs from the user object', function () {
|
|
195
|
-
expect(this.brain.userForId(1).room).to.be.undefined
|
|
196
|
-
|
|
197
|
-
// undefined -> having a room
|
|
198
|
-
const newUser1 = this.brain.userForId(1, { room: 'room1' })
|
|
199
|
-
expect(newUser1).to.not.equal(this.user1)
|
|
200
|
-
|
|
201
|
-
// changing the room
|
|
202
|
-
const newUser2 = this.brain.userForId(1, { room: 'room2' })
|
|
203
|
-
expect(newUser2).to.not.equal(newUser1)
|
|
204
|
-
})
|
|
205
|
-
|
|
206
|
-
describe('when there is no matching user ID', function () {
|
|
207
|
-
it('creates a new User', function () {
|
|
208
|
-
expect(this.brain.data.users).to.not.include.key('all-new-user')
|
|
209
|
-
const newUser = this.brain.userForId('all-new-user')
|
|
210
|
-
expect(newUser).to.be.instanceof(User)
|
|
211
|
-
expect(newUser.id).to.equal('all-new-user')
|
|
212
|
-
expect(this.brain.data.users).to.include.key('all-new-user')
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
it('passes the provided options to the new User', function () {
|
|
216
|
-
const newUser = this.brain.userForId('all-new-user', { name: 'All New User', prop: 'mine' })
|
|
217
|
-
expect(newUser.name).to.equal('All New User')
|
|
218
|
-
expect(newUser.prop).to.equal('mine')
|
|
219
|
-
})
|
|
220
|
-
})
|
|
221
|
-
})
|
|
222
|
-
|
|
223
|
-
describe('#userForName', function () {
|
|
224
|
-
it('returns the user with a matching name', function () {
|
|
225
|
-
expect(this.brain.userForName('Guy One')).to.equal(this.user1)
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
it('does a case-insensitive match', function () {
|
|
229
|
-
expect(this.brain.userForName('guy one')).to.equal(this.user1)
|
|
230
|
-
})
|
|
231
|
-
|
|
232
|
-
it('returns null if no user matches', function () {
|
|
233
|
-
expect(this.brain.userForName('not a real user')).to.be.null
|
|
234
|
-
})
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
describe('#usersForRawFuzzyName', function () {
|
|
238
|
-
it('does a case-insensitive match', function () {
|
|
239
|
-
expect(this.brain.usersForRawFuzzyName('guy')).to.have.members([this.user1, this.user2])
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('returns all matching users (prefix match) when there is not an exact match (case-insensitive)', function () {
|
|
243
|
-
expect(this.brain.usersForRawFuzzyName('Guy')).to.have.members([this.user1, this.user2])
|
|
244
|
-
})
|
|
245
|
-
|
|
246
|
-
it('returns all matching users (prefix match) when there is an exact match (case-insensitive)', function () {
|
|
247
|
-
// Matched case
|
|
248
|
-
expect(this.brain.usersForRawFuzzyName('Guy One')).to.deep.equal([this.user1, this.user2])
|
|
249
|
-
// Mismatched case
|
|
250
|
-
expect(this.brain.usersForRawFuzzyName('guy one')).to.deep.equal([this.user1, this.user2])
|
|
251
|
-
})
|
|
252
|
-
|
|
253
|
-
it('returns an empty array if no users match', function () {
|
|
254
|
-
const result = this.brain.usersForRawFuzzyName('not a real user')
|
|
255
|
-
expect(result).to.be.an('array')
|
|
256
|
-
expect(result).to.be.empty
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
describe('#usersForFuzzyName', function () {
|
|
261
|
-
it('does a case-insensitive match', function () {
|
|
262
|
-
expect(this.brain.usersForFuzzyName('guy')).to.have.members([this.user1, this.user2])
|
|
263
|
-
})
|
|
264
|
-
|
|
265
|
-
it('returns all matching users (prefix match) when there is not an exact match', function () {
|
|
266
|
-
expect(this.brain.usersForFuzzyName('Guy')).to.have.members([this.user1, this.user2])
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
it('returns just the user when there is an exact match (case-insensitive)', function () {
|
|
270
|
-
// Matched case
|
|
271
|
-
expect(this.brain.usersForFuzzyName('Guy One')).to.deep.equal([this.user1])
|
|
272
|
-
// Mismatched case
|
|
273
|
-
expect(this.brain.usersForFuzzyName('guy one')).to.deep.equal([this.user1])
|
|
274
|
-
})
|
|
275
|
-
|
|
276
|
-
it('returns an empty array if no users match', function () {
|
|
277
|
-
const result = this.brain.usersForFuzzyName('not a real user')
|
|
278
|
-
expect(result).to.be.an('array')
|
|
279
|
-
expect(result).to.be.empty
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
describe('Auto-Save', function () {
|
|
285
|
-
it('is on by default', function () {
|
|
286
|
-
expect(this.brain.autoSave).to.equal(true)
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
it('automatically saves every 5 seconds when turned on', function () {
|
|
290
|
-
sinon.spy(this.brain, 'save')
|
|
291
|
-
|
|
292
|
-
this.brain.setAutoSave(true)
|
|
293
|
-
|
|
294
|
-
this.clock.tick(5000)
|
|
295
|
-
expect(this.brain.save).to.have.been.called
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
it('does not auto-save when turned off', function () {
|
|
299
|
-
sinon.spy(this.brain, 'save')
|
|
300
|
-
|
|
301
|
-
this.brain.setAutoSave(false)
|
|
302
|
-
|
|
303
|
-
this.clock.tick(2 * 5000)
|
|
304
|
-
expect(this.brain.save).to.not.have.been.called
|
|
305
|
-
})
|
|
306
|
-
})
|
|
307
|
-
|
|
308
|
-
describe('User Searching', function () {
|
|
309
|
-
it('finds users by ID', function () {
|
|
310
|
-
expect(this.brain.userForId('1')).to.equal(this.user1)
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
it('finds users by exact name', function () {
|
|
314
|
-
expect(this.brain.userForName('Guy One')).to.equal(this.user1)
|
|
315
|
-
})
|
|
316
|
-
|
|
317
|
-
it('finds users by fuzzy name (prefix match)', function () {
|
|
318
|
-
const result = this.brain.usersForFuzzyName('Guy')
|
|
319
|
-
expect(result).to.have.members([this.user1, this.user2])
|
|
320
|
-
expect(result).to.not.have.members([this.user3])
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
it('returns User objects, not POJOs', function () {
|
|
324
|
-
expect(this.brain.userForId('1').constructor.name).to.equal('User')
|
|
325
|
-
for (const user of this.brain.usersForFuzzyName('Guy')) {
|
|
326
|
-
expect(user.constructor.name).to.equal('User')
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
for (const user of this.brain.usersForRawFuzzyName('Guy One')) {
|
|
330
|
-
expect(user.constructor.name).to.equal('User')
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
expect(isCircular(this.brain)).to.be.false
|
|
334
|
-
})
|
|
335
|
-
})
|
|
336
|
-
})
|
package/test/datastore_test.js
DELETED
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
/* global describe, beforeEach, it */
|
|
4
|
-
|
|
5
|
-
const chai = require('chai')
|
|
6
|
-
const sinon = require('sinon')
|
|
7
|
-
chai.use(require('sinon-chai'))
|
|
8
|
-
|
|
9
|
-
const expect = chai.expect
|
|
10
|
-
|
|
11
|
-
const Brain = require('../src/brain')
|
|
12
|
-
const InMemoryDataStore = require('../src/datastores/memory')
|
|
13
|
-
|
|
14
|
-
describe('Datastore', function () {
|
|
15
|
-
beforeEach(function () {
|
|
16
|
-
this.clock = sinon.useFakeTimers()
|
|
17
|
-
this.robot = {
|
|
18
|
-
emit () {},
|
|
19
|
-
on () {},
|
|
20
|
-
receive: sinon.spy()
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// This *should* be callsArgAsync to match the 'on' API, but that makes
|
|
24
|
-
// the tests more complicated and seems irrelevant.
|
|
25
|
-
sinon.stub(this.robot, 'on').withArgs('running').callsArg(1)
|
|
26
|
-
|
|
27
|
-
this.robot.brain = new Brain(this.robot)
|
|
28
|
-
this.robot.datastore = new InMemoryDataStore(this.robot)
|
|
29
|
-
this.robot.brain.userForId('1', { name: 'User One' })
|
|
30
|
-
this.robot.brain.userForId('2', { name: 'User Two' })
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
this.afterEach(function () {
|
|
34
|
-
this.clock.restore()
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
describe('global scope', function () {
|
|
38
|
-
it('returns undefined for values not in the datastore', function () {
|
|
39
|
-
return this.robot.datastore.get('blah').then(function (value) {
|
|
40
|
-
expect(value).to.be.an('undefined')
|
|
41
|
-
})
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
it('can store simple values', function () {
|
|
45
|
-
return this.robot.datastore.set('key', 'value').then(() => {
|
|
46
|
-
return this.robot.datastore.get('key').then((value) => {
|
|
47
|
-
expect(value).to.equal('value')
|
|
48
|
-
})
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
it('can store arbitrary JavaScript values', function () {
|
|
53
|
-
const object = {
|
|
54
|
-
name: 'test',
|
|
55
|
-
data: [1, 2, 3]
|
|
56
|
-
}
|
|
57
|
-
return this.robot.datastore.set('key', object).then(() => {
|
|
58
|
-
return this.robot.datastore.get('key').then((value) => {
|
|
59
|
-
expect(value.name).to.equal('test')
|
|
60
|
-
expect(value.data).to.deep.equal([1, 2, 3])
|
|
61
|
-
})
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('can dig inside objects for values', function () {
|
|
66
|
-
const object = {
|
|
67
|
-
a: 'one',
|
|
68
|
-
b: 'two'
|
|
69
|
-
}
|
|
70
|
-
return this.robot.datastore.set('key', object).then(() => {
|
|
71
|
-
return this.robot.datastore.getObject('key', 'a').then((value) => {
|
|
72
|
-
expect(value).to.equal('one')
|
|
73
|
-
})
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('can set individual keys inside objects', function () {
|
|
78
|
-
const object = {
|
|
79
|
-
a: 'one',
|
|
80
|
-
b: 'two'
|
|
81
|
-
}
|
|
82
|
-
return this.robot.datastore.set('object', object).then(() => {
|
|
83
|
-
return this.robot.datastore.setObject('object', 'c', 'three').then(() => {
|
|
84
|
-
return this.robot.datastore.get('object').then((value) => {
|
|
85
|
-
expect(value.a).to.equal('one')
|
|
86
|
-
expect(value.b).to.equal('two')
|
|
87
|
-
expect(value.c).to.equal('three')
|
|
88
|
-
})
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
it('creates an object from scratch when none exists', function () {
|
|
94
|
-
return this.robot.datastore.setObject('object', 'key', 'value').then(() => {
|
|
95
|
-
return this.robot.datastore.get('object').then((value) => {
|
|
96
|
-
const expected = { key: 'value' }
|
|
97
|
-
expect(value).to.deep.equal(expected)
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
it('can append to an existing array', function () {
|
|
103
|
-
return this.robot.datastore.set('array', [1, 2, 3]).then(() => {
|
|
104
|
-
return this.robot.datastore.setArray('array', 4).then(() => {
|
|
105
|
-
return this.robot.datastore.get('array').then((value) => {
|
|
106
|
-
expect(value).to.deep.equal([1, 2, 3, 4])
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
it('creates an array from scratch when none exists', function () {
|
|
113
|
-
return this.robot.datastore.setArray('array', 4).then(() => {
|
|
114
|
-
return this.robot.datastore.get('array').then((value) => {
|
|
115
|
-
expect(value).to.deep.equal([4])
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
describe('User scope', function () {
|
|
122
|
-
it('has access to the robot object', function () {
|
|
123
|
-
const user = this.robot.brain.userForId('1')
|
|
124
|
-
expect(user._getRobot()).to.equal(this.robot)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
it('can store user data which is separate from global data', function () {
|
|
128
|
-
const user = this.robot.brain.userForId('1')
|
|
129
|
-
return user.set('blah', 'blah').then(() => {
|
|
130
|
-
return user.get('blah').then((userBlah) => {
|
|
131
|
-
return this.robot.datastore.get('blah').then((datastoreBlah) => {
|
|
132
|
-
expect(userBlah).to.not.equal(datastoreBlah)
|
|
133
|
-
expect(userBlah).to.equal('blah')
|
|
134
|
-
expect(datastoreBlah).to.be.an('undefined')
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
})
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
it('stores user data separate per-user', function () {
|
|
141
|
-
const userOne = this.robot.brain.userForId('1')
|
|
142
|
-
const userTwo = this.robot.brain.userForId('2')
|
|
143
|
-
return userOne.set('blah', 'blah').then(() => {
|
|
144
|
-
return userOne.get('blah').then((valueOne) => {
|
|
145
|
-
return userTwo.get('blah').then((valueTwo) => {
|
|
146
|
-
expect(valueOne).to.not.equal(valueTwo)
|
|
147
|
-
expect(valueOne).to.equal('blah')
|
|
148
|
-
expect(valueTwo).to.be.an('undefined')
|
|
149
|
-
})
|
|
150
|
-
})
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
})
|
|
154
|
-
})
|