1 | {ok:expect, equal} = require 'assert'
|
2 | bond = require './lib/bond'
|
3 |
|
4 | describe '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 |
|
49 |
|
50 |
|
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 |
|
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 |
|
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
|