oojspec 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,692 @@
1
+ ((typeof define === "function" && define.amd && function (m) {
2
+ define("referee", ["expect", "lodash", "samsam", "bane"], m);
3
+ }) || (typeof module === "object" && function (m) {
4
+ module.exports = m(
5
+ require("./expect"),
6
+ require("lodash"),
7
+ require("samsam"),
8
+ require("bane")
9
+ );
10
+ }) || function (m) {
11
+ this.referee = m(
12
+ this.expect,
13
+ this._,
14
+ this.samsam,
15
+ this.bane
16
+ );
17
+ })(function (expect, _, samsam, bane) {
18
+ "use strict";
19
+
20
+ var toString = Object.prototype.toString;
21
+ var slice = Array.prototype.slice;
22
+ var assert, refute, referee = bane.createEventEmitter();
23
+
24
+ referee.countAssertion = function countAssertion() {
25
+ if (typeof referee.count !== "number") { referee.count = 0; }
26
+ referee.count += 1;
27
+ };
28
+
29
+ function interpolate(string, prop, value) {
30
+ return string.replace(new RegExp("\\$\\{" + prop + "\\}", "g"), value);
31
+ }
32
+
33
+ // Interpolate positional arguments. Replaces occurences of ${<index>} in
34
+ // the string with the corresponding entry in values[<index>]
35
+ function interpolatePosArg(message, values) {
36
+ return _.reduce(values, function (msg, value, index) {
37
+ return interpolate(msg, index, referee.format(value));
38
+ }, message);
39
+ }
40
+
41
+ function interpolateProperties(message, properties) {
42
+ return _.reduce(_.keys(properties), function (str, name) {
43
+ var formattedValue = name == "customMessage" ? referee.prepareMessage(properties[name]) : referee.format(properties[name]);
44
+ return interpolate(str, name, formattedValue);
45
+ }, message || "");
46
+ }
47
+
48
+ // Internal helper. Used throughout to fail assertions if they receive
49
+ // too few arguments. The name is provided for a helpful error message.
50
+ function assertArgNum(name, args, num) {
51
+ if (args.length < num) {
52
+ referee.fail("[" + name + "] Expected to receive at least " +
53
+ num + " argument" + (num > 1 ? "s" : ""));
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+
59
+ // Internal helper. Not the most elegant of functions, but it takes
60
+ // care of all the nitty-gritty of assertion functions: counting,
61
+ // verifying parameter count, interpolating messages with actual
62
+ // values and so on.
63
+ function defineAssertion(type, name, func, minArgs, messageValues) {
64
+ referee[type][name] = function () {
65
+ referee.countAssertion();
66
+ var fullName = type + "." + name, failed = false;
67
+
68
+ if (!assertArgNum(fullName, arguments, minArgs || func.length)) {
69
+ return;
70
+ }
71
+
72
+ var args = slice.call(arguments, 0),
73
+ namedValues = {};
74
+
75
+ if (typeof messageValues === "function") {
76
+ var replacedValues = messageValues.apply(this, args);
77
+ if (typeof(replacedValues) === "object") {
78
+ namedValues = replacedValues;
79
+ } else {
80
+ args = replacedValues
81
+ }
82
+ }
83
+
84
+ var ctx = {
85
+ fail: function (msg) {
86
+ failed = true;
87
+ delete this.fail;
88
+ var message = referee[type][name][msg] || msg;
89
+ message = interpolatePosArg(message, args);
90
+ message = interpolateProperties(message, this);
91
+ message = interpolateProperties(message, namedValues);
92
+ referee.fail("[" + type + "." + name + "] " + message);
93
+ return false;
94
+ }
95
+ };
96
+
97
+ if (!func.apply(ctx, arguments) && !failed) {
98
+ // when a function returns false and hasn't already failed with a custom message,
99
+ // fail with default message
100
+ ctx.fail("message");
101
+ }
102
+
103
+ if (!failed) {
104
+ referee.emit.apply(referee, ["pass", fullName].concat(args));
105
+ }
106
+ };
107
+ }
108
+
109
+ referee.add = function (name, opt) {
110
+ var refuteArgs;
111
+
112
+ if (opt.refute) {
113
+ refuteArgs = opt.refute.length;
114
+ } else {
115
+ refuteArgs = opt.assert.length;
116
+ opt.refute = function () {
117
+ return !opt.assert.apply(this, arguments);
118
+ };
119
+ }
120
+
121
+ var values = opt.values;
122
+ defineAssertion("assert", name, opt.assert, opt.assert.length, values);
123
+ defineAssertion("refute", name, opt.refute, refuteArgs, values);
124
+
125
+ assert[name].message = opt.assertMessage;
126
+ refute[name].message = opt.refuteMessage;
127
+
128
+ if (opt.expectation) {
129
+ if (referee.expect && referee.expect.wrapAssertion) {
130
+ referee.expect.wrapAssertion(name, opt.expectation, referee);
131
+ } else {
132
+ assert[name].expectationName = opt.expectation;
133
+ refute[name].expectationName = opt.expectation;
134
+ }
135
+ }
136
+ };
137
+
138
+ assert = referee.assert = function assert(actual, message) {
139
+ referee.countAssertion();
140
+ if (!assertArgNum("assert", arguments, 1)) { return; }
141
+
142
+ if (!actual) {
143
+ var v = referee.format(actual);
144
+ referee.fail(message || "[assert] Expected " + v + " to be truthy");
145
+ } else {
146
+ referee.emit("pass", "assert", message || "", actual);
147
+ }
148
+ };
149
+
150
+ assert.toString = function () {
151
+ return "referee.assert()";
152
+ };
153
+
154
+ refute = referee.refute = function (actual, message) {
155
+ referee.countAssertion();
156
+ if (!assertArgNum("refute", arguments, 1)) { return; }
157
+
158
+ if (actual) {
159
+ var v = referee.format(actual);
160
+ referee.fail(message || "[refute] Expected " + v + " to be falsy");
161
+ } else {
162
+ referee.emit("pass", "refute", message || "", actual);
163
+ }
164
+ };
165
+
166
+ referee.count = 0;
167
+
168
+ referee.fail = function (message) {
169
+ var exception = new Error(message);
170
+ exception.name = "AssertionError";
171
+
172
+ try {
173
+ throw exception;
174
+ } catch (e) {
175
+ referee.emit("failure", e);
176
+ }
177
+
178
+ if (typeof referee.throwOnFailure !== "boolean" ||
179
+ referee.throwOnFailure) {
180
+ throw exception;
181
+ }
182
+ };
183
+
184
+ referee.format = function (object) { return String(object); };
185
+
186
+ referee.prepareMessage = function msg(message) {
187
+ if (!message) {
188
+ return "";
189
+ }
190
+ return message + (/[.:!?]$/.test(message) ? " " : ": ");
191
+ };
192
+
193
+ function actualAndExpectedMessageValues(actual, expected, message) {
194
+ return {
195
+ actual: actual,
196
+ expected: expected,
197
+ customMessage: message
198
+ };
199
+ }
200
+
201
+ function actualMessageValues(actual, message) {
202
+ return {
203
+ actual: actual,
204
+ customMessage: message
205
+ };
206
+ }
207
+
208
+ function actualAndTypeOfMessageValues(actual, message) {
209
+ return {
210
+ actual: actual,
211
+ actualType: typeof actual,
212
+ customMessage: message
213
+ };
214
+ }
215
+
216
+ referee.add("same", {
217
+ assert: function (actual, expected) {
218
+ return samsam.identical(actual, expected);
219
+ },
220
+ refute: function (actual, expected) {
221
+ return !samsam.identical(actual, expected);
222
+ },
223
+ assertMessage: "${customMessage}${actual} expected to be the same object as ${expected}",
224
+ refuteMessage: "${customMessage}${actual} expected not to be the same object as ${expected}",
225
+ expectation: "toBe",
226
+ values: actualAndExpectedMessageValues
227
+ });
228
+
229
+ // Extract/replace with separate module that does a more detailed
230
+ // visualization of multi-line strings
231
+ function multiLineStringDiff(actual, expected, message) {
232
+ if (actual === expected) { return true; }
233
+
234
+ var heading = assert.equals.multiLineStringHeading;
235
+ var failureText = interpolateProperties(heading, { customMessage: message });
236
+ var actualLines = actual.split("\n");
237
+ var expectedLines = expected.split("\n");
238
+ var lineCount = Math.max(expectedLines.length, actualLines.length);
239
+ var i, lines = [];
240
+
241
+ for (i = 0; i < lineCount; ++i) {
242
+ if (expectedLines[i] !== actualLines[i]) {
243
+ lines.push("line " + (i + 1) + ": " + (expectedLines[i] || "") +
244
+ "\nwas: " + (actualLines[i] || ""));
245
+ }
246
+ }
247
+
248
+ referee.fail("[assert.equals] " + failureText + lines.join("\n\n"));
249
+ return false;
250
+ }
251
+
252
+ referee.add("equals", {
253
+ // Uses arguments[2] because the function's .length is used to determine
254
+ // the minimum required number of arguments.
255
+ assert: function (actual, expected) {
256
+ if (typeof actual === "string" && typeof expected === "string" &&
257
+ (actual.indexOf("\n") >= 0 ||
258
+ expected.indexOf("\n") >= 0)) {
259
+ return multiLineStringDiff(actual, expected, arguments[2]);
260
+ }
261
+
262
+ return samsam.deepEqual(actual, expected);
263
+ },
264
+
265
+ refute: function (actual, expected) {
266
+ return !samsam.deepEqual(actual, expected);
267
+ },
268
+
269
+ assertMessage: "${customMessage}${actual} expected to be equal to ${expected}",
270
+ refuteMessage: "${customMessage}${actual} expected not to be equal to ${expected}",
271
+ expectation: "toEqual",
272
+ values: actualAndExpectedMessageValues
273
+ });
274
+
275
+ assert.equals.multiLineStringHeading = "${customMessage}Expected multi-line strings " +
276
+ "to be equal:\n";
277
+
278
+ referee.add("greater", {
279
+ assert: function (actual, expected) {
280
+ return actual > expected;
281
+ },
282
+
283
+ assertMessage: "${customMessage}Expected ${actual} to be greater than ${expected}",
284
+ refuteMessage: "${customMessage}Expected ${actual} to be less than or equal to ${expected}",
285
+ expectation: "toBeGreaterThan",
286
+ values: actualAndExpectedMessageValues
287
+ });
288
+
289
+ referee.add("less", {
290
+ assert: function (actual, expected) {
291
+ return actual < expected;
292
+ },
293
+
294
+ assertMessage: "${customMessage}Expected ${actual} to be less than ${expected}",
295
+ refuteMessage: "${customMessage}Expected ${actual} to be greater than or equal to ${expected}",
296
+ expectation: "toBeLessThan",
297
+ values: actualAndExpectedMessageValues
298
+ });
299
+
300
+ referee.add("defined", {
301
+ assert: function (actual) {
302
+ return typeof actual !== "undefined";
303
+ },
304
+ assertMessage: "${customMessage}Expected to be defined",
305
+ refuteMessage: "${customMessage}Expected ${actual} (${actualType}) not to be defined",
306
+ expectation: "toBeDefined",
307
+ values: actualAndTypeOfMessageValues
308
+ });
309
+
310
+ referee.add("isNull", {
311
+ assert: function (actual) {
312
+ return actual === null;
313
+ },
314
+ assertMessage: "${customMessage}Expected ${actual} to be null",
315
+ refuteMessage: "${customMessage}Expected not to be null",
316
+ expectation: "toBeNull",
317
+ values: actualMessageValues
318
+ });
319
+
320
+
321
+ referee.match = function (actual, matcher) {
322
+ try {
323
+ return samsam.match(actual, matcher);
324
+ } catch (e) {
325
+ throw new Error("Matcher (" + referee.format(matcher) +
326
+ ") was not a string, a number, a function, " +
327
+ "a boolean or an object");
328
+ }
329
+ };
330
+
331
+ referee.add("match", {
332
+ assert: function (actual, matcher) {
333
+ var passed;
334
+
335
+ try {
336
+ passed = referee.match(actual, matcher);
337
+ } catch (e) {
338
+ this.exceptionMessage = e.message;
339
+ return this.fail("exceptionMessage");
340
+ }
341
+
342
+ return passed;
343
+ },
344
+
345
+ refute: function (actual, matcher) {
346
+ var passed;
347
+
348
+ try {
349
+ passed = referee.match(actual, matcher);
350
+ } catch (e) {
351
+ this.exceptionMessage = e.message;
352
+ return this.fail("exceptionMessage");
353
+ }
354
+
355
+ return !passed;
356
+ },
357
+
358
+ assertMessage: "${customMessage}${actual} expected to match ${expected}",
359
+ refuteMessage: "${customMessage}${actual} expected not to match ${expected}",
360
+ expectation: "toMatch",
361
+ values: actualAndExpectedMessageValues
362
+ });
363
+
364
+ assert.match.exceptionMessage = refute.match.exceptionMessage = "${customMessage}${exceptionMessage}";
365
+
366
+ referee.add("isObject", {
367
+ assert: function (actual) {
368
+ return typeof actual === "object" && !!actual;
369
+ },
370
+ assertMessage: "${customMessage}${actual} (${actualType}) expected to be object and not null",
371
+ refuteMessage: "${customMessage}${actual} expected to be null or not an object",
372
+ expectation: "toBeObject",
373
+ values: actualAndTypeOfMessageValues
374
+ });
375
+
376
+ referee.add("isFunction", {
377
+ assert: function (actual) {
378
+ return typeof actual === "function";
379
+ },
380
+ assertMessage: "${customMessage}${actual} (${actualType}) expected to be function",
381
+ refuteMessage: "${customMessage}${actual} expected not to be function",
382
+ expectation: "toBeFunction",
383
+ values: function (actual, message) {
384
+ return {
385
+ actual: String(actual).replace("\n", ""),
386
+ actualType: typeof actual,
387
+ customMessage: message
388
+ };
389
+ }
390
+ });
391
+
392
+ referee.add("isTrue", {
393
+ assert: function (actual) {
394
+ return actual === true;
395
+ },
396
+ assertMessage: "${customMessage}Expected ${actual} to be true",
397
+ refuteMessage: "${customMessage}Expected ${actual} to not be true",
398
+ expectation: "toBeTrue",
399
+ values: actualMessageValues
400
+ });
401
+
402
+ referee.add("isFalse", {
403
+ assert: function (actual) {
404
+ return actual === false;
405
+ },
406
+ assertMessage: "${customMessage}Expected ${actual} to be false",
407
+ refuteMessage: "${customMessage}Expected ${actual} to not be false",
408
+ expectation: "toBeFalse",
409
+ values: actualMessageValues
410
+ });
411
+
412
+ referee.add("isString", {
413
+ assert: function (actual) {
414
+ return typeof actual === "string";
415
+ },
416
+ assertMessage: "${customMessage}Expected ${actual} (${actualType}) to be string",
417
+ refuteMessage: "${customMessage}Expected ${actual} not to be string",
418
+ expectation: "toBeString",
419
+ values: actualAndTypeOfMessageValues
420
+ });
421
+
422
+ referee.add("isBoolean", {
423
+ assert: function (actual) {
424
+ return typeof actual === "boolean";
425
+ },
426
+ assertMessage: "${customMessage}Expected ${actual} (${actualType}) to be boolean",
427
+ refuteMessage: "${customMessage}Expected ${actual} not to be boolean",
428
+ expectation: "toBeBoolean",
429
+ values: actualAndTypeOfMessageValues
430
+ });
431
+
432
+ referee.add("isNumber", {
433
+ assert: function (actual) {
434
+ return typeof actual === "number" && !isNaN(actual);
435
+ },
436
+ assertMessage: "${customMessage}Expected ${actual} (${actualType}) to be a non-NaN number",
437
+ refuteMessage: "${customMessage}Expected ${actual} to be NaN or a non-number value",
438
+ expectation: "toBeNumber",
439
+ values: actualAndTypeOfMessageValues
440
+ });
441
+
442
+ referee.add("isNaN", {
443
+ assert: function (actual) {
444
+ return typeof actual === "number" && isNaN(actual);
445
+ },
446
+ assertMessage: "${customMessage}Expected ${actual} to be NaN",
447
+ refuteMessage: "${customMessage}Expected not to be NaN",
448
+ expectation: "toBeNaN",
449
+ values: actualAndTypeOfMessageValues
450
+ });
451
+
452
+ referee.add("isArray", {
453
+ assert: function (actual) {
454
+ return toString.call(actual) === "[object Array]";
455
+ },
456
+ assertMessage: "${customMessage}Expected ${actual} to be array",
457
+ refuteMessage: "${customMessage}Expected ${actual} not to be array",
458
+ expectation: "toBeArray",
459
+ values: actualAndTypeOfMessageValues
460
+ });
461
+
462
+ function isArrayLike(object) {
463
+ return _.isArray(object) ||
464
+ (!!object && typeof object.length === "number" &&
465
+ typeof object.splice === "function") ||
466
+ _.isArguments(object);
467
+ }
468
+
469
+ referee.isArrayLike = isArrayLike;
470
+
471
+ referee.add("isArrayLike", {
472
+ assert: function (actual) {
473
+ return isArrayLike(actual);
474
+ },
475
+ assertMessage: "${customMessage}Expected ${actual} to be array like",
476
+ refuteMessage: "${customMessage}Expected ${actual} not to be array like",
477
+ expectation: "toBeArrayLike",
478
+ values: actualAndTypeOfMessageValues
479
+ });
480
+
481
+ function exactKeys(object, keys) {
482
+ var keyMap = {};
483
+ var keyCnt = 0;
484
+ for (var i = 0; i < keys.length; i++) {
485
+ keyMap[keys[i]] = true;
486
+ keyCnt += 1;
487
+ }
488
+ for (var key in object) {
489
+ if (object.hasOwnProperty(key)) {
490
+ if (! keyMap[key]) {
491
+ return false;
492
+ }
493
+ keyCnt -= 1;
494
+ }
495
+ }
496
+ return keyCnt === 0;
497
+ }
498
+
499
+ referee.add("keys", {
500
+ assert: function (actual, keys) {
501
+ return exactKeys(actual, keys);
502
+ },
503
+ assertMessage: "${customMessage}Expected ${actualObject} to have exact keys ${keys}",
504
+ refuteMessage: "${customMessage}Expected not to have exact keys ${keys}",
505
+ expectation: "toHaveKeys",
506
+ values: function (actual, keys, message) {
507
+ return {
508
+ actualObject: actual,
509
+ keys: keys,
510
+ customMessage: message
511
+ }
512
+ }
513
+ });
514
+
515
+ function captureException(callback) {
516
+ try { callback(); } catch (e) { return e; }
517
+ return null;
518
+ }
519
+
520
+ referee.captureException = captureException;
521
+
522
+ referee.add("exception", {
523
+ assert: function (callback) {
524
+ var matcher = arguments[1];
525
+ var customMessage = arguments[2];
526
+
527
+ if (typeof matcher === "string") {
528
+ customMessage = matcher;
529
+ matcher = undefined;
530
+ }
531
+
532
+ this.expected = matcher;
533
+ this.customMessage = customMessage;
534
+
535
+ var err = captureException(callback);
536
+
537
+ if (err) {
538
+ this.actualExceptionType = err.name;
539
+ this.actualExceptionMessage = err.message;
540
+ this.actualExceptionStack = err.stack;
541
+ }
542
+
543
+ if (!err) {
544
+ if (typeof matcher === "object") {
545
+ return this.fail("typeNoExceptionMessage");
546
+ } else {
547
+ return this.fail("message");
548
+ }
549
+ }
550
+
551
+ if (typeof matcher === "object" && !referee.match(err, matcher)) {
552
+ return this.fail("typeFailMessage");
553
+ }
554
+
555
+ if (typeof matcher === "function" && matcher(err) !== true) {
556
+ return this.fail("matchFailMessage");
557
+ }
558
+
559
+ return true;
560
+ },
561
+
562
+ refute: function (callback) {
563
+ var err = captureException(callback);
564
+
565
+ if (err) {
566
+ this.customMessage = arguments[1];
567
+ this.actualExceptionType = err.name;
568
+ this.actualExceptionMessage = err.message;
569
+ return false;
570
+ }
571
+
572
+ return true;
573
+ },
574
+
575
+ expectation: "toThrow",
576
+ assertMessage: "${customMessage}Expected exception",
577
+ refuteMessage: "${customMessage}Expected not to throw but threw ${actualExceptionType} (${actualExceptionMessage})"
578
+ });
579
+
580
+ assert.exception.typeNoExceptionMessage = "${customMessage}Expected ${expected} but no exception was thrown";
581
+ assert.exception.typeFailMessage = "${customMessage}Expected ${expected} but threw ${actualExceptionType} (${actualExceptionMessage})\n${actualExceptionStack}";
582
+ assert.exception.matchFailMessage = "${customMessage}Expected thrown ${actualExceptionType} (${actualExceptionMessage}) to pass matcher function";
583
+
584
+
585
+ referee.add("near", {
586
+ assert: function (actual, expected, delta) {
587
+ return Math.abs(actual - expected) <= delta;
588
+ },
589
+ assertMessage: "${customMessage}Expected ${actual} to be equal to ${expected} +/- ${delta}",
590
+ refuteMessage: "${customMessage}Expected ${actual} not to be equal to ${expected} +/- ${delta}",
591
+ expectation: "toBeNear",
592
+ values: function (actual, expected, delta, message) {
593
+ return {
594
+ actual: actual,
595
+ expected: expected,
596
+ delta: delta,
597
+ customMessage: message
598
+ };
599
+ }
600
+ });
601
+
602
+ referee.add("hasPrototype", {
603
+ assert: function (actual, protoObj) {
604
+ return protoObj.isPrototypeOf(actual);
605
+ },
606
+ assertMessage: "${customMessage}Expected ${actual} to have ${expected} on its prototype chain",
607
+ refuteMessage: "${customMessage}Expected ${actual} not to have ${expected} on its " +
608
+ "prototype chain",
609
+ expectation: "toHavePrototype",
610
+ values: actualAndExpectedMessageValues
611
+ });
612
+
613
+ referee.add("contains", {
614
+ assert: function (haystack, needle) {
615
+ return _.include(haystack, needle);
616
+ },
617
+ assertMessage: "${customMessage}Expected [${actual}] to contain ${expected}",
618
+ refuteMessage: "${customMessage}Expected [${actual}] not to contain ${expected}",
619
+ expectation: "toContain",
620
+ values: actualAndExpectedMessageValues
621
+ });
622
+
623
+ referee.add("tagName", {
624
+ assert: function (element, tagName) {
625
+ // Uses arguments[2] because the function's .length is used to
626
+ // determine the minimum required number of arguments.
627
+ if (!element.tagName) {
628
+ return this.fail("noTagNameMessage");
629
+ }
630
+
631
+ return tagName.toLowerCase &&
632
+ tagName.toLowerCase() === element.tagName.toLowerCase();
633
+ },
634
+ assertMessage: "${customMessage}Expected tagName to be ${expected} but was ${actual}",
635
+ refuteMessage: "${customMessage}Expected tagName not to be ${actual}",
636
+ expectation: "toHaveTagName",
637
+ values: function (element, tagName, message) {
638
+ return {
639
+ actualElement: element,
640
+ actual: element.tagName,
641
+ expected: tagName,
642
+ customMessage: message
643
+ };
644
+ }
645
+ });
646
+
647
+ assert.tagName.noTagNameMessage = "${customMessage}Expected ${actualElement} to have tagName " +
648
+ "property";
649
+ refute.tagName.noTagNameMessage = "${customMessage}Expected ${actualElement} to have tagName " +
650
+ "property";
651
+
652
+ referee.add("className", {
653
+ assert: function (element, name) {
654
+ if (typeof element.className === "undefined") {
655
+ return this.fail("noClassNameMessage");
656
+ }
657
+
658
+ var expected = typeof name === "string" ? name.split(" ") : name;
659
+ var actual = element.className.split(" ");
660
+ var i, l;
661
+ for (i = 0, l = expected.length; i < l; i++) {
662
+ if (!_.include(actual, expected[i])) { return false; }
663
+ }
664
+
665
+ return true;
666
+ },
667
+ assertMessage: "${customMessage}Expected object's className to include ${expected} " +
668
+ "but was ${actual}",
669
+ refuteMessage: "${customMessage}Expected object's className not to include ${expected}",
670
+ expectation: "toHaveClassName",
671
+ values: function (element, className, message) {
672
+ return {
673
+ actualElement: element,
674
+ actual: element.className,
675
+ expected: className,
676
+ customMessage: message
677
+ };
678
+ }
679
+ });
680
+
681
+ assert.className.noClassNameMessage = "${customMessage}Expected object to have " +
682
+ "className property";
683
+ refute.className.noClassNameMessage = "${customMessage}Expected object to have " +
684
+ "className property";
685
+
686
+ referee.expect = function () {
687
+ expect.init(referee);
688
+ return expect.apply(referee, arguments);
689
+ };
690
+
691
+ return referee;
692
+ });