Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80629 views
1
var isCommonJS = typeof window == "undefined" && typeof exports == "object";
2
3
/**
4
* Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
5
*
6
* @namespace
7
*/
8
var jasmine = {};
9
if (isCommonJS) exports.jasmine = jasmine;
10
/**
11
* @private
12
*/
13
jasmine.unimplementedMethod_ = function() {
14
throw new Error("unimplemented method");
15
};
16
17
/**
18
* Use <code>jasmine.undefined</code> instead of <code>undefined</code>, since <code>undefined</code> is just
19
* a plain old variable and may be redefined by somebody else.
20
*
21
* @private
22
*/
23
jasmine.undefined = jasmine.___undefined___;
24
25
/**
26
* Show diagnostic messages in the console if set to true
27
*
28
*/
29
jasmine.VERBOSE = false;
30
31
/**
32
* Default interval in milliseconds for event loop yields (e.g. to allow network activity or to refresh the screen with the HTML-based runner). Small values here may result in slow test running. Zero means no updates until all tests have completed.
33
*
34
*/
35
jasmine.DEFAULT_UPDATE_INTERVAL = 250;
36
37
/**
38
* Maximum levels of nesting that will be included when an object is pretty-printed
39
*/
40
jasmine.MAX_PRETTY_PRINT_DEPTH = 40;
41
42
/**
43
* Default timeout interval in milliseconds for waitsFor() blocks.
44
*/
45
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
46
47
/**
48
* By default exceptions thrown in the context of a test are caught by jasmine so that it can run the remaining tests in the suite.
49
* Set to false to let the exception bubble up in the browser.
50
*
51
*/
52
jasmine.CATCH_EXCEPTIONS = true;
53
54
jasmine.getGlobal = function() {
55
function getGlobal() {
56
return this;
57
}
58
59
return getGlobal();
60
};
61
62
/**
63
* Allows for bound functions to be compared. Internal use only.
64
*
65
* @ignore
66
* @private
67
* @param base {Object} bound 'this' for the function
68
* @param name {Function} function to find
69
*/
70
jasmine.bindOriginal_ = function(base, name) {
71
var original = base[name];
72
if (original.apply) {
73
return function() {
74
return original.apply(base, arguments);
75
};
76
} else {
77
// IE support
78
return jasmine.getGlobal()[name];
79
}
80
};
81
82
jasmine.setTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'setTimeout');
83
jasmine.clearTimeout = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearTimeout');
84
jasmine.setInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'setInterval');
85
jasmine.clearInterval = jasmine.bindOriginal_(jasmine.getGlobal(), 'clearInterval');
86
87
jasmine.MessageResult = function(values) {
88
this.type = 'log';
89
this.values = values;
90
this.trace = new Error(); // todo: test better
91
};
92
93
jasmine.MessageResult.prototype.toString = function() {
94
var text = "";
95
for (var i = 0; i < this.values.length; i++) {
96
if (i > 0) text += " ";
97
if (jasmine.isString_(this.values[i])) {
98
text += this.values[i];
99
} else {
100
text += jasmine.pp(this.values[i]);
101
}
102
}
103
return text;
104
};
105
106
jasmine.ExpectationResult = function(params) {
107
this.type = 'expect';
108
this.matcherName = params.matcherName;
109
this.passed_ = params.passed;
110
this.expected = params.expected;
111
this.actual = params.actual;
112
this.message = this.passed_ ? 'Passed.' : params.message;
113
this.isNot = params.isNot;
114
115
var trace = (params.trace || new Error(this.message));
116
this.trace = this.passed_ ? '' : trace;
117
};
118
119
jasmine.ExpectationResult.prototype.toString = function () {
120
return this.message;
121
};
122
123
jasmine.ExpectationResult.prototype.passed = function () {
124
return this.passed_;
125
};
126
127
/**
128
* Getter for the Jasmine environment. Ensures one gets created
129
*/
130
jasmine.getEnv = function() {
131
var env = jasmine.currentEnv_ = jasmine.currentEnv_ || new jasmine.Env();
132
return env;
133
};
134
135
/**
136
* @ignore
137
* @private
138
* @param value
139
* @returns {Boolean}
140
*/
141
jasmine.isArray_ = function(value) {
142
return jasmine.isA_("Array", value);
143
};
144
145
/**
146
* @ignore
147
* @private
148
* @param value
149
* @returns {Boolean}
150
*/
151
jasmine.isString_ = function(value) {
152
return jasmine.isA_("String", value);
153
};
154
155
/**
156
* @ignore
157
* @private
158
* @param value
159
* @returns {Boolean}
160
*/
161
jasmine.isNumber_ = function(value) {
162
return jasmine.isA_("Number", value);
163
};
164
165
/**
166
* @ignore
167
* @private
168
* @param {String} typeName
169
* @param value
170
* @returns {Boolean}
171
*/
172
jasmine.isA_ = function(typeName, value) {
173
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
174
};
175
176
/**
177
* Pretty printer for expecations. Takes any object and turns it into a human-readable string.
178
*
179
* @param value {Object} an object to be outputted
180
* @returns {String}
181
*/
182
jasmine.pp = function(value) {
183
var stringPrettyPrinter = new jasmine.StringPrettyPrinter();
184
stringPrettyPrinter.format(value);
185
return stringPrettyPrinter.string;
186
};
187
188
/**
189
* Returns true if the object is a DOM Node.
190
*
191
* @param {Object} obj object to check
192
* @returns {Boolean}
193
*/
194
jasmine.isDomNode = function(obj) {
195
return obj.nodeType > 0;
196
};
197
198
/**
199
* Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
200
*
201
* @example
202
* // don't care about which function is passed in, as long as it's a function
203
* expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
204
*
205
* @param {Class} clazz
206
* @returns matchable object of the type clazz
207
*/
208
jasmine.any = function(clazz) {
209
return new jasmine.Matchers.Any(clazz);
210
};
211
212
/**
213
* Returns a matchable subset of a JSON object. For use in expectations when you don't care about all of the
214
* attributes on the object.
215
*
216
* @example
217
* // don't care about any other attributes than foo.
218
* expect(mySpy).toHaveBeenCalledWith(jasmine.objectContaining({foo: "bar"});
219
*
220
* @param sample {Object} sample
221
* @returns matchable object for the sample
222
*/
223
jasmine.objectContaining = function (sample) {
224
return new jasmine.Matchers.ObjectContaining(sample);
225
};
226
227
/**
228
* Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
229
*
230
* Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
231
* expectation syntax. Spies can be checked if they were called or not and what the calling params were.
232
*
233
* A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
234
*
235
* Spies are torn down at the end of every spec.
236
*
237
* Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
238
*
239
* @example
240
* // a stub
241
* var myStub = jasmine.createSpy('myStub'); // can be used anywhere
242
*
243
* // spy example
244
* var foo = {
245
* not: function(bool) { return !bool; }
246
* }
247
*
248
* // actual foo.not will not be called, execution stops
249
* spyOn(foo, 'not');
250
251
// foo.not spied upon, execution will continue to implementation
252
* spyOn(foo, 'not').andCallThrough();
253
*
254
* // fake example
255
* var foo = {
256
* not: function(bool) { return !bool; }
257
* }
258
*
259
* // foo.not(val) will return val
260
* spyOn(foo, 'not').andCallFake(function(value) {return value;});
261
*
262
* // mock example
263
* foo.not(7 == 7);
264
* expect(foo.not).toHaveBeenCalled();
265
* expect(foo.not).toHaveBeenCalledWith(true);
266
*
267
* @constructor
268
* @see spyOn, jasmine.createSpy, jasmine.createSpyObj
269
* @param {String} name
270
*/
271
jasmine.Spy = function(name) {
272
/**
273
* The name of the spy, if provided.
274
*/
275
this.identity = name || 'unknown';
276
/**
277
* Is this Object a spy?
278
*/
279
this.isSpy = true;
280
/**
281
* The actual function this spy stubs.
282
*/
283
this.plan = function() {
284
};
285
/**
286
* Tracking of the most recent call to the spy.
287
* @example
288
* var mySpy = jasmine.createSpy('foo');
289
* mySpy(1, 2);
290
* mySpy.mostRecentCall.args = [1, 2];
291
*/
292
this.mostRecentCall = {};
293
294
/**
295
* Holds arguments for each call to the spy, indexed by call count
296
* @example
297
* var mySpy = jasmine.createSpy('foo');
298
* mySpy(1, 2);
299
* mySpy(7, 8);
300
* mySpy.mostRecentCall.args = [7, 8];
301
* mySpy.argsForCall[0] = [1, 2];
302
* mySpy.argsForCall[1] = [7, 8];
303
*/
304
this.argsForCall = [];
305
this.calls = [];
306
};
307
308
/**
309
* Tells a spy to call through to the actual implemenatation.
310
*
311
* @example
312
* var foo = {
313
* bar: function() { // do some stuff }
314
* }
315
*
316
* // defining a spy on an existing property: foo.bar
317
* spyOn(foo, 'bar').andCallThrough();
318
*/
319
jasmine.Spy.prototype.andCallThrough = function() {
320
this.plan = this.originalValue;
321
return this;
322
};
323
324
/**
325
* For setting the return value of a spy.
326
*
327
* @example
328
* // defining a spy from scratch: foo() returns 'baz'
329
* var foo = jasmine.createSpy('spy on foo').andReturn('baz');
330
*
331
* // defining a spy on an existing property: foo.bar() returns 'baz'
332
* spyOn(foo, 'bar').andReturn('baz');
333
*
334
* @param {Object} value
335
*/
336
jasmine.Spy.prototype.andReturn = function(value) {
337
this.plan = function() {
338
return value;
339
};
340
return this;
341
};
342
343
/**
344
* For throwing an exception when a spy is called.
345
*
346
* @example
347
* // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
348
* var foo = jasmine.createSpy('spy on foo').andThrow('baz');
349
*
350
* // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
351
* spyOn(foo, 'bar').andThrow('baz');
352
*
353
* @param {String} exceptionMsg
354
*/
355
jasmine.Spy.prototype.andThrow = function(exceptionMsg) {
356
this.plan = function() {
357
throw exceptionMsg;
358
};
359
return this;
360
};
361
362
/**
363
* Calls an alternate implementation when a spy is called.
364
*
365
* @example
366
* var baz = function() {
367
* // do some stuff, return something
368
* }
369
* // defining a spy from scratch: foo() calls the function baz
370
* var foo = jasmine.createSpy('spy on foo').andCall(baz);
371
*
372
* // defining a spy on an existing property: foo.bar() calls an anonymnous function
373
* spyOn(foo, 'bar').andCall(function() { return 'baz';} );
374
*
375
* @param {Function} fakeFunc
376
*/
377
jasmine.Spy.prototype.andCallFake = function(fakeFunc) {
378
this.plan = fakeFunc;
379
return this;
380
};
381
382
/**
383
* Resets all of a spy's the tracking variables so that it can be used again.
384
*
385
* @example
386
* spyOn(foo, 'bar');
387
*
388
* foo.bar();
389
*
390
* expect(foo.bar.callCount).toEqual(1);
391
*
392
* foo.bar.reset();
393
*
394
* expect(foo.bar.callCount).toEqual(0);
395
*/
396
jasmine.Spy.prototype.reset = function() {
397
this.wasCalled = false;
398
this.callCount = 0;
399
this.argsForCall = [];
400
this.calls = [];
401
this.mostRecentCall = {};
402
};
403
404
jasmine.createSpy = function(name) {
405
406
var spyObj = function() {
407
spyObj.wasCalled = true;
408
spyObj.callCount++;
409
var args = jasmine.util.argsToArray(arguments);
410
spyObj.mostRecentCall.object = this;
411
spyObj.mostRecentCall.args = args;
412
spyObj.argsForCall.push(args);
413
spyObj.calls.push({object: this, args: args});
414
return spyObj.plan.apply(this, arguments);
415
};
416
417
var spy = new jasmine.Spy(name);
418
419
for (var prop in spy) {
420
spyObj[prop] = spy[prop];
421
}
422
423
spyObj.reset();
424
425
return spyObj;
426
};
427
428
/**
429
* Determines whether an object is a spy.
430
*
431
* @param {jasmine.Spy|Object} putativeSpy
432
* @returns {Boolean}
433
*/
434
jasmine.isSpy = function(putativeSpy) {
435
return putativeSpy && putativeSpy.isSpy;
436
};
437
438
/**
439
* Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
440
* large in one call.
441
*
442
* @param {String} baseName name of spy class
443
* @param {Array} methodNames array of names of methods to make spies
444
*/
445
jasmine.createSpyObj = function(baseName, methodNames) {
446
if (!jasmine.isArray_(methodNames) || methodNames.length === 0) {
447
throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
448
}
449
var obj = {};
450
for (var i = 0; i < methodNames.length; i++) {
451
obj[methodNames[i]] = jasmine.createSpy(baseName + '.' + methodNames[i]);
452
}
453
return obj;
454
};
455
456
/**
457
* All parameters are pretty-printed and concatenated together, then written to the current spec's output.
458
*
459
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
460
*/
461
jasmine.log = function() {
462
var spec = jasmine.getEnv().currentSpec;
463
spec.log.apply(spec, arguments);
464
};
465
466
/**
467
* Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
468
*
469
* @example
470
* // spy example
471
* var foo = {
472
* not: function(bool) { return !bool; }
473
* }
474
* spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
475
*
476
* @see jasmine.createSpy
477
* @param obj
478
* @param methodName
479
* @return {jasmine.Spy} a Jasmine spy that can be chained with all spy methods
480
*/
481
var spyOn = function(obj, methodName) {
482
return jasmine.getEnv().currentSpec.spyOn(obj, methodName);
483
};
484
if (isCommonJS) exports.spyOn = spyOn;
485
486
/**
487
* Creates a Jasmine spec that will be added to the current suite.
488
*
489
* // TODO: pending tests
490
*
491
* @example
492
* it('should be true', function() {
493
* expect(true).toEqual(true);
494
* });
495
*
496
* @param {String} desc description of this specification
497
* @param {Function} func defines the preconditions and expectations of the spec
498
*/
499
var it = function(desc, func) {
500
return jasmine.getEnv().it(desc, func);
501
};
502
if (isCommonJS) exports.it = it;
503
504
/**
505
* Creates a <em>disabled</em> Jasmine spec.
506
*
507
* A convenience method that allows existing specs to be disabled temporarily during development.
508
*
509
* @param {String} desc description of this specification
510
* @param {Function} func defines the preconditions and expectations of the spec
511
*/
512
var xit = function(desc, func) {
513
return jasmine.getEnv().xit(desc, func);
514
};
515
if (isCommonJS) exports.xit = xit;
516
517
/**
518
* Starts a chain for a Jasmine expectation.
519
*
520
* It is passed an Object that is the actual value and should chain to one of the many
521
* jasmine.Matchers functions.
522
*
523
* @param {Object} actual Actual value to test against and expected value
524
* @return {jasmine.Matchers}
525
*/
526
var expect = function(actual) {
527
return jasmine.getEnv().currentSpec.expect(actual);
528
};
529
if (isCommonJS) exports.expect = expect;
530
531
/**
532
* Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
533
*
534
* @param {Function} func Function that defines part of a jasmine spec.
535
*/
536
var runs = function(func) {
537
jasmine.getEnv().currentSpec.runs(func);
538
};
539
if (isCommonJS) exports.runs = runs;
540
541
/**
542
* Waits a fixed time period before moving to the next block.
543
*
544
* @deprecated Use waitsFor() instead
545
* @param {Number} timeout milliseconds to wait
546
*/
547
var waits = function(timeout) {
548
jasmine.getEnv().currentSpec.waits(timeout);
549
};
550
if (isCommonJS) exports.waits = waits;
551
552
/**
553
* Waits for the latchFunction to return true before proceeding to the next block.
554
*
555
* @param {Function} latchFunction
556
* @param {String} optional_timeoutMessage
557
* @param {Number} optional_timeout
558
*/
559
var waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
560
jasmine.getEnv().currentSpec.waitsFor.apply(jasmine.getEnv().currentSpec, arguments);
561
};
562
if (isCommonJS) exports.waitsFor = waitsFor;
563
564
/**
565
* A function that is called before each spec in a suite.
566
*
567
* Used for spec setup, including validating assumptions.
568
*
569
* @param {Function} beforeEachFunction
570
*/
571
var beforeEach = function(beforeEachFunction) {
572
jasmine.getEnv().beforeEach(beforeEachFunction);
573
};
574
if (isCommonJS) exports.beforeEach = beforeEach;
575
576
/**
577
* A function that is called after each spec in a suite.
578
*
579
* Used for restoring any state that is hijacked during spec execution.
580
*
581
* @param {Function} afterEachFunction
582
*/
583
var afterEach = function(afterEachFunction) {
584
jasmine.getEnv().afterEach(afterEachFunction);
585
};
586
if (isCommonJS) exports.afterEach = afterEach;
587
588
/**
589
* Defines a suite of specifications.
590
*
591
* Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
592
* are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
593
* of setup in some tests.
594
*
595
* @example
596
* // TODO: a simple suite
597
*
598
* // TODO: a simple suite with a nested describe block
599
*
600
* @param {String} description A string, usually the class under test.
601
* @param {Function} specDefinitions function that defines several specs.
602
*/
603
var describe = function(description, specDefinitions) {
604
return jasmine.getEnv().describe(description, specDefinitions);
605
};
606
if (isCommonJS) exports.describe = describe;
607
608
/**
609
* Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
610
*
611
* @param {String} description A string, usually the class under test.
612
* @param {Function} specDefinitions function that defines several specs.
613
*/
614
var xdescribe = function(description, specDefinitions) {
615
return jasmine.getEnv().xdescribe(description, specDefinitions);
616
};
617
if (isCommonJS) exports.xdescribe = xdescribe;
618
619
620
// Provide the XMLHttpRequest class for IE 5.x-6.x:
621
jasmine.XmlHttpRequest = (typeof XMLHttpRequest == "undefined") ? function() {
622
function tryIt(f) {
623
try {
624
return f();
625
} catch(e) {
626
}
627
return null;
628
}
629
630
var xhr = tryIt(function() {
631
return new ActiveXObject("Msxml2.XMLHTTP.6.0");
632
}) ||
633
tryIt(function() {
634
return new ActiveXObject("Msxml2.XMLHTTP.3.0");
635
}) ||
636
tryIt(function() {
637
return new ActiveXObject("Msxml2.XMLHTTP");
638
}) ||
639
tryIt(function() {
640
return new ActiveXObject("Microsoft.XMLHTTP");
641
});
642
643
if (!xhr) throw new Error("This browser does not support XMLHttpRequest.");
644
645
return xhr;
646
} : XMLHttpRequest;
647
/**
648
* @namespace
649
*/
650
jasmine.util = {};
651
652
/**
653
* Declare that a child class inherit it's prototype from the parent class.
654
*
655
* @private
656
* @param {Function} childClass
657
* @param {Function} parentClass
658
*/
659
jasmine.util.inherit = function(childClass, parentClass) {
660
/**
661
* @private
662
*/
663
var subclass = function() {
664
};
665
subclass.prototype = parentClass.prototype;
666
childClass.prototype = new subclass();
667
};
668
669
jasmine.util.formatException = function(e) {
670
var lineNumber;
671
if (e.line) {
672
lineNumber = e.line;
673
}
674
else if (e.lineNumber) {
675
lineNumber = e.lineNumber;
676
}
677
678
var file;
679
680
if (e.sourceURL) {
681
file = e.sourceURL;
682
}
683
else if (e.fileName) {
684
file = e.fileName;
685
}
686
687
var message = (e.name && e.message) ? (e.name + ': ' + e.message) : e.toString();
688
689
if (file && lineNumber) {
690
message += ' in ' + file + ' (line ' + lineNumber + ')';
691
}
692
693
return message;
694
};
695
696
jasmine.util.htmlEscape = function(str) {
697
if (!str) return str;
698
return str.replace(/&/g, '&amp;')
699
.replace(/</g, '&lt;')
700
.replace(/>/g, '&gt;');
701
};
702
703
jasmine.util.argsToArray = function(args) {
704
var arrayOfArgs = [];
705
for (var i = 0; i < args.length; i++) arrayOfArgs.push(args[i]);
706
return arrayOfArgs;
707
};
708
709
jasmine.util.extend = function(destination, source) {
710
for (var property in source) destination[property] = source[property];
711
return destination;
712
};
713
714
/**
715
* Environment for Jasmine
716
*
717
* @constructor
718
*/
719
jasmine.Env = function() {
720
this.currentSpec = null;
721
this.currentSuite = null;
722
this.currentRunner_ = new jasmine.Runner(this);
723
724
this.reporter = new jasmine.MultiReporter();
725
726
this.updateInterval = jasmine.DEFAULT_UPDATE_INTERVAL;
727
this.defaultTimeoutInterval = jasmine.DEFAULT_TIMEOUT_INTERVAL;
728
this.lastUpdate = 0;
729
this.specFilter = function() {
730
return true;
731
};
732
733
this.nextSpecId_ = 0;
734
this.nextSuiteId_ = 0;
735
this.equalityTesters_ = [];
736
737
// wrap matchers
738
this.matchersClass = function() {
739
jasmine.Matchers.apply(this, arguments);
740
};
741
jasmine.util.inherit(this.matchersClass, jasmine.Matchers);
742
743
jasmine.Matchers.wrapInto_(jasmine.Matchers.prototype, this.matchersClass);
744
};
745
746
747
jasmine.Env.prototype.setTimeout = jasmine.setTimeout;
748
jasmine.Env.prototype.clearTimeout = jasmine.clearTimeout;
749
jasmine.Env.prototype.setInterval = jasmine.setInterval;
750
jasmine.Env.prototype.clearInterval = jasmine.clearInterval;
751
752
/**
753
* @returns an object containing jasmine version build info, if set.
754
*/
755
jasmine.Env.prototype.version = function () {
756
if (jasmine.version_) {
757
return jasmine.version_;
758
} else {
759
throw new Error('Version not set');
760
}
761
};
762
763
/**
764
* @returns string containing jasmine version build info, if set.
765
*/
766
jasmine.Env.prototype.versionString = function() {
767
if (!jasmine.version_) {
768
return "version unknown";
769
}
770
771
var version = this.version();
772
var versionString = version.major + "." + version.minor + "." + version.build;
773
if (version.release_candidate) {
774
versionString += ".rc" + version.release_candidate;
775
}
776
versionString += " revision " + version.revision;
777
return versionString;
778
};
779
780
/**
781
* @returns a sequential integer starting at 0
782
*/
783
jasmine.Env.prototype.nextSpecId = function () {
784
return this.nextSpecId_++;
785
};
786
787
/**
788
* @returns a sequential integer starting at 0
789
*/
790
jasmine.Env.prototype.nextSuiteId = function () {
791
return this.nextSuiteId_++;
792
};
793
794
/**
795
* Register a reporter to receive status updates from Jasmine.
796
* @param {jasmine.Reporter} reporter An object which will receive status updates.
797
*/
798
jasmine.Env.prototype.addReporter = function(reporter) {
799
this.reporter.addReporter(reporter);
800
};
801
802
jasmine.Env.prototype.execute = function() {
803
this.currentRunner_.execute();
804
};
805
806
jasmine.Env.prototype.describe = function(description, specDefinitions) {
807
var suite = new jasmine.Suite(this, description, specDefinitions, this.currentSuite);
808
809
var parentSuite = this.currentSuite;
810
if (parentSuite) {
811
parentSuite.add(suite);
812
} else {
813
this.currentRunner_.add(suite);
814
}
815
816
this.currentSuite = suite;
817
818
var declarationError = null;
819
try {
820
specDefinitions.call(suite);
821
} catch(e) {
822
declarationError = e;
823
}
824
825
if (declarationError) {
826
this.it("encountered a declaration exception", function() {
827
throw declarationError;
828
});
829
}
830
831
this.currentSuite = parentSuite;
832
833
return suite;
834
};
835
836
jasmine.Env.prototype.beforeEach = function(beforeEachFunction) {
837
if (this.currentSuite) {
838
this.currentSuite.beforeEach(beforeEachFunction);
839
} else {
840
this.currentRunner_.beforeEach(beforeEachFunction);
841
}
842
};
843
844
jasmine.Env.prototype.currentRunner = function () {
845
return this.currentRunner_;
846
};
847
848
jasmine.Env.prototype.afterEach = function(afterEachFunction) {
849
if (this.currentSuite) {
850
this.currentSuite.afterEach(afterEachFunction);
851
} else {
852
this.currentRunner_.afterEach(afterEachFunction);
853
}
854
855
};
856
857
jasmine.Env.prototype.xdescribe = function(desc, specDefinitions) {
858
return {
859
execute: function() {
860
}
861
};
862
};
863
864
jasmine.Env.prototype.it = function(description, func) {
865
var spec = new jasmine.Spec(this, this.currentSuite, description);
866
this.currentSuite.add(spec);
867
this.currentSpec = spec;
868
869
if (func) {
870
spec.runs(func);
871
}
872
873
return spec;
874
};
875
876
jasmine.Env.prototype.xit = function(desc, func) {
877
return {
878
id: this.nextSpecId(),
879
runs: function() {
880
}
881
};
882
};
883
884
jasmine.Env.prototype.compareRegExps_ = function(a, b, mismatchKeys, mismatchValues) {
885
if (a.source != b.source)
886
mismatchValues.push("expected pattern /" + b.source + "/ is not equal to the pattern /" + a.source + "/");
887
888
if (a.ignoreCase != b.ignoreCase)
889
mismatchValues.push("expected modifier i was" + (b.ignoreCase ? " " : " not ") + "set and does not equal the origin modifier");
890
891
if (a.global != b.global)
892
mismatchValues.push("expected modifier g was" + (b.global ? " " : " not ") + "set and does not equal the origin modifier");
893
894
if (a.multiline != b.multiline)
895
mismatchValues.push("expected modifier m was" + (b.multiline ? " " : " not ") + "set and does not equal the origin modifier");
896
897
if (a.sticky != b.sticky)
898
mismatchValues.push("expected modifier y was" + (b.sticky ? " " : " not ") + "set and does not equal the origin modifier");
899
900
return (mismatchValues.length === 0);
901
};
902
903
jasmine.Env.prototype.compareObjects_ = function(a, b, mismatchKeys, mismatchValues) {
904
if (a.__Jasmine_been_here_before__ === b && b.__Jasmine_been_here_before__ === a) {
905
return true;
906
}
907
908
a.__Jasmine_been_here_before__ = b;
909
b.__Jasmine_been_here_before__ = a;
910
911
var hasKey = function(obj, keyName) {
912
return obj !== null && obj[keyName] !== jasmine.undefined;
913
};
914
915
for (var property in b) {
916
if (!hasKey(a, property) && hasKey(b, property)) {
917
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
918
}
919
}
920
for (property in a) {
921
if (!hasKey(b, property) && hasKey(a, property)) {
922
mismatchKeys.push("expected missing key '" + property + "', but present in actual.");
923
}
924
}
925
for (property in b) {
926
if (property == '__Jasmine_been_here_before__') continue;
927
if (!this.equals_(a[property], b[property], mismatchKeys, mismatchValues)) {
928
mismatchValues.push("'" + property + "' was '" + (b[property] ? jasmine.util.htmlEscape(b[property].toString()) : b[property]) + "' in expected, but was '" + (a[property] ? jasmine.util.htmlEscape(a[property].toString()) : a[property]) + "' in actual.");
929
}
930
}
931
932
if (jasmine.isArray_(a) && jasmine.isArray_(b) && a.length != b.length) {
933
mismatchValues.push("arrays were not the same length");
934
}
935
936
delete a.__Jasmine_been_here_before__;
937
delete b.__Jasmine_been_here_before__;
938
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
939
};
940
941
jasmine.Env.prototype.equals_ = function(a, b, mismatchKeys, mismatchValues) {
942
mismatchKeys = mismatchKeys || [];
943
mismatchValues = mismatchValues || [];
944
945
for (var i = 0; i < this.equalityTesters_.length; i++) {
946
var equalityTester = this.equalityTesters_[i];
947
var result = equalityTester(a, b, this, mismatchKeys, mismatchValues);
948
if (result !== jasmine.undefined) return result;
949
}
950
951
if (a === b) return true;
952
953
if (a === jasmine.undefined || a === null || b === jasmine.undefined || b === null) {
954
return (a == jasmine.undefined && b == jasmine.undefined);
955
}
956
957
if (jasmine.isDomNode(a) && jasmine.isDomNode(b)) {
958
return a === b;
959
}
960
961
if (a instanceof Date && b instanceof Date) {
962
return a.getTime() == b.getTime();
963
}
964
965
if (a.jasmineMatches) {
966
return a.jasmineMatches(b);
967
}
968
969
if (b.jasmineMatches) {
970
return b.jasmineMatches(a);
971
}
972
973
if (a instanceof jasmine.Matchers.ObjectContaining) {
974
return a.matches(b);
975
}
976
977
if (b instanceof jasmine.Matchers.ObjectContaining) {
978
return b.matches(a);
979
}
980
981
if (jasmine.isString_(a) && jasmine.isString_(b)) {
982
return (a == b);
983
}
984
985
if (jasmine.isNumber_(a) && jasmine.isNumber_(b)) {
986
return (a == b);
987
}
988
989
if (a instanceof RegExp && b instanceof RegExp) {
990
return this.compareRegExps_(a, b, mismatchKeys, mismatchValues);
991
}
992
993
if (typeof a === "object" && typeof b === "object") {
994
return this.compareObjects_(a, b, mismatchKeys, mismatchValues);
995
}
996
997
//Straight check
998
return (a === b);
999
};
1000
1001
jasmine.Env.prototype.contains_ = function(haystack, needle) {
1002
if (jasmine.isArray_(haystack)) {
1003
for (var i = 0; i < haystack.length; i++) {
1004
if (this.equals_(haystack[i], needle)) return true;
1005
}
1006
return false;
1007
}
1008
return haystack.indexOf(needle) >= 0;
1009
};
1010
1011
jasmine.Env.prototype.addEqualityTester = function(equalityTester) {
1012
this.equalityTesters_.push(equalityTester);
1013
};
1014
/** No-op base class for Jasmine reporters.
1015
*
1016
* @constructor
1017
*/
1018
jasmine.Reporter = function() {
1019
};
1020
1021
//noinspection JSUnusedLocalSymbols
1022
jasmine.Reporter.prototype.reportRunnerStarting = function(runner) {
1023
};
1024
1025
//noinspection JSUnusedLocalSymbols
1026
jasmine.Reporter.prototype.reportRunnerResults = function(runner) {
1027
};
1028
1029
//noinspection JSUnusedLocalSymbols
1030
jasmine.Reporter.prototype.reportSuiteResults = function(suite) {
1031
};
1032
1033
//noinspection JSUnusedLocalSymbols
1034
jasmine.Reporter.prototype.reportSpecStarting = function(spec) {
1035
};
1036
1037
//noinspection JSUnusedLocalSymbols
1038
jasmine.Reporter.prototype.reportSpecResults = function(spec) {
1039
};
1040
1041
//noinspection JSUnusedLocalSymbols
1042
jasmine.Reporter.prototype.log = function(str) {
1043
};
1044
1045
/**
1046
* Blocks are functions with executable code that make up a spec.
1047
*
1048
* @constructor
1049
* @param {jasmine.Env} env
1050
* @param {Function} func
1051
* @param {jasmine.Spec} spec
1052
*/
1053
jasmine.Block = function(env, func, spec) {
1054
this.env = env;
1055
this.func = func;
1056
this.spec = spec;
1057
};
1058
1059
jasmine.Block.prototype.execute = function(onComplete) {
1060
if (!jasmine.CATCH_EXCEPTIONS) {
1061
this.func.apply(this.spec);
1062
}
1063
else {
1064
try {
1065
this.func.apply(this.spec);
1066
} catch (e) {
1067
this.spec.fail(e);
1068
}
1069
}
1070
onComplete();
1071
};
1072
/** JavaScript API reporter.
1073
*
1074
* @constructor
1075
*/
1076
jasmine.JsApiReporter = function() {
1077
this.started = false;
1078
this.finished = false;
1079
this.suites_ = [];
1080
this.results_ = {};
1081
};
1082
1083
jasmine.JsApiReporter.prototype.reportRunnerStarting = function(runner) {
1084
this.started = true;
1085
var suites = runner.topLevelSuites();
1086
for (var i = 0; i < suites.length; i++) {
1087
var suite = suites[i];
1088
this.suites_.push(this.summarize_(suite));
1089
}
1090
};
1091
1092
jasmine.JsApiReporter.prototype.suites = function() {
1093
return this.suites_;
1094
};
1095
1096
jasmine.JsApiReporter.prototype.summarize_ = function(suiteOrSpec) {
1097
var isSuite = suiteOrSpec instanceof jasmine.Suite;
1098
var summary = {
1099
id: suiteOrSpec.id,
1100
name: suiteOrSpec.description,
1101
type: isSuite ? 'suite' : 'spec',
1102
children: []
1103
};
1104
1105
if (isSuite) {
1106
var children = suiteOrSpec.children();
1107
for (var i = 0; i < children.length; i++) {
1108
summary.children.push(this.summarize_(children[i]));
1109
}
1110
}
1111
return summary;
1112
};
1113
1114
jasmine.JsApiReporter.prototype.results = function() {
1115
return this.results_;
1116
};
1117
1118
jasmine.JsApiReporter.prototype.resultsForSpec = function(specId) {
1119
return this.results_[specId];
1120
};
1121
1122
//noinspection JSUnusedLocalSymbols
1123
jasmine.JsApiReporter.prototype.reportRunnerResults = function(runner) {
1124
this.finished = true;
1125
};
1126
1127
//noinspection JSUnusedLocalSymbols
1128
jasmine.JsApiReporter.prototype.reportSuiteResults = function(suite) {
1129
};
1130
1131
//noinspection JSUnusedLocalSymbols
1132
jasmine.JsApiReporter.prototype.reportSpecResults = function(spec) {
1133
this.results_[spec.id] = {
1134
messages: spec.results().getItems(),
1135
result: spec.results().failedCount > 0 ? "failed" : "passed"
1136
};
1137
};
1138
1139
//noinspection JSUnusedLocalSymbols
1140
jasmine.JsApiReporter.prototype.log = function(str) {
1141
};
1142
1143
jasmine.JsApiReporter.prototype.resultsForSpecs = function(specIds){
1144
var results = {};
1145
for (var i = 0; i < specIds.length; i++) {
1146
var specId = specIds[i];
1147
results[specId] = this.summarizeResult_(this.results_[specId]);
1148
}
1149
return results;
1150
};
1151
1152
jasmine.JsApiReporter.prototype.summarizeResult_ = function(result){
1153
var summaryMessages = [];
1154
var messagesLength = result.messages.length;
1155
for (var messageIndex = 0; messageIndex < messagesLength; messageIndex++) {
1156
var resultMessage = result.messages[messageIndex];
1157
summaryMessages.push({
1158
text: resultMessage.type == 'log' ? resultMessage.toString() : jasmine.undefined,
1159
passed: resultMessage.passed ? resultMessage.passed() : true,
1160
type: resultMessage.type,
1161
message: resultMessage.message,
1162
trace: {
1163
stack: resultMessage.passed && !resultMessage.passed() ? resultMessage.trace.stack : jasmine.undefined
1164
}
1165
});
1166
}
1167
1168
return {
1169
result : result.result,
1170
messages : summaryMessages
1171
};
1172
};
1173
1174
/**
1175
* @constructor
1176
* @param {jasmine.Env} env
1177
* @param actual
1178
* @param {jasmine.Spec} spec
1179
*/
1180
jasmine.Matchers = function(env, actual, spec, opt_isNot) {
1181
this.env = env;
1182
this.actual = actual;
1183
this.spec = spec;
1184
this.isNot = opt_isNot || false;
1185
this.reportWasCalled_ = false;
1186
};
1187
1188
// todo: @deprecated as of Jasmine 0.11, remove soon [xw]
1189
jasmine.Matchers.pp = function(str) {
1190
throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
1191
};
1192
1193
// todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
1194
jasmine.Matchers.prototype.report = function(result, failing_message, details) {
1195
throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
1196
};
1197
1198
jasmine.Matchers.wrapInto_ = function(prototype, matchersClass) {
1199
for (var methodName in prototype) {
1200
if (methodName == 'report') continue;
1201
var orig = prototype[methodName];
1202
matchersClass.prototype[methodName] = jasmine.Matchers.matcherFn_(methodName, orig);
1203
}
1204
};
1205
1206
jasmine.Matchers.matcherFn_ = function(matcherName, matcherFunction) {
1207
return function() {
1208
var matcherArgs = jasmine.util.argsToArray(arguments);
1209
var result = matcherFunction.apply(this, arguments);
1210
1211
if (this.isNot) {
1212
result = !result;
1213
}
1214
1215
if (this.reportWasCalled_) return result;
1216
1217
var message;
1218
if (!result) {
1219
if (this.message) {
1220
message = this.message.apply(this, arguments);
1221
if (jasmine.isArray_(message)) {
1222
message = message[this.isNot ? 1 : 0];
1223
}
1224
} else {
1225
var englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1226
message = "Expected " + jasmine.pp(this.actual) + (this.isNot ? " not " : " ") + englishyPredicate;
1227
if (matcherArgs.length > 0) {
1228
for (var i = 0; i < matcherArgs.length; i++) {
1229
if (i > 0) message += ",";
1230
message += " " + jasmine.pp(matcherArgs[i]);
1231
}
1232
}
1233
message += ".";
1234
}
1235
}
1236
var expectationResult = new jasmine.ExpectationResult({
1237
matcherName: matcherName,
1238
passed: result,
1239
expected: matcherArgs.length > 1 ? matcherArgs : matcherArgs[0],
1240
actual: this.actual,
1241
message: message,
1242
isNot: this.isNot
1243
});
1244
this.spec.addMatcherResult(expectationResult);
1245
return jasmine.undefined;
1246
};
1247
};
1248
1249
1250
1251
1252
/**
1253
* toBe: compares the actual to the expected using ===
1254
* @param expected
1255
*/
1256
jasmine.Matchers.prototype.toBe = function(expected) {
1257
return this.actual === expected;
1258
};
1259
1260
/**
1261
* toNotBe: compares the actual to the expected using !==
1262
* @param expected
1263
* @deprecated as of 1.0. Use not.toBe() instead.
1264
*/
1265
jasmine.Matchers.prototype.toNotBe = function(expected) {
1266
return this.actual !== expected;
1267
};
1268
1269
/**
1270
* toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
1271
*
1272
* @param expected
1273
*/
1274
jasmine.Matchers.prototype.toEqual = function(expected) {
1275
return this.env.equals_(this.actual, expected);
1276
};
1277
1278
/**
1279
* toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
1280
* @param expected
1281
* @deprecated as of 1.0. Use not.toEqual() instead.
1282
*/
1283
jasmine.Matchers.prototype.toNotEqual = function(expected) {
1284
return !this.env.equals_(this.actual, expected);
1285
};
1286
1287
/**
1288
* Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
1289
* a pattern or a String.
1290
*
1291
* @param expected
1292
*/
1293
jasmine.Matchers.prototype.toMatch = function(expected) {
1294
return new RegExp(expected).test(this.actual);
1295
};
1296
1297
/**
1298
* Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
1299
* @param expected
1300
* @deprecated as of 1.0. Use not.toMatch() instead.
1301
*/
1302
jasmine.Matchers.prototype.toNotMatch = function(expected) {
1303
return !(new RegExp(expected).test(this.actual));
1304
};
1305
1306
/**
1307
* Matcher that compares the actual to jasmine.undefined.
1308
*/
1309
jasmine.Matchers.prototype.toBeDefined = function() {
1310
return (this.actual !== jasmine.undefined);
1311
};
1312
1313
/**
1314
* Matcher that compares the actual to jasmine.undefined.
1315
*/
1316
jasmine.Matchers.prototype.toBeUndefined = function() {
1317
return (this.actual === jasmine.undefined);
1318
};
1319
1320
/**
1321
* Matcher that compares the actual to null.
1322
*/
1323
jasmine.Matchers.prototype.toBeNull = function() {
1324
return (this.actual === null);
1325
};
1326
1327
/**
1328
* Matcher that compares the actual to NaN.
1329
*/
1330
jasmine.Matchers.prototype.toBeNaN = function() {
1331
this.message = function() {
1332
return [ "Expected " + jasmine.pp(this.actual) + " to be NaN." ];
1333
};
1334
1335
return (this.actual !== this.actual);
1336
};
1337
1338
/**
1339
* Matcher that boolean not-nots the actual.
1340
*/
1341
jasmine.Matchers.prototype.toBeTruthy = function() {
1342
return !!this.actual;
1343
};
1344
1345
1346
/**
1347
* Matcher that boolean nots the actual.
1348
*/
1349
jasmine.Matchers.prototype.toBeFalsy = function() {
1350
return !this.actual;
1351
};
1352
1353
1354
/**
1355
* Matcher that checks to see if the actual, a Jasmine spy, was called.
1356
*/
1357
jasmine.Matchers.prototype.toHaveBeenCalled = function() {
1358
if (arguments.length > 0) {
1359
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
1360
}
1361
1362
if (!jasmine.isSpy(this.actual)) {
1363
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1364
}
1365
1366
this.message = function() {
1367
return [
1368
"Expected spy " + this.actual.identity + " to have been called.",
1369
"Expected spy " + this.actual.identity + " not to have been called."
1370
];
1371
};
1372
1373
return this.actual.wasCalled;
1374
};
1375
1376
/** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
1377
jasmine.Matchers.prototype.wasCalled = jasmine.Matchers.prototype.toHaveBeenCalled;
1378
1379
/**
1380
* Matcher that checks to see if the actual, a Jasmine spy, was not called.
1381
*
1382
* @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
1383
*/
1384
jasmine.Matchers.prototype.wasNotCalled = function() {
1385
if (arguments.length > 0) {
1386
throw new Error('wasNotCalled does not take arguments');
1387
}
1388
1389
if (!jasmine.isSpy(this.actual)) {
1390
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1391
}
1392
1393
this.message = function() {
1394
return [
1395
"Expected spy " + this.actual.identity + " to not have been called.",
1396
"Expected spy " + this.actual.identity + " to have been called."
1397
];
1398
};
1399
1400
return !this.actual.wasCalled;
1401
};
1402
1403
/**
1404
* Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
1405
*
1406
* @example
1407
*
1408
*/
1409
jasmine.Matchers.prototype.toHaveBeenCalledWith = function() {
1410
var expectedArgs = jasmine.util.argsToArray(arguments);
1411
if (!jasmine.isSpy(this.actual)) {
1412
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1413
}
1414
this.message = function() {
1415
var invertedMessage = "Expected spy " + this.actual.identity + " not to have been called with " + jasmine.pp(expectedArgs) + " but it was.";
1416
var positiveMessage = "";
1417
if (this.actual.callCount === 0) {
1418
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but it was never called.";
1419
} else {
1420
positiveMessage = "Expected spy " + this.actual.identity + " to have been called with " + jasmine.pp(expectedArgs) + " but actual calls were " + jasmine.pp(this.actual.argsForCall).replace(/^\[ | \]$/g, '')
1421
}
1422
return [positiveMessage, invertedMessage];
1423
};
1424
1425
return this.env.contains_(this.actual.argsForCall, expectedArgs);
1426
};
1427
1428
/** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
1429
jasmine.Matchers.prototype.wasCalledWith = jasmine.Matchers.prototype.toHaveBeenCalledWith;
1430
1431
/** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
1432
jasmine.Matchers.prototype.wasNotCalledWith = function() {
1433
var expectedArgs = jasmine.util.argsToArray(arguments);
1434
if (!jasmine.isSpy(this.actual)) {
1435
throw new Error('Expected a spy, but got ' + jasmine.pp(this.actual) + '.');
1436
}
1437
1438
this.message = function() {
1439
return [
1440
"Expected spy not to have been called with " + jasmine.pp(expectedArgs) + " but it was",
1441
"Expected spy to have been called with " + jasmine.pp(expectedArgs) + " but it was"
1442
];
1443
};
1444
1445
return !this.env.contains_(this.actual.argsForCall, expectedArgs);
1446
};
1447
1448
/**
1449
* Matcher that checks that the expected item is an element in the actual Array.
1450
*
1451
* @param {Object} expected
1452
*/
1453
jasmine.Matchers.prototype.toContain = function(expected) {
1454
return this.env.contains_(this.actual, expected);
1455
};
1456
1457
/**
1458
* Matcher that checks that the expected item is NOT an element in the actual Array.
1459
*
1460
* @param {Object} expected
1461
* @deprecated as of 1.0. Use not.toContain() instead.
1462
*/
1463
jasmine.Matchers.prototype.toNotContain = function(expected) {
1464
return !this.env.contains_(this.actual, expected);
1465
};
1466
1467
jasmine.Matchers.prototype.toBeLessThan = function(expected) {
1468
return this.actual < expected;
1469
};
1470
1471
jasmine.Matchers.prototype.toBeGreaterThan = function(expected) {
1472
return this.actual > expected;
1473
};
1474
1475
/**
1476
* Matcher that checks that the expected item is equal to the actual item
1477
* up to a given level of decimal precision (default 2).
1478
*
1479
* @param {Number} expected
1480
* @param {Number} precision, as number of decimal places
1481
*/
1482
jasmine.Matchers.prototype.toBeCloseTo = function(expected, precision) {
1483
if (!(precision === 0)) {
1484
precision = precision || 2;
1485
}
1486
return Math.abs(expected - this.actual) < (Math.pow(10, -precision) / 2);
1487
};
1488
1489
/**
1490
* Matcher that checks that the expected exception was thrown by the actual.
1491
*
1492
* @param {String} [expected]
1493
*/
1494
jasmine.Matchers.prototype.toThrow = function(expected) {
1495
var result = false;
1496
var exception;
1497
if (typeof this.actual != 'function') {
1498
throw new Error('Actual is not a function');
1499
}
1500
try {
1501
this.actual();
1502
} catch (e) {
1503
exception = e;
1504
}
1505
if (exception) {
1506
result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected));
1507
}
1508
1509
var not = this.isNot ? "not " : "";
1510
1511
this.message = function() {
1512
if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
1513
return ["Expected function " + not + "to throw", expected ? expected.message || expected : "an exception", ", but it threw", exception.message || exception].join(' ');
1514
} else {
1515
return "Expected function to throw an exception.";
1516
}
1517
};
1518
1519
return result;
1520
};
1521
1522
jasmine.Matchers.Any = function(expectedClass) {
1523
this.expectedClass = expectedClass;
1524
};
1525
1526
jasmine.Matchers.Any.prototype.jasmineMatches = function(other) {
1527
if (this.expectedClass == String) {
1528
return typeof other == 'string' || other instanceof String;
1529
}
1530
1531
if (this.expectedClass == Number) {
1532
return typeof other == 'number' || other instanceof Number;
1533
}
1534
1535
if (this.expectedClass == Function) {
1536
return typeof other == 'function' || other instanceof Function;
1537
}
1538
1539
if (this.expectedClass == Object) {
1540
return typeof other == 'object';
1541
}
1542
1543
return other instanceof this.expectedClass;
1544
};
1545
1546
jasmine.Matchers.Any.prototype.jasmineToString = function() {
1547
return '<jasmine.any(' + this.expectedClass + ')>';
1548
};
1549
1550
jasmine.Matchers.ObjectContaining = function (sample) {
1551
this.sample = sample;
1552
};
1553
1554
jasmine.Matchers.ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
1555
mismatchKeys = mismatchKeys || [];
1556
mismatchValues = mismatchValues || [];
1557
1558
var env = jasmine.getEnv();
1559
1560
var hasKey = function(obj, keyName) {
1561
return obj != null && obj[keyName] !== jasmine.undefined;
1562
};
1563
1564
for (var property in this.sample) {
1565
if (!hasKey(other, property) && hasKey(this.sample, property)) {
1566
mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1567
}
1568
else if (!env.equals_(this.sample[property], other[property], mismatchKeys, mismatchValues)) {
1569
mismatchValues.push("'" + property + "' was '" + (other[property] ? jasmine.util.htmlEscape(other[property].toString()) : other[property]) + "' in expected, but was '" + (this.sample[property] ? jasmine.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in actual.");
1570
}
1571
}
1572
1573
return (mismatchKeys.length === 0 && mismatchValues.length === 0);
1574
};
1575
1576
jasmine.Matchers.ObjectContaining.prototype.jasmineToString = function () {
1577
return "<jasmine.objectContaining(" + jasmine.pp(this.sample) + ")>";
1578
};
1579
// Mock setTimeout, clearTimeout
1580
// Contributed by Pivotal Computer Systems, www.pivotalsf.com
1581
1582
jasmine.FakeTimer = function() {
1583
this.reset();
1584
1585
var self = this;
1586
self.setTimeout = function(funcToCall, millis) {
1587
self.timeoutsMade++;
1588
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, false);
1589
return self.timeoutsMade;
1590
};
1591
1592
self.setInterval = function(funcToCall, millis) {
1593
self.timeoutsMade++;
1594
self.scheduleFunction(self.timeoutsMade, funcToCall, millis, true);
1595
return self.timeoutsMade;
1596
};
1597
1598
self.clearTimeout = function(timeoutKey) {
1599
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
1600
};
1601
1602
self.clearInterval = function(timeoutKey) {
1603
self.scheduledFunctions[timeoutKey] = jasmine.undefined;
1604
};
1605
1606
};
1607
1608
jasmine.FakeTimer.prototype.reset = function() {
1609
this.timeoutsMade = 0;
1610
this.scheduledFunctions = {};
1611
this.nowMillis = 0;
1612
};
1613
1614
jasmine.FakeTimer.prototype.tick = function(millis) {
1615
var oldMillis = this.nowMillis;
1616
var newMillis = oldMillis + millis;
1617
this.runFunctionsWithinRange(oldMillis, newMillis);
1618
this.nowMillis = newMillis;
1619
};
1620
1621
jasmine.FakeTimer.prototype.runFunctionsWithinRange = function(oldMillis, nowMillis) {
1622
var scheduledFunc;
1623
var funcsToRun = [];
1624
for (var timeoutKey in this.scheduledFunctions) {
1625
scheduledFunc = this.scheduledFunctions[timeoutKey];
1626
if (scheduledFunc != jasmine.undefined &&
1627
scheduledFunc.runAtMillis >= oldMillis &&
1628
scheduledFunc.runAtMillis <= nowMillis) {
1629
funcsToRun.push(scheduledFunc);
1630
this.scheduledFunctions[timeoutKey] = jasmine.undefined;
1631
}
1632
}
1633
1634
if (funcsToRun.length > 0) {
1635
funcsToRun.sort(function(a, b) {
1636
return a.runAtMillis - b.runAtMillis;
1637
});
1638
for (var i = 0; i < funcsToRun.length; ++i) {
1639
try {
1640
var funcToRun = funcsToRun[i];
1641
this.nowMillis = funcToRun.runAtMillis;
1642
funcToRun.funcToCall();
1643
if (funcToRun.recurring) {
1644
this.scheduleFunction(funcToRun.timeoutKey,
1645
funcToRun.funcToCall,
1646
funcToRun.millis,
1647
true);
1648
}
1649
} catch(e) {
1650
}
1651
}
1652
this.runFunctionsWithinRange(oldMillis, nowMillis);
1653
}
1654
};
1655
1656
jasmine.FakeTimer.prototype.scheduleFunction = function(timeoutKey, funcToCall, millis, recurring) {
1657
this.scheduledFunctions[timeoutKey] = {
1658
runAtMillis: this.nowMillis + millis,
1659
funcToCall: funcToCall,
1660
recurring: recurring,
1661
timeoutKey: timeoutKey,
1662
millis: millis
1663
};
1664
};
1665
1666
/**
1667
* @namespace
1668
*/
1669
jasmine.Clock = {
1670
defaultFakeTimer: new jasmine.FakeTimer(),
1671
1672
reset: function() {
1673
jasmine.Clock.assertInstalled();
1674
jasmine.Clock.defaultFakeTimer.reset();
1675
},
1676
1677
tick: function(millis) {
1678
jasmine.Clock.assertInstalled();
1679
jasmine.Clock.defaultFakeTimer.tick(millis);
1680
},
1681
1682
runFunctionsWithinRange: function(oldMillis, nowMillis) {
1683
jasmine.Clock.defaultFakeTimer.runFunctionsWithinRange(oldMillis, nowMillis);
1684
},
1685
1686
scheduleFunction: function(timeoutKey, funcToCall, millis, recurring) {
1687
jasmine.Clock.defaultFakeTimer.scheduleFunction(timeoutKey, funcToCall, millis, recurring);
1688
},
1689
1690
useMock: function() {
1691
if (!jasmine.Clock.isInstalled()) {
1692
var spec = jasmine.getEnv().currentSpec;
1693
spec.after(jasmine.Clock.uninstallMock);
1694
1695
jasmine.Clock.installMock();
1696
}
1697
},
1698
1699
installMock: function() {
1700
jasmine.Clock.installed = jasmine.Clock.defaultFakeTimer;
1701
},
1702
1703
uninstallMock: function() {
1704
jasmine.Clock.assertInstalled();
1705
jasmine.Clock.installed = jasmine.Clock.real;
1706
},
1707
1708
real: {
1709
setTimeout: jasmine.getGlobal().setTimeout,
1710
clearTimeout: jasmine.getGlobal().clearTimeout,
1711
setInterval: jasmine.getGlobal().setInterval,
1712
clearInterval: jasmine.getGlobal().clearInterval
1713
},
1714
1715
assertInstalled: function() {
1716
if (!jasmine.Clock.isInstalled()) {
1717
throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
1718
}
1719
},
1720
1721
isInstalled: function() {
1722
return jasmine.Clock.installed == jasmine.Clock.defaultFakeTimer;
1723
},
1724
1725
installed: null
1726
};
1727
jasmine.Clock.installed = jasmine.Clock.real;
1728
1729
//else for IE support
1730
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
1731
if (jasmine.Clock.installed.setTimeout.apply) {
1732
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
1733
} else {
1734
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
1735
}
1736
};
1737
1738
jasmine.getGlobal().setInterval = function(funcToCall, millis) {
1739
if (jasmine.Clock.installed.setInterval.apply) {
1740
return jasmine.Clock.installed.setInterval.apply(this, arguments);
1741
} else {
1742
return jasmine.Clock.installed.setInterval(funcToCall, millis);
1743
}
1744
};
1745
1746
jasmine.getGlobal().clearTimeout = function(timeoutKey) {
1747
if (jasmine.Clock.installed.clearTimeout.apply) {
1748
return jasmine.Clock.installed.clearTimeout.apply(this, arguments);
1749
} else {
1750
return jasmine.Clock.installed.clearTimeout(timeoutKey);
1751
}
1752
};
1753
1754
jasmine.getGlobal().clearInterval = function(timeoutKey) {
1755
if (jasmine.Clock.installed.clearTimeout.apply) {
1756
return jasmine.Clock.installed.clearInterval.apply(this, arguments);
1757
} else {
1758
return jasmine.Clock.installed.clearInterval(timeoutKey);
1759
}
1760
};
1761
1762
/**
1763
* @constructor
1764
*/
1765
jasmine.MultiReporter = function() {
1766
this.subReporters_ = [];
1767
};
1768
jasmine.util.inherit(jasmine.MultiReporter, jasmine.Reporter);
1769
1770
jasmine.MultiReporter.prototype.addReporter = function(reporter) {
1771
this.subReporters_.push(reporter);
1772
};
1773
1774
(function() {
1775
var functionNames = [
1776
"reportRunnerStarting",
1777
"reportRunnerResults",
1778
"reportSuiteResults",
1779
"reportSpecStarting",
1780
"reportSpecResults",
1781
"log"
1782
];
1783
for (var i = 0; i < functionNames.length; i++) {
1784
var functionName = functionNames[i];
1785
jasmine.MultiReporter.prototype[functionName] = (function(functionName) {
1786
return function() {
1787
for (var j = 0; j < this.subReporters_.length; j++) {
1788
var subReporter = this.subReporters_[j];
1789
if (subReporter[functionName]) {
1790
subReporter[functionName].apply(subReporter, arguments);
1791
}
1792
}
1793
};
1794
})(functionName);
1795
}
1796
})();
1797
/**
1798
* Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
1799
*
1800
* @constructor
1801
*/
1802
jasmine.NestedResults = function() {
1803
/**
1804
* The total count of results
1805
*/
1806
this.totalCount = 0;
1807
/**
1808
* Number of passed results
1809
*/
1810
this.passedCount = 0;
1811
/**
1812
* Number of failed results
1813
*/
1814
this.failedCount = 0;
1815
/**
1816
* Was this suite/spec skipped?
1817
*/
1818
this.skipped = false;
1819
/**
1820
* @ignore
1821
*/
1822
this.items_ = [];
1823
};
1824
1825
/**
1826
* Roll up the result counts.
1827
*
1828
* @param result
1829
*/
1830
jasmine.NestedResults.prototype.rollupCounts = function(result) {
1831
this.totalCount += result.totalCount;
1832
this.passedCount += result.passedCount;
1833
this.failedCount += result.failedCount;
1834
};
1835
1836
/**
1837
* Adds a log message.
1838
* @param values Array of message parts which will be concatenated later.
1839
*/
1840
jasmine.NestedResults.prototype.log = function(values) {
1841
this.items_.push(new jasmine.MessageResult(values));
1842
};
1843
1844
/**
1845
* Getter for the results: message & results.
1846
*/
1847
jasmine.NestedResults.prototype.getItems = function() {
1848
return this.items_;
1849
};
1850
1851
/**
1852
* Adds a result, tracking counts (total, passed, & failed)
1853
* @param {jasmine.ExpectationResult|jasmine.NestedResults} result
1854
*/
1855
jasmine.NestedResults.prototype.addResult = function(result) {
1856
if (result.type != 'log') {
1857
if (result.items_) {
1858
this.rollupCounts(result);
1859
} else {
1860
this.totalCount++;
1861
if (result.passed()) {
1862
this.passedCount++;
1863
} else {
1864
this.failedCount++;
1865
}
1866
}
1867
}
1868
this.items_.push(result);
1869
};
1870
1871
/**
1872
* @returns {Boolean} True if <b>everything</b> below passed
1873
*/
1874
jasmine.NestedResults.prototype.passed = function() {
1875
return this.passedCount === this.totalCount;
1876
};
1877
/**
1878
* Base class for pretty printing for expectation results.
1879
*/
1880
jasmine.PrettyPrinter = function() {
1881
this.ppNestLevel_ = 0;
1882
};
1883
1884
/**
1885
* Formats a value in a nice, human-readable string.
1886
*
1887
* @param value
1888
*/
1889
jasmine.PrettyPrinter.prototype.format = function(value) {
1890
this.ppNestLevel_++;
1891
try {
1892
if (value === jasmine.undefined) {
1893
this.emitScalar('undefined');
1894
} else if (value === null) {
1895
this.emitScalar('null');
1896
} else if (value === jasmine.getGlobal()) {
1897
this.emitScalar('<global>');
1898
} else if (value.jasmineToString) {
1899
this.emitScalar(value.jasmineToString());
1900
} else if (typeof value === 'string') {
1901
this.emitString(value);
1902
} else if (jasmine.isSpy(value)) {
1903
this.emitScalar("spy on " + value.identity);
1904
} else if (value instanceof RegExp) {
1905
this.emitScalar(value.toString());
1906
} else if (typeof value === 'function') {
1907
this.emitScalar('Function');
1908
} else if (typeof value.nodeType === 'number') {
1909
this.emitScalar('HTMLNode');
1910
} else if (value instanceof Date) {
1911
this.emitScalar('Date(' + value + ')');
1912
} else if (value.__Jasmine_been_here_before__) {
1913
this.emitScalar('<circular reference: ' + (jasmine.isArray_(value) ? 'Array' : 'Object') + '>');
1914
} else if (jasmine.isArray_(value) || typeof value == 'object') {
1915
value.__Jasmine_been_here_before__ = true;
1916
if (jasmine.isArray_(value)) {
1917
this.emitArray(value);
1918
} else {
1919
this.emitObject(value);
1920
}
1921
delete value.__Jasmine_been_here_before__;
1922
} else {
1923
this.emitScalar(value.toString());
1924
}
1925
} finally {
1926
this.ppNestLevel_--;
1927
}
1928
};
1929
1930
jasmine.PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1931
for (var property in obj) {
1932
if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
1933
if (property == '__Jasmine_been_here_before__') continue;
1934
fn(property, obj.__lookupGetter__ ? (obj.__lookupGetter__(property) !== jasmine.undefined &&
1935
obj.__lookupGetter__(property) !== null) : false);
1936
}
1937
};
1938
1939
jasmine.PrettyPrinter.prototype.emitArray = jasmine.unimplementedMethod_;
1940
jasmine.PrettyPrinter.prototype.emitObject = jasmine.unimplementedMethod_;
1941
jasmine.PrettyPrinter.prototype.emitScalar = jasmine.unimplementedMethod_;
1942
jasmine.PrettyPrinter.prototype.emitString = jasmine.unimplementedMethod_;
1943
1944
jasmine.StringPrettyPrinter = function() {
1945
jasmine.PrettyPrinter.call(this);
1946
1947
this.string = '';
1948
};
1949
jasmine.util.inherit(jasmine.StringPrettyPrinter, jasmine.PrettyPrinter);
1950
1951
jasmine.StringPrettyPrinter.prototype.emitScalar = function(value) {
1952
this.append(value);
1953
};
1954
1955
jasmine.StringPrettyPrinter.prototype.emitString = function(value) {
1956
this.append("'" + value + "'");
1957
};
1958
1959
jasmine.StringPrettyPrinter.prototype.emitArray = function(array) {
1960
if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1961
this.append("Array");
1962
return;
1963
}
1964
1965
this.append('[ ');
1966
for (var i = 0; i < array.length; i++) {
1967
if (i > 0) {
1968
this.append(', ');
1969
}
1970
this.format(array[i]);
1971
}
1972
this.append(' ]');
1973
};
1974
1975
jasmine.StringPrettyPrinter.prototype.emitObject = function(obj) {
1976
if (this.ppNestLevel_ > jasmine.MAX_PRETTY_PRINT_DEPTH) {
1977
this.append("Object");
1978
return;
1979
}
1980
1981
var self = this;
1982
this.append('{ ');
1983
var first = true;
1984
1985
this.iterateObject(obj, function(property, isGetter) {
1986
if (first) {
1987
first = false;
1988
} else {
1989
self.append(', ');
1990
}
1991
1992
self.append(property);
1993
self.append(' : ');
1994
if (isGetter) {
1995
self.append('<getter>');
1996
} else {
1997
self.format(obj[property]);
1998
}
1999
});
2000
2001
this.append(' }');
2002
};
2003
2004
jasmine.StringPrettyPrinter.prototype.append = function(value) {
2005
this.string += value;
2006
};
2007
jasmine.Queue = function(env) {
2008
this.env = env;
2009
2010
// parallel to blocks. each true value in this array means the block will
2011
// get executed even if we abort
2012
this.ensured = [];
2013
this.blocks = [];
2014
this.running = false;
2015
this.index = 0;
2016
this.offset = 0;
2017
this.abort = false;
2018
};
2019
2020
jasmine.Queue.prototype.addBefore = function(block, ensure) {
2021
if (ensure === jasmine.undefined) {
2022
ensure = false;
2023
}
2024
2025
this.blocks.unshift(block);
2026
this.ensured.unshift(ensure);
2027
};
2028
2029
jasmine.Queue.prototype.add = function(block, ensure) {
2030
if (ensure === jasmine.undefined) {
2031
ensure = false;
2032
}
2033
2034
this.blocks.push(block);
2035
this.ensured.push(ensure);
2036
};
2037
2038
jasmine.Queue.prototype.insertNext = function(block, ensure) {
2039
if (ensure === jasmine.undefined) {
2040
ensure = false;
2041
}
2042
2043
this.ensured.splice((this.index + this.offset + 1), 0, ensure);
2044
this.blocks.splice((this.index + this.offset + 1), 0, block);
2045
this.offset++;
2046
};
2047
2048
jasmine.Queue.prototype.start = function(onComplete) {
2049
this.running = true;
2050
this.onComplete = onComplete;
2051
this.next_();
2052
};
2053
2054
jasmine.Queue.prototype.isRunning = function() {
2055
return this.running;
2056
};
2057
2058
jasmine.Queue.LOOP_DONT_RECURSE = true;
2059
2060
jasmine.Queue.prototype.next_ = function() {
2061
var self = this;
2062
var goAgain = true;
2063
2064
while (goAgain) {
2065
goAgain = false;
2066
2067
if (self.index < self.blocks.length && !(this.abort && !this.ensured[self.index])) {
2068
var calledSynchronously = true;
2069
var completedSynchronously = false;
2070
2071
var onComplete = function () {
2072
if (jasmine.Queue.LOOP_DONT_RECURSE && calledSynchronously) {
2073
completedSynchronously = true;
2074
return;
2075
}
2076
2077
if (self.blocks[self.index].abort) {
2078
self.abort = true;
2079
}
2080
2081
self.offset = 0;
2082
self.index++;
2083
2084
var now = new Date().getTime();
2085
if (self.env.updateInterval && now - self.env.lastUpdate > self.env.updateInterval) {
2086
self.env.lastUpdate = now;
2087
self.env.setTimeout(function() {
2088
self.next_();
2089
}, 0);
2090
} else {
2091
if (jasmine.Queue.LOOP_DONT_RECURSE && completedSynchronously) {
2092
goAgain = true;
2093
} else {
2094
self.next_();
2095
}
2096
}
2097
};
2098
self.blocks[self.index].execute(onComplete);
2099
2100
calledSynchronously = false;
2101
if (completedSynchronously) {
2102
onComplete();
2103
}
2104
2105
} else {
2106
self.running = false;
2107
if (self.onComplete) {
2108
self.onComplete();
2109
}
2110
}
2111
}
2112
};
2113
2114
jasmine.Queue.prototype.results = function() {
2115
var results = new jasmine.NestedResults();
2116
for (var i = 0; i < this.blocks.length; i++) {
2117
if (this.blocks[i].results) {
2118
results.addResult(this.blocks[i].results());
2119
}
2120
}
2121
return results;
2122
};
2123
2124
2125
/**
2126
* Runner
2127
*
2128
* @constructor
2129
* @param {jasmine.Env} env
2130
*/
2131
jasmine.Runner = function(env) {
2132
var self = this;
2133
self.env = env;
2134
self.queue = new jasmine.Queue(env);
2135
self.before_ = [];
2136
self.after_ = [];
2137
self.suites_ = [];
2138
};
2139
2140
jasmine.Runner.prototype.execute = function() {
2141
var self = this;
2142
if (self.env.reporter.reportRunnerStarting) {
2143
self.env.reporter.reportRunnerStarting(this);
2144
}
2145
self.queue.start(function () {
2146
self.finishCallback();
2147
});
2148
};
2149
2150
jasmine.Runner.prototype.beforeEach = function(beforeEachFunction) {
2151
beforeEachFunction.typeName = 'beforeEach';
2152
this.before_.splice(0,0,beforeEachFunction);
2153
};
2154
2155
jasmine.Runner.prototype.afterEach = function(afterEachFunction) {
2156
afterEachFunction.typeName = 'afterEach';
2157
this.after_.splice(0,0,afterEachFunction);
2158
};
2159
2160
2161
jasmine.Runner.prototype.finishCallback = function() {
2162
this.env.reporter.reportRunnerResults(this);
2163
};
2164
2165
jasmine.Runner.prototype.addSuite = function(suite) {
2166
this.suites_.push(suite);
2167
};
2168
2169
jasmine.Runner.prototype.add = function(block) {
2170
if (block instanceof jasmine.Suite) {
2171
this.addSuite(block);
2172
}
2173
this.queue.add(block);
2174
};
2175
2176
jasmine.Runner.prototype.specs = function () {
2177
var suites = this.suites();
2178
var specs = [];
2179
for (var i = 0; i < suites.length; i++) {
2180
specs = specs.concat(suites[i].specs());
2181
}
2182
return specs;
2183
};
2184
2185
jasmine.Runner.prototype.suites = function() {
2186
return this.suites_;
2187
};
2188
2189
jasmine.Runner.prototype.topLevelSuites = function() {
2190
var topLevelSuites = [];
2191
for (var i = 0; i < this.suites_.length; i++) {
2192
if (!this.suites_[i].parentSuite) {
2193
topLevelSuites.push(this.suites_[i]);
2194
}
2195
}
2196
return topLevelSuites;
2197
};
2198
2199
jasmine.Runner.prototype.results = function() {
2200
return this.queue.results();
2201
};
2202
/**
2203
* Internal representation of a Jasmine specification, or test.
2204
*
2205
* @constructor
2206
* @param {jasmine.Env} env
2207
* @param {jasmine.Suite} suite
2208
* @param {String} description
2209
*/
2210
jasmine.Spec = function(env, suite, description) {
2211
if (!env) {
2212
throw new Error('jasmine.Env() required');
2213
}
2214
if (!suite) {
2215
throw new Error('jasmine.Suite() required');
2216
}
2217
var spec = this;
2218
spec.id = env.nextSpecId ? env.nextSpecId() : null;
2219
spec.env = env;
2220
spec.suite = suite;
2221
spec.description = description;
2222
spec.queue = new jasmine.Queue(env);
2223
2224
spec.afterCallbacks = [];
2225
spec.spies_ = [];
2226
2227
spec.results_ = new jasmine.NestedResults();
2228
spec.results_.description = description;
2229
spec.matchersClass = null;
2230
};
2231
2232
jasmine.Spec.prototype.getFullName = function() {
2233
return this.suite.getFullName() + ' ' + this.description + '.';
2234
};
2235
2236
2237
jasmine.Spec.prototype.results = function() {
2238
return this.results_;
2239
};
2240
2241
/**
2242
* All parameters are pretty-printed and concatenated together, then written to the spec's output.
2243
*
2244
* Be careful not to leave calls to <code>jasmine.log</code> in production code.
2245
*/
2246
jasmine.Spec.prototype.log = function() {
2247
return this.results_.log(arguments);
2248
};
2249
2250
jasmine.Spec.prototype.runs = function (func) {
2251
var block = new jasmine.Block(this.env, func, this);
2252
this.addToQueue(block);
2253
return this;
2254
};
2255
2256
jasmine.Spec.prototype.addToQueue = function (block) {
2257
if (this.queue.isRunning()) {
2258
this.queue.insertNext(block);
2259
} else {
2260
this.queue.add(block);
2261
}
2262
};
2263
2264
/**
2265
* @param {jasmine.ExpectationResult} result
2266
*/
2267
jasmine.Spec.prototype.addMatcherResult = function(result) {
2268
this.results_.addResult(result);
2269
};
2270
2271
jasmine.Spec.prototype.expect = function(actual) {
2272
var positive = new (this.getMatchersClass_())(this.env, actual, this);
2273
positive.not = new (this.getMatchersClass_())(this.env, actual, this, true);
2274
return positive;
2275
};
2276
2277
/**
2278
* Waits a fixed time period before moving to the next block.
2279
*
2280
* @deprecated Use waitsFor() instead
2281
* @param {Number} timeout milliseconds to wait
2282
*/
2283
jasmine.Spec.prototype.waits = function(timeout) {
2284
var waitsFunc = new jasmine.WaitsBlock(this.env, timeout, this);
2285
this.addToQueue(waitsFunc);
2286
return this;
2287
};
2288
2289
/**
2290
* Waits for the latchFunction to return true before proceeding to the next block.
2291
*
2292
* @param {Function} latchFunction
2293
* @param {String} optional_timeoutMessage
2294
* @param {Number} optional_timeout
2295
*/
2296
jasmine.Spec.prototype.waitsFor = function(latchFunction, optional_timeoutMessage, optional_timeout) {
2297
var latchFunction_ = null;
2298
var optional_timeoutMessage_ = null;
2299
var optional_timeout_ = null;
2300
2301
for (var i = 0; i < arguments.length; i++) {
2302
var arg = arguments[i];
2303
switch (typeof arg) {
2304
case 'function':
2305
latchFunction_ = arg;
2306
break;
2307
case 'string':
2308
optional_timeoutMessage_ = arg;
2309
break;
2310
case 'number':
2311
optional_timeout_ = arg;
2312
break;
2313
}
2314
}
2315
2316
var waitsForFunc = new jasmine.WaitsForBlock(this.env, optional_timeout_, latchFunction_, optional_timeoutMessage_, this);
2317
this.addToQueue(waitsForFunc);
2318
return this;
2319
};
2320
2321
jasmine.Spec.prototype.fail = function (e) {
2322
var expectationResult = new jasmine.ExpectationResult({
2323
passed: false,
2324
message: e ? jasmine.util.formatException(e) : 'Exception',
2325
trace: { stack: e.stack }
2326
});
2327
this.results_.addResult(expectationResult);
2328
};
2329
2330
jasmine.Spec.prototype.getMatchersClass_ = function() {
2331
return this.matchersClass || this.env.matchersClass;
2332
};
2333
2334
jasmine.Spec.prototype.addMatchers = function(matchersPrototype) {
2335
var parent = this.getMatchersClass_();
2336
var newMatchersClass = function() {
2337
parent.apply(this, arguments);
2338
};
2339
jasmine.util.inherit(newMatchersClass, parent);
2340
jasmine.Matchers.wrapInto_(matchersPrototype, newMatchersClass);
2341
this.matchersClass = newMatchersClass;
2342
};
2343
2344
jasmine.Spec.prototype.finishCallback = function() {
2345
this.env.reporter.reportSpecResults(this);
2346
};
2347
2348
jasmine.Spec.prototype.finish = function(onComplete) {
2349
this.removeAllSpies();
2350
this.finishCallback();
2351
if (onComplete) {
2352
onComplete();
2353
}
2354
};
2355
2356
jasmine.Spec.prototype.after = function(doAfter) {
2357
if (this.queue.isRunning()) {
2358
this.queue.add(new jasmine.Block(this.env, doAfter, this), true);
2359
} else {
2360
this.afterCallbacks.unshift(doAfter);
2361
}
2362
};
2363
2364
jasmine.Spec.prototype.execute = function(onComplete) {
2365
var spec = this;
2366
if (!spec.env.specFilter(spec)) {
2367
spec.results_.skipped = true;
2368
spec.finish(onComplete);
2369
return;
2370
}
2371
2372
this.env.reporter.reportSpecStarting(this);
2373
2374
spec.env.currentSpec = spec;
2375
2376
spec.addBeforesAndAftersToQueue();
2377
2378
spec.queue.start(function () {
2379
spec.finish(onComplete);
2380
});
2381
};
2382
2383
jasmine.Spec.prototype.addBeforesAndAftersToQueue = function() {
2384
var runner = this.env.currentRunner();
2385
var i;
2386
2387
for (var suite = this.suite; suite; suite = suite.parentSuite) {
2388
for (i = 0; i < suite.before_.length; i++) {
2389
this.queue.addBefore(new jasmine.Block(this.env, suite.before_[i], this));
2390
}
2391
}
2392
for (i = 0; i < runner.before_.length; i++) {
2393
this.queue.addBefore(new jasmine.Block(this.env, runner.before_[i], this));
2394
}
2395
for (i = 0; i < this.afterCallbacks.length; i++) {
2396
this.queue.add(new jasmine.Block(this.env, this.afterCallbacks[i], this), true);
2397
}
2398
for (suite = this.suite; suite; suite = suite.parentSuite) {
2399
for (i = 0; i < suite.after_.length; i++) {
2400
this.queue.add(new jasmine.Block(this.env, suite.after_[i], this), true);
2401
}
2402
}
2403
for (i = 0; i < runner.after_.length; i++) {
2404
this.queue.add(new jasmine.Block(this.env, runner.after_[i], this), true);
2405
}
2406
};
2407
2408
jasmine.Spec.prototype.explodes = function() {
2409
throw 'explodes function should not have been called';
2410
};
2411
2412
jasmine.Spec.prototype.spyOn = function(obj, methodName, ignoreMethodDoesntExist) {
2413
if (obj == jasmine.undefined) {
2414
throw "spyOn could not find an object to spy upon for " + methodName + "()";
2415
}
2416
2417
if (!ignoreMethodDoesntExist && obj[methodName] === jasmine.undefined) {
2418
throw methodName + '() method does not exist';
2419
}
2420
2421
if (!ignoreMethodDoesntExist && obj[methodName] && obj[methodName].isSpy) {
2422
throw new Error(methodName + ' has already been spied upon');
2423
}
2424
2425
var spyObj = jasmine.createSpy(methodName);
2426
2427
this.spies_.push(spyObj);
2428
spyObj.baseObj = obj;
2429
spyObj.methodName = methodName;
2430
spyObj.originalValue = obj[methodName];
2431
2432
obj[methodName] = spyObj;
2433
2434
return spyObj;
2435
};
2436
2437
jasmine.Spec.prototype.removeAllSpies = function() {
2438
for (var i = 0; i < this.spies_.length; i++) {
2439
var spy = this.spies_[i];
2440
spy.baseObj[spy.methodName] = spy.originalValue;
2441
}
2442
this.spies_ = [];
2443
};
2444
2445
/**
2446
* Internal representation of a Jasmine suite.
2447
*
2448
* @constructor
2449
* @param {jasmine.Env} env
2450
* @param {String} description
2451
* @param {Function} specDefinitions
2452
* @param {jasmine.Suite} parentSuite
2453
*/
2454
jasmine.Suite = function(env, description, specDefinitions, parentSuite) {
2455
var self = this;
2456
self.id = env.nextSuiteId ? env.nextSuiteId() : null;
2457
self.description = description;
2458
self.queue = new jasmine.Queue(env);
2459
self.parentSuite = parentSuite;
2460
self.env = env;
2461
self.before_ = [];
2462
self.after_ = [];
2463
self.children_ = [];
2464
self.suites_ = [];
2465
self.specs_ = [];
2466
};
2467
2468
jasmine.Suite.prototype.getFullName = function() {
2469
var fullName = this.description;
2470
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
2471
fullName = parentSuite.description + ' ' + fullName;
2472
}
2473
return fullName;
2474
};
2475
2476
jasmine.Suite.prototype.finish = function(onComplete) {
2477
this.env.reporter.reportSuiteResults(this);
2478
this.finished = true;
2479
if (typeof(onComplete) == 'function') {
2480
onComplete();
2481
}
2482
};
2483
2484
jasmine.Suite.prototype.beforeEach = function(beforeEachFunction) {
2485
beforeEachFunction.typeName = 'beforeEach';
2486
this.before_.unshift(beforeEachFunction);
2487
};
2488
2489
jasmine.Suite.prototype.afterEach = function(afterEachFunction) {
2490
afterEachFunction.typeName = 'afterEach';
2491
this.after_.unshift(afterEachFunction);
2492
};
2493
2494
jasmine.Suite.prototype.results = function() {
2495
return this.queue.results();
2496
};
2497
2498
jasmine.Suite.prototype.add = function(suiteOrSpec) {
2499
this.children_.push(suiteOrSpec);
2500
if (suiteOrSpec instanceof jasmine.Suite) {
2501
this.suites_.push(suiteOrSpec);
2502
this.env.currentRunner().addSuite(suiteOrSpec);
2503
} else {
2504
this.specs_.push(suiteOrSpec);
2505
}
2506
this.queue.add(suiteOrSpec);
2507
};
2508
2509
jasmine.Suite.prototype.specs = function() {
2510
return this.specs_;
2511
};
2512
2513
jasmine.Suite.prototype.suites = function() {
2514
return this.suites_;
2515
};
2516
2517
jasmine.Suite.prototype.children = function() {
2518
return this.children_;
2519
};
2520
2521
jasmine.Suite.prototype.execute = function(onComplete) {
2522
var self = this;
2523
this.queue.start(function () {
2524
self.finish(onComplete);
2525
});
2526
};
2527
jasmine.WaitsBlock = function(env, timeout, spec) {
2528
this.timeout = timeout;
2529
jasmine.Block.call(this, env, null, spec);
2530
};
2531
2532
jasmine.util.inherit(jasmine.WaitsBlock, jasmine.Block);
2533
2534
jasmine.WaitsBlock.prototype.execute = function (onComplete) {
2535
if (jasmine.VERBOSE) {
2536
this.env.reporter.log('>> Jasmine waiting for ' + this.timeout + ' ms...');
2537
}
2538
this.env.setTimeout(function () {
2539
onComplete();
2540
}, this.timeout);
2541
};
2542
/**
2543
* A block which waits for some condition to become true, with timeout.
2544
*
2545
* @constructor
2546
* @extends jasmine.Block
2547
* @param {jasmine.Env} env The Jasmine environment.
2548
* @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
2549
* @param {Function} latchFunction A function which returns true when the desired condition has been met.
2550
* @param {String} message The message to display if the desired condition hasn't been met within the given time period.
2551
* @param {jasmine.Spec} spec The Jasmine spec.
2552
*/
2553
jasmine.WaitsForBlock = function(env, timeout, latchFunction, message, spec) {
2554
this.timeout = timeout || env.defaultTimeoutInterval;
2555
this.latchFunction = latchFunction;
2556
this.message = message;
2557
this.totalTimeSpentWaitingForLatch = 0;
2558
jasmine.Block.call(this, env, null, spec);
2559
};
2560
jasmine.util.inherit(jasmine.WaitsForBlock, jasmine.Block);
2561
2562
jasmine.WaitsForBlock.TIMEOUT_INCREMENT = 10;
2563
2564
jasmine.WaitsForBlock.prototype.execute = function(onComplete) {
2565
if (jasmine.VERBOSE) {
2566
this.env.reporter.log('>> Jasmine waiting for ' + (this.message || 'something to happen'));
2567
}
2568
var latchFunctionResult;
2569
try {
2570
latchFunctionResult = this.latchFunction.apply(this.spec);
2571
} catch (e) {
2572
this.spec.fail(e);
2573
onComplete();
2574
return;
2575
}
2576
2577
if (latchFunctionResult) {
2578
onComplete();
2579
} else if (this.totalTimeSpentWaitingForLatch >= this.timeout) {
2580
var message = 'timed out after ' + this.timeout + ' msec waiting for ' + (this.message || 'something to happen');
2581
this.spec.fail({
2582
name: 'timeout',
2583
message: message
2584
});
2585
2586
this.abort = true;
2587
onComplete();
2588
} else {
2589
this.totalTimeSpentWaitingForLatch += jasmine.WaitsForBlock.TIMEOUT_INCREMENT;
2590
var self = this;
2591
this.env.setTimeout(function() {
2592
self.execute(onComplete);
2593
}, jasmine.WaitsForBlock.TIMEOUT_INCREMENT);
2594
}
2595
};
2596
2597
jasmine.version_= {
2598
"major": 1,
2599
"minor": 3,
2600
"build": 0,
2601
"revision": 1354052693
2602
};
2603
2604