UNPKG

11.7 kBJavaScriptView Raw
1"use strict";
2
3var slice = require("@sinonjs/commons").prototypes.array.slice;
4var calledInOrder = require("@sinonjs/commons").calledInOrder;
5var orderByFirstCall = require("@sinonjs/commons").orderByFirstCall;
6var referee = require("@sinonjs/referee");
7var formatio = require("@sinonjs/formatio");
8var sinon = require("sinon");
9
10var timesInWords = [null, "once", "twice", "thrice"];
11var push = Array.prototype.push;
12
13function callCount(fake) {
14 var count = fake.callCount;
15 return timesInWords[count] || (count || 0) + " times";
16}
17
18function callsToString(fake) {
19 if (typeof fake.getCalls !== "function") {
20 return "";
21 }
22
23 var calls = fake.getCalls();
24 if (calls.length === 0) {
25 return "";
26 }
27
28 return (
29 "\n" +
30 calls
31 .map(function(call) {
32 return " " + call.toString();
33 })
34 .join("\n")
35 );
36}
37
38sinon.expectation.pass = function(assertion) {
39 referee.emit("pass", assertion);
40};
41
42sinon.expectation.fail = function(message) {
43 referee.fail(message);
44};
45
46// Lazy bind the format method to referee's. This way, Sinon will
47// always format objects like referee does, even if referee is
48// configured after referee-sinon is loaded
49var formatter = formatio.configure({
50 quoteStrings: false,
51 limitChildrenCount: 250
52});
53
54function format() {
55 return formatter.ascii.apply(formatter, arguments);
56}
57
58referee.setFormatter(format);
59sinon.setFormatter(format);
60
61function verifyFakes() {
62 var method, isNot, i, l;
63
64 for (i = 0, l = arguments.length; i < l; ++i) {
65 method = arguments[i];
66 isNot = (method || "fake") + " is not ";
67
68 if (!method) {
69 this.fail(isNot + "a spy");
70 }
71 if (typeof method.calledWith !== "function") {
72 this.fail(isNot + "stubbed");
73 }
74 }
75
76 return true;
77}
78
79referee.add("callCount", {
80 assert: function(spy, count) {
81 verifyFakes.call(this, spy);
82 return spy.callCount === count;
83 },
84 assertMessage:
85 "Expected ${spyObj} to be called exactly ${expectedTimes} times, but was called ${actualTimes}",
86 refuteMessage:
87 "Expected ${spyObj} to not be called exactly ${expectedTimes} times",
88 expectation: "toHaveCallCount",
89 values: function(spyObj, count) {
90 return {
91 spyObj: spyObj,
92 actualTimes: callCount(spyObj),
93 expectedTimes: count
94 };
95 }
96});
97
98referee.add("called", {
99 assert: function(spy) {
100 verifyFakes.call(this, spy);
101 return spy.called;
102 },
103 assertMessage:
104 "Expected ${spyObj} to be called at least once but was never called",
105 refuteMessage:
106 "Expected ${spyObj} to not be called but was called ${times}${calls}",
107 expectation: "toHaveBeenCalled",
108 values: function(spyObj) {
109 return {
110 spyObj: spyObj,
111 times: callCount(spyObj),
112 calls: callsToString(spyObj)
113 };
114 }
115});
116
117referee.add("calledWithNew", {
118 assert: function(spy) {
119 verifyFakes.call(this, spy);
120 return spy.calledWithNew();
121 },
122 assertMessage:
123 "Expected ${spyObj} to be called with 'new' at least once but was never called with 'new'",
124 refuteMessage: "Expected ${spyObj} to not be called with 'new'",
125 expectation: "toHaveBeenCalledWithNew",
126 values: function(spyObj) {
127 return {
128 spyObj: spyObj
129 };
130 }
131});
132
133referee.add("alwaysCalledWithNew", {
134 assert: function(spy) {
135 verifyFakes.call(this, spy);
136 return spy.alwaysCalledWithNew();
137 },
138 assertMessage: "Expected ${spyObj} to always be called with 'new'",
139 refuteMessage: "Expected ${spyObj} to not always be called with 'new'",
140 expectation: "toAlwaysHaveBeenCalledWithNew",
141 values: function(spyObj) {
142 return {
143 spyObj: spyObj
144 };
145 }
146});
147
148referee.add("callOrder", {
149 assert: function(spy) {
150 var type = Object.prototype.toString.call(spy);
151 var isArray = type === "[object Array]";
152 var args = isArray ? spy : arguments;
153 verifyFakes.apply(this, args);
154 if (calledInOrder(args)) {
155 return true;
156 }
157
158 this.expected = [].join.call(args, ", ");
159 this.actual = orderByFirstCall(slice(args)).join(", ");
160 return false;
161 },
162
163 assertMessage:
164 "Expected ${expected} to be called in order but were called as ${actual}",
165 refuteMessage: "Expected ${expected} not to be called in order"
166});
167
168function addCallCountAssertion(count) {
169 referee.add("called" + count, {
170 assert: function(spy) {
171 verifyFakes.call(this, spy);
172 return spy["called" + count];
173 },
174 assertMessage:
175 "Expected ${spyObj} to be called ${expectedTimes} but was called ${times}${calls}",
176 refuteMessage:
177 "Expected ${spyObj} to not be called exactly ${expectedTimes}${calls}",
178 expectation: "toHaveBeenCalled" + count,
179 values: function(spyObj) {
180 return {
181 spyObj: spyObj,
182 expectedTimes: count.toLowerCase(),
183 times: callCount(spyObj),
184 calls: callsToString(spyObj)
185 };
186 }
187 });
188}
189
190addCallCountAssertion("Once");
191addCallCountAssertion("Twice");
192addCallCountAssertion("Thrice");
193
194function valuesWithThis(spyObj, expectedThis) {
195 return {
196 spyObj: spyObj,
197 expectedThis: expectedThis,
198 actualThis: spyObj.printf ? spyObj.printf("%t") : ""
199 };
200}
201
202referee.add("calledOn", {
203 assert: function(spy, thisObj) {
204 verifyFakes.call(this, spy);
205 return spy.calledOn(thisObj);
206 },
207 assertMessage:
208 "Expected ${spyObj} to be called with ${expectedThis} as this but was called on ${actualThis}",
209 refuteMessage:
210 "Expected ${spyObj} not to be called with ${expectedThis} as this",
211 expectation: "toHaveBeenCalledOn",
212 values: valuesWithThis
213});
214
215referee.add("alwaysCalledOn", {
216 assert: function(spy, thisObj) {
217 verifyFakes.call(this, spy);
218 return spy.alwaysCalledOn(thisObj);
219 },
220 assertMessage:
221 "Expected ${spyObj} to always be called with ${expectedThis} as this but was called on ${actualThis}",
222 refuteMessage:
223 "Expected ${spyObj} not to always be called with ${expectedThis} as this",
224 expectation: "toHaveAlwaysBeenCalledOn",
225 values: valuesWithThis
226});
227
228function formattedArgs(args, i) {
229 var index = i;
230 var l, result;
231
232 for (l = args.length, result = []; index < l; ++index) {
233 push.call(result, format(args[index]));
234 }
235 return result.join(", ");
236}
237
238function spyAndCalls(spyObj) {
239 var expected = formattedArgs(arguments, 1);
240 var actual = spyObj.printf ? spyObj.printf("%C") : "";
241 return {
242 spyObj: spyObj,
243 actual: actual,
244 expected: expected
245 };
246}
247
248referee.add("calledWith", {
249 assert: function(spy) {
250 verifyFakes.call(this, spy);
251 return spy.calledWith.apply(spy, slice(arguments, 1));
252 },
253 assertMessage:
254 "Expected ${spyObj} to be called with arguments ${expected}${actual}",
255 refuteMessage:
256 "Expected ${spyObj} not to be called with arguments ${expected}${actual}",
257 expectation: "toHaveBeenCalledWith",
258 values: spyAndCalls
259});
260
261referee.add("alwaysCalledWith", {
262 assert: function(spy) {
263 verifyFakes.call(this, spy);
264 return spy.alwaysCalledWith.apply(spy, slice(arguments, 1));
265 },
266 assertMessage:
267 "Expected ${spyObj} to always be called with arguments ${expected}${actual}",
268 refuteMessage:
269 "Expected ${spyObj} not to always be called with arguments ${expected}${actual}",
270 expectation: "toHaveAlwaysBeenCalledWith",
271 values: spyAndCalls
272});
273
274referee.add("calledOnceWith", {
275 assert: function(spy) {
276 verifyFakes.call(this, spy);
277 return spy.calledOnce && spy.calledWith.apply(spy, slice(arguments, 1));
278 },
279 assertMessage:
280 "Expected ${spyObj} to be called once with arguments ${expected}${actual}",
281 refuteMessage:
282 "Expected ${spyObj} not to be called once with arguments ${expected}${actual}",
283 expectation: "toHaveBeenCalledOnceWith",
284 values: spyAndCalls
285});
286
287referee.add("calledWithExactly", {
288 assert: function(spy) {
289 verifyFakes.call(this, spy);
290 return spy.calledWithExactly.apply(spy, slice(arguments, 1));
291 },
292 assertMessage:
293 "Expected ${spyObj} to be called with exact arguments ${expected}${actual}",
294 refuteMessage:
295 "Expected ${spyObj} not to be called with exact arguments ${expected}${actual}",
296 expectation: "toHaveBeenCalledWithExactly",
297 values: spyAndCalls
298});
299
300referee.add("alwaysCalledWithExactly", {
301 assert: function(spy) {
302 verifyFakes.call(this, spy);
303 return spy.alwaysCalledWithExactly.apply(spy, slice(arguments, 1));
304 },
305 assertMessage:
306 "Expected ${spyObj} to always be called with exact arguments ${expected}${actual}",
307 refuteMessage:
308 "Expected ${spyObj} not to always be called with exact arguments ${expected}${actual}",
309 expectation: "toHaveAlwaysBeenCalledWithExactly",
310 values: spyAndCalls
311});
312
313referee.add("calledOnceWithExactly", {
314 assert: function(spy) {
315 verifyFakes.call(this, spy);
316 return spy.calledOnceWithExactly.apply(spy, slice(arguments, 1));
317 },
318 assertMessage:
319 "Expected ${spyObj} to be called once with exact arguments ${expected}${actual}",
320 refuteMessage:
321 "Expected ${spyObj} not to be once called with exact arguments ${expected}${actual}",
322 expectation: "toHaveBeenCalledOnceWithExactly",
323 values: spyAndCalls
324});
325
326referee.add("calledWithMatch", {
327 assert: function(spy) {
328 verifyFakes.call(this, spy);
329 return spy.calledWithMatch.apply(spy, slice(arguments, 1));
330 },
331 assertMessage:
332 "Expected ${spyObj} to be called with matching arguments ${expected}${actual}",
333 refuteMessage:
334 "Expected ${spyObj} not to be called with matching arguments ${expected}${actual}",
335 expectation: "toHaveBeenCalledWithMatch",
336 values: spyAndCalls
337});
338
339referee.add("alwaysCalledWithMatch", {
340 assert: function(spy) {
341 verifyFakes.call(this, spy);
342 return spy.alwaysCalledWithMatch.apply(spy, slice(arguments, 1));
343 },
344 assertMessage:
345 "Expected ${spyObj} to always be called with matching arguments ${expected}${actual}",
346 refuteMessage:
347 "Expected ${spyObj} not to always be called with matching arguments ${expected}${actual}",
348 expectation: "toHaveAlwaysBeenCalledWithMatch",
349 values: spyAndCalls
350});
351
352function spyAndException(spyObj, exception) {
353 return {
354 spyObj: spyObj,
355 actual: spyObj.printf ? spyObj.printf("%C") : "",
356 exception: exception // note: not actually used
357 };
358}
359
360referee.add("threw", {
361 assert: function(spy) {
362 verifyFakes.call(this, spy);
363 return spy.threw(arguments[1]);
364 },
365 assertMessage: "Expected ${spyObj} to throw an exception${actual}",
366 refuteMessage: "Expected ${spyObj} not to throw an exception${actual}",
367 expectation: "toHaveThrown",
368 values: spyAndException
369});
370
371referee.add("alwaysThrew", {
372 assert: function(spy) {
373 verifyFakes.call(this, spy);
374 return spy.alwaysThrew(arguments[1]);
375 },
376 assertMessage: "Expected ${spyObj} to always throw an exception${actual}",
377 refuteMessage:
378 "Expected ${spyObj} not to always throw an exception${actual}",
379 expectation: "toAlwaysHaveThrown",
380 values: spyAndException
381});
382
383referee.sinon = sinon;
384
385module.exports = referee;