UNPKG

7.5 kBtext/coffeescriptView Raw
1{ok:expect, equal} = require 'assert'
2bond = require './lib/bond'
3
4describe 'bond', ->
5 math =
6 PI: Math.PI
7
8 zero: 0
9
10 abs: Math.abs
11
12 add: (a, b) ->
13 a + b
14
15 subtract: (a, b) ->
16 a - b
17
18 ComplexNumber: (@real, @imaginary) ->
19 this.toString = ->
20 "#{@real} + #{@imaginary}i"
21
22 NumberObject: (number) ->
23 return {number}
24
25 describe '#bond', ->
26 describe 'when called with 0 args', ->
27 it 'returns a simple spy', ->
28 spy = bond()
29 expect !spy.called
30
31 spy()
32 expect spy.called
33
34 it 'returns a spy that can have a return value', ->
35 spy = bond().return(3)
36 result = spy()
37 equal result, 3
38
39 it 'returns the bond api when called with 2 args', ->
40 api = bond(math, 'add')
41 expect api.to
42 expect api.return
43 expect api.through
44 expect api.restore
45
46 describe 'to', ->
47 describe 'can replace earlier bound values', ->
48 # these tests must be run in this specific order;
49 # do not bond math.zero in any other test
50 # because a failure here will cause test suite pollution
51 it 'setup', ->
52 bond(math, 'zero').to 3.14
53 bond(math, 'zero').to 12
54
55 equal math.zero, 12
56
57 it 'test', ->
58 # test that the old replacements have been cleared away
59 equal math.zero, 0
60
61 describe 'non function values', ->
62 it 'replaces values', ->
63 bond(math, 'PI').to 3.14
64
65 equal math.PI, 3.14
66
67 it 'returns to original value', ->
68 equal math.PI, 3.141592653589793
69
70 describe 'function values', ->
71 it 'creates a through spy', ->
72 bond(math, 'subtract').to (x, y) -> math.abs(x - y)
73
74 result = math.subtract(5, 10)
75
76 equal result, 5
77 equal math.subtract.called, 1
78 expect math.subtract.calledWith(5, 10)
79
80 it 'returns the original values', ->
81 result = math.subtract(5, 10)
82 equal result, -5
83
84 it 'explicitly returns objects from constructors', ->
85 bond(math, 'NumberObject').to -> {number: 7}
86
87 result = new math.NumberObject()
88 equal result.number, 7
89
90 it "doesn't return non-objects from constructors", ->
91 bond(math, 'NumberObject').to ->
92 @numero = 42
93 return 'I should not be returned'
94
95 result = new math.NumberObject()
96 equal result.numero, 42
97
98 describe 'return', ->
99 it 'replaces methods', ->
100 bond(math, 'add').return(888)
101
102 result = math.add()
103 equal result, 888
104
105 it 'returns to original value', ->
106 result = math.add(1, 2)
107 equal result, 3
108
109 describe 'asyncReturn', ->
110 module =
111 useNodeCallback: (value1, value2, callback) ->
112 throw new Error
113 dontUseNodeCallback: (value1, value2) ->
114 throw new Error
115
116 it 'calls the last argument with the provided arguments', (done) ->
117 ignoredValue1 = 5
118 ignoredValue2 = 4
119 stubValue1 = 3
120 stubValue2 = 2
121 bond(module, 'useNodeCallback').asyncReturn(null, stubValue1, stubValue2)
122 module.useNodeCallback ignoredValue1, ignoredValue2, (error, value1, value2) ->
123 expect !error
124 equal value1, stubValue1
125 equal value2, stubValue2
126 done()
127
128 it 'calls the callback with an error', (done) ->
129 ignoredValue = 5
130 stubError = 1
131 bond(module, 'useNodeCallback').asyncReturn(stubError)
132 module.useNodeCallback ignoredValue, (error) ->
133 equal error, stubError
134 done()
135
136 it 'throws an error if the last argument is not a function', ->
137 ignoredValue = 5
138 stubValue = 2
139 error = null
140 bond(module, 'dontUseNodeCallback').asyncReturn(stubValue)
141
142 try
143 module.useNodeCallback ignoredValue
144 catch err
145 error = err
146
147 expect error
148
149 it 'calls the callback on the next tick', (done) ->
150 ignoredValue = 5
151 stubValue = 3
152
153 module2 =
154 work: ->
155 done()
156 callbackSpy = bond(module2, 'work').through()
157
158 bond(module, 'useNodeCallback').asyncReturn(stubValue)
159 module.useNodeCallback ignoredValue, callbackSpy
160
161 # this will fail if the callback is called immediately
162 expect !callbackSpy.called
163
164 describe 'through', ->
165 it 'calls original method', ->
166 bond(math, 'add').through()
167
168 result = math.add(1, 2)
169 equal result, 3
170
171 it 'explicitly returns objects from constructors', ->
172 bond(math, 'NumberObject').through()
173
174 result = new math.NumberObject(42)
175 equal result.number, 42
176
177 describe 'restore', ->
178 it 'restores the original property', ->
179 original = math.add
180 bond(math,'add').through()
181 expect original != math.add
182 math.add.restore()
183 expect original == math.add
184
185 describe 'spies with `through` and `return`', ->
186 it 'returns the bond api mixed into the returned spy', ->
187 for method in ['through', 'return']
188 bond(math, 'add')[method]()
189 expect math.add.to
190 expect math.add.return
191 expect math.add.through
192 expect math.add.restore
193
194 it 'allows the spy to be replaced with new spies via the mixed-in api', ->
195 bond(math,'add').return(123)
196 result = math.add(1, 2)
197 equal result, 123
198
199 math.add.return(321)
200 result = math.add(1, 2)
201 equal result, 321
202
203 math.add.through()
204 result = math.add(1, 2)
205 equal result, 3
206
207 math.add.return(123)
208 result = math.add(1, 2)
209 equal result, 123
210
211 it 'records call count via called', ->
212 bond(math, 'add').return(777)
213 equal math.add.called, 0
214 math.add(1, 2)
215 equal math.add.called, 1
216 math.add(1, 2)
217 equal math.add.called, 2
218
219 it 'records called via called', ->
220 bond(math, 'add').through()
221 expect !math.add.called
222 math.add(1, 2)
223 expect math.add.called
224
225 describe 'calledWith', ->
226 it 'returns whether the method has been called', ->
227 bond(math, 'add').return(666)
228 expect !math.add.calledWith(11, 22)
229 math.add(11, 22)
230 expect math.add.calledWith(11, 22)
231
232 it 'returns true when the arguments are not from the most recent call', ->
233 bond(math, 'add').return(666)
234 math.add(11, 22)
235 math.add(33, 44)
236 expect math.add.calledWith(11, 22)
237
238 it 'matches objects with deep equality', ->
239 bond(math, 'add').return(666)
240 math.add(a: { b: 'c' })
241 expect math.add.calledWith(a: { b: 'c' })
242
243 it 'matches arrays with deep equality', ->
244 bond(math, 'add').return(666)
245 math.add([1, 2, 3])
246 expect math.add.calledWith([1, 2, 3])
247
248 it 'exposes argsForCall', ->
249 bond(math, 'add').return(555)
250
251 math.add(111, 222)
252 math.add(333, 444)
253
254 equal math.add.calledArgs[0][0], 111
255 equal math.add.calledArgs[0][1], 222
256 equal math.add.calledArgs[1][0], 333
257 equal math.add.calledArgs[1][1], 444
258
259 it 'returns the spy', ->
260 spy = bond(math, 'add').through()
261 math.add(1, 2)
262 expect spy.called
263
264 it 'through is constructor safe', ->
265 bond(math, 'ComplexNumber').through()
266 result = new math.ComplexNumber(3, 4)
267
268 equal result.real, 3
269 equal result.imaginary, 4
270 expect math.ComplexNumber.called
271
272 it 'return is constructor safe', ->
273 number =
274 real: 1
275 imaginary: 2
276 bond(math, 'ComplexNumber').return(number)
277 result = new math.ComplexNumber(3, 4)
278
279 equal result, number