1 var isCommonJS
= typeof window
== "undefined";
4 * Top level namespace for Jasmine, a lightweight JavaScript BDD/spec/testing framework.
9 if (isCommonJS
) exports
.jasmine
= jasmine
;
13 jasmine
.unimplementedMethod_ = function() {
14 throw new Error("unimplemented method");
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.
23 jasmine
.undefined = jasmine
.___undefined___
;
26 * Show diagnostic messages in the console if set to true
29 jasmine
.VERBOSE
= false;
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.
35 jasmine
.DEFAULT_UPDATE_INTERVAL
= 250;
38 * Default timeout interval in milliseconds for waitsFor() blocks.
40 jasmine
.DEFAULT_TIMEOUT_INTERVAL
= 5000;
42 jasmine
.getGlobal = function() {
43 function getGlobal() {
51 * Allows for bound functions to be compared. Internal use only.
55 * @param base {Object} bound 'this' for the function
56 * @param name {Function} function to find
58 jasmine
.bindOriginal_ = function(base
, name
) {
59 var original
= base
[name
];
62 return original
.apply(base
, arguments
);
66 return jasmine
.getGlobal()[name
];
70 jasmine
.setTimeout
= jasmine
.bindOriginal_(jasmine
.getGlobal(), 'setTimeout');
71 jasmine
.clearTimeout
= jasmine
.bindOriginal_(jasmine
.getGlobal(), 'clearTimeout');
72 jasmine
.setInterval
= jasmine
.bindOriginal_(jasmine
.getGlobal(), 'setInterval');
73 jasmine
.clearInterval
= jasmine
.bindOriginal_(jasmine
.getGlobal(), 'clearInterval');
75 jasmine
.MessageResult = function(values
) {
78 this.trace
= new Error(); // todo: test better
81 jasmine
.MessageResult
.prototype.toString = function() {
83 for (var i
= 0; i
< this.values
.length
; i
++) {
84 if (i
> 0) text
+= " ";
85 if (jasmine
.isString_(this.values
[i
])) {
86 text
+= this.values
[i
];
88 text
+= jasmine
.pp(this.values
[i
]);
94 jasmine
.ExpectationResult = function(params
) {
96 this.matcherName
= params
.matcherName
;
97 this.passed_
= params
.passed
;
98 this.expected
= params
.expected
;
99 this.actual
= params
.actual
;
100 this.message
= this.passed_
? 'Passed.' : params
.message
;
102 var trace
= (params
.trace
|| new Error(this.message
));
103 this.trace
= this.passed_
? '' : trace
;
106 jasmine
.ExpectationResult
.prototype.toString = function () {
110 jasmine
.ExpectationResult
.prototype.passed = function () {
115 * Getter for the Jasmine environment. Ensures one gets created
117 jasmine
.getEnv = function() {
118 var env
= jasmine
.currentEnv_
= jasmine
.currentEnv_
|| new jasmine
.Env();
128 jasmine
.isArray_ = function(value
) {
129 return jasmine
.isA_("Array", value
);
138 jasmine
.isString_ = function(value
) {
139 return jasmine
.isA_("String", value
);
148 jasmine
.isNumber_ = function(value
) {
149 return jasmine
.isA_("Number", value
);
155 * @param {String} typeName
159 jasmine
.isA_ = function(typeName
, value
) {
160 return Object
.prototype.toString
.apply(value
) === '[object ' + typeName
+ ']';
164 * Pretty printer for expecations. Takes any object and turns it into a human-readable string.
166 * @param value {Object} an object to be outputted
169 jasmine
.pp = function(value
) {
170 var stringPrettyPrinter
= new jasmine
.StringPrettyPrinter();
171 stringPrettyPrinter
.format(value
);
172 return stringPrettyPrinter
.string
;
176 * Returns true if the object is a DOM Node.
178 * @param {Object} obj object to check
181 jasmine
.isDomNode = function(obj
) {
182 return obj
.nodeType
> 0;
186 * Returns a matchable 'generic' object of the class type. For use in expecations of type when values don't matter.
189 * // don't care about which function is passed in, as long as it's a function
190 * expect(mySpy).toHaveBeenCalledWith(jasmine.any(Function));
192 * @param {Class} clazz
193 * @returns matchable object of the type clazz
195 jasmine
.any = function(clazz
) {
196 return new jasmine
.Matchers
.Any(clazz
);
200 * Jasmine Spies are test doubles that can act as stubs, spies, fakes or when used in an expecation, mocks.
202 * Spies should be created in test setup, before expectations. They can then be checked, using the standard Jasmine
203 * expectation syntax. Spies can be checked if they were called or not and what the calling params were.
205 * A Spy has the following fields: wasCalled, callCount, mostRecentCall, and argsForCall (see docs).
207 * Spies are torn down at the end of every spec.
209 * Note: Do <b>not</b> call new jasmine.Spy() directly - a spy must be created using spyOn, jasmine.createSpy or jasmine.createSpyObj.
213 * var myStub = jasmine.createSpy('myStub'); // can be used anywhere
217 * not: function(bool) { return !bool; }
220 * // actual foo.not will not be called, execution stops
223 // foo.not spied upon, execution will continue to implementation
224 * spyOn(foo, 'not').andCallThrough();
228 * not: function(bool) { return !bool; }
231 * // foo.not(val) will return val
232 * spyOn(foo, 'not').andCallFake(function(value) {return value;});
236 * expect(foo.not).toHaveBeenCalled();
237 * expect(foo.not).toHaveBeenCalledWith(true);
240 * @see spyOn, jasmine.createSpy, jasmine.createSpyObj
241 * @param {String} name
243 jasmine
.Spy = function(name
) {
245 * The name of the spy, if provided.
247 this.identity
= name
|| 'unknown';
249 * Is this Object a spy?
253 * The actual function this spy stubs.
255 this.plan = function() {
258 * Tracking of the most recent call to the spy.
260 * var mySpy = jasmine.createSpy('foo');
262 * mySpy.mostRecentCall.args = [1, 2];
264 this.mostRecentCall
= {};
267 * Holds arguments for each call to the spy, indexed by call count
269 * var mySpy = jasmine.createSpy('foo');
272 * mySpy.mostRecentCall.args = [7, 8];
273 * mySpy.argsForCall[0] = [1, 2];
274 * mySpy.argsForCall[1] = [7, 8];
276 this.argsForCall
= [];
281 * Tells a spy to call through to the actual implemenatation.
285 * bar: function() { // do some stuff }
288 * // defining a spy on an existing property: foo.bar
289 * spyOn(foo, 'bar').andCallThrough();
291 jasmine
.Spy
.prototype.andCallThrough = function() {
292 this.plan
= this.originalValue
;
297 * For setting the return value of a spy.
300 * // defining a spy from scratch: foo() returns 'baz'
301 * var foo = jasmine.createSpy('spy on foo').andReturn('baz');
303 * // defining a spy on an existing property: foo.bar() returns 'baz'
304 * spyOn(foo, 'bar').andReturn('baz');
306 * @param {Object} value
308 jasmine
.Spy
.prototype.andReturn = function(value
) {
309 this.plan = function() {
316 * For throwing an exception when a spy is called.
319 * // defining a spy from scratch: foo() throws an exception w/ message 'ouch'
320 * var foo = jasmine.createSpy('spy on foo').andThrow('baz');
322 * // defining a spy on an existing property: foo.bar() throws an exception w/ message 'ouch'
323 * spyOn(foo, 'bar').andThrow('baz');
325 * @param {String} exceptionMsg
327 jasmine
.Spy
.prototype.andThrow = function(exceptionMsg
) {
328 this.plan = function() {
335 * Calls an alternate implementation when a spy is called.
338 * var baz = function() {
339 * // do some stuff, return something
341 * // defining a spy from scratch: foo() calls the function baz
342 * var foo = jasmine.createSpy('spy on foo').andCall(baz);
344 * // defining a spy on an existing property: foo.bar() calls an anonymnous function
345 * spyOn(foo, 'bar').andCall(function() { return 'baz';} );
347 * @param {Function} fakeFunc
349 jasmine
.Spy
.prototype.andCallFake = function(fakeFunc
) {
350 this.plan
= fakeFunc
;
355 * Resets all of a spy's the tracking variables so that it can be used again.
362 * expect(foo.bar.callCount).toEqual(1);
366 * expect(foo.bar.callCount).toEqual(0);
368 jasmine
.Spy
.prototype.reset = function() {
369 this.wasCalled
= false;
371 this.argsForCall
= [];
373 this.mostRecentCall
= {};
376 jasmine
.createSpy = function(name
) {
378 var spyObj = function() {
379 spyObj
.wasCalled
= true;
381 var args
= jasmine
.util
.argsToArray(arguments
);
382 spyObj
.mostRecentCall
.object
= this;
383 spyObj
.mostRecentCall
.args
= args
;
384 spyObj
.argsForCall
.push(args
);
385 spyObj
.calls
.push({object
: this, args
: args
});
386 return spyObj
.plan
.apply(this, arguments
);
389 var spy
= new jasmine
.Spy(name
);
391 for (var prop
in spy
) {
392 spyObj
[prop
] = spy
[prop
];
401 * Determines whether an object is a spy.
403 * @param {jasmine.Spy|Object} putativeSpy
406 jasmine
.isSpy = function(putativeSpy
) {
407 return putativeSpy
&& putativeSpy
.isSpy
;
411 * Creates a more complicated spy: an Object that has every property a function that is a spy. Used for stubbing something
414 * @param {String} baseName name of spy class
415 * @param {Array} methodNames array of names of methods to make spies
417 jasmine
.createSpyObj = function(baseName
, methodNames
) {
418 if (!jasmine
.isArray_(methodNames
) || methodNames
.length
=== 0) {
419 throw new Error('createSpyObj requires a non-empty array of method names to create spies for');
422 for (var i
= 0; i
< methodNames
.length
; i
++) {
423 obj
[methodNames
[i
]] = jasmine
.createSpy(baseName
+ '.' + methodNames
[i
]);
429 * All parameters are pretty-printed and concatenated together, then written to the current spec's output.
431 * Be careful not to leave calls to <code>jasmine.log</code> in production code.
433 jasmine
.log = function() {
434 var spec
= jasmine
.getEnv().currentSpec
;
435 spec
.log
.apply(spec
, arguments
);
439 * Function that installs a spy on an existing object's method name. Used within a Spec to create a spy.
444 * not: function(bool) { return !bool; }
446 * spyOn(foo, 'not'); // actual foo.not will not be called, execution stops
448 * @see jasmine.createSpy
451 * @returns a Jasmine spy that can be chained with all spy methods
453 var spyOn = function(obj
, methodName
) {
454 return jasmine
.getEnv().currentSpec
.spyOn(obj
, methodName
);
456 if (isCommonJS
) exports
.spyOn
= spyOn
;
459 * Creates a Jasmine spec that will be added to the current suite.
461 * // TODO: pending tests
464 * it('should be true', function() {
465 * expect(true).toEqual(true);
468 * @param {String} desc description of this specification
469 * @param {Function} func defines the preconditions and expectations of the spec
471 var it = function(desc
, func
) {
472 return jasmine
.getEnv().it(desc
, func
);
474 if (isCommonJS
) exports
.it
= it
;
477 * Creates a <em>disabled</em> Jasmine spec.
479 * A convenience method that allows existing specs to be disabled temporarily during development.
481 * @param {String} desc description of this specification
482 * @param {Function} func defines the preconditions and expectations of the spec
484 var xit = function(desc
, func
) {
485 return jasmine
.getEnv().xit(desc
, func
);
487 if (isCommonJS
) exports
.xit
= xit
;
490 * Starts a chain for a Jasmine expectation.
492 * It is passed an Object that is the actual value and should chain to one of the many
493 * jasmine.Matchers functions.
495 * @param {Object} actual Actual value to test against and expected value
497 var expect = function(actual
) {
498 return jasmine
.getEnv().currentSpec
.expect(actual
);
500 if (isCommonJS
) exports
.expect
= expect
;
503 * Defines part of a jasmine spec. Used in cominbination with waits or waitsFor in asynchrnous specs.
505 * @param {Function} func Function that defines part of a jasmine spec.
507 var runs = function(func
) {
508 jasmine
.getEnv().currentSpec
.runs(func
);
510 if (isCommonJS
) exports
.runs
= runs
;
513 * Waits a fixed time period before moving to the next block.
515 * @deprecated Use waitsFor() instead
516 * @param {Number} timeout milliseconds to wait
518 var waits = function(timeout
) {
519 jasmine
.getEnv().currentSpec
.waits(timeout
);
521 if (isCommonJS
) exports
.waits
= waits
;
524 * Waits for the latchFunction to return true before proceeding to the next block.
526 * @param {Function} latchFunction
527 * @param {String} optional_timeoutMessage
528 * @param {Number} optional_timeout
530 var waitsFor = function(latchFunction
, optional_timeoutMessage
, optional_timeout
) {
531 jasmine
.getEnv().currentSpec
.waitsFor
.apply(jasmine
.getEnv().currentSpec
, arguments
);
533 if (isCommonJS
) exports
.waitsFor
= waitsFor
;
536 * A function that is called before each spec in a suite.
538 * Used for spec setup, including validating assumptions.
540 * @param {Function} beforeEachFunction
542 var beforeEach = function(beforeEachFunction
) {
543 jasmine
.getEnv().beforeEach(beforeEachFunction
);
545 if (isCommonJS
) exports
.beforeEach
= beforeEach
;
548 * A function that is called after each spec in a suite.
550 * Used for restoring any state that is hijacked during spec execution.
552 * @param {Function} afterEachFunction
554 var afterEach = function(afterEachFunction
) {
555 jasmine
.getEnv().afterEach(afterEachFunction
);
557 if (isCommonJS
) exports
.afterEach
= afterEach
;
560 * Defines a suite of specifications.
562 * Stores the description and all defined specs in the Jasmine environment as one suite of specs. Variables declared
563 * are accessible by calls to beforeEach, it, and afterEach. Describe blocks can be nested, allowing for specialization
564 * of setup in some tests.
567 * // TODO: a simple suite
569 * // TODO: a simple suite with a nested describe block
571 * @param {String} description A string, usually the class under test.
572 * @param {Function} specDefinitions function that defines several specs.
574 var describe = function(description
, specDefinitions
) {
575 return jasmine
.getEnv().describe(description
, specDefinitions
);
577 if (isCommonJS
) exports
.describe
= describe
;
580 * Disables a suite of specifications. Used to disable some suites in a file, or files, temporarily during development.
582 * @param {String} description A string, usually the class under test.
583 * @param {Function} specDefinitions function that defines several specs.
585 var xdescribe = function(description
, specDefinitions
) {
586 return jasmine
.getEnv().xdescribe(description
, specDefinitions
);
588 if (isCommonJS
) exports
.xdescribe
= xdescribe
;
591 // Provide the XMLHttpRequest class for IE 5.x-6.x:
592 jasmine
.XmlHttpRequest
= (typeof XMLHttpRequest
== "undefined") ? function() {
601 var xhr
= tryIt(function() {
602 return new ActiveXObject("Msxml2.XMLHTTP.6.0");
605 return new ActiveXObject("Msxml2.XMLHTTP.3.0");
608 return new ActiveXObject("Msxml2.XMLHTTP");
611 return new ActiveXObject("Microsoft.XMLHTTP");
614 if (!xhr
) throw new Error("This browser does not support XMLHttpRequest.");
624 * Declare that a child class inherit it's prototype from the parent class.
627 * @param {Function} childClass
628 * @param {Function} parentClass
630 jasmine
.util
.inherit = function(childClass
, parentClass
) {
634 var subclass = function() {
636 subclass
.prototype = parentClass
.prototype;
637 childClass
.prototype = new subclass();
640 jasmine
.util
.formatException = function(e
) {
645 else if (e
.lineNumber
) {
646 lineNumber
= e
.lineNumber
;
654 else if (e
.fileName
) {
658 var message
= (e
.name
&& e
.message
) ? (e
.name
+ ': ' + e
.message
) : e
.toString();
660 if (file
&& lineNumber
) {
661 message
+= ' in ' + file
+ ' (line ' + lineNumber
+ ')';
667 jasmine
.util
.htmlEscape = function(str
) {
668 if (!str
) return str
;
669 return str
.replace(/&/g
, '&')
670 .replace(/</g
, '<')
671 .replace(/>/g
, '>');
674 jasmine
.util
.argsToArray = function(args
) {
675 var arrayOfArgs
= [];
676 for (var i
= 0; i
< args
.length
; i
++) arrayOfArgs
.push(args
[i
]);
680 jasmine
.util
.extend = function(destination
, source
) {
681 for (var property
in source
) destination
[property
] = source
[property
];
686 * Environment for Jasmine
690 jasmine
.Env = function() {
691 this.currentSpec
= null;
692 this.currentSuite
= null;
693 this.currentRunner_
= new jasmine
.Runner(this);
695 this.reporter
= new jasmine
.MultiReporter();
697 this.updateInterval
= jasmine
.DEFAULT_UPDATE_INTERVAL
;
698 this.defaultTimeoutInterval
= jasmine
.DEFAULT_TIMEOUT_INTERVAL
;
700 this.specFilter = function() {
704 this.nextSpecId_
= 0;
705 this.nextSuiteId_
= 0;
706 this.equalityTesters_
= [];
709 this.matchersClass = function() {
710 jasmine
.Matchers
.apply(this, arguments
);
712 jasmine
.util
.inherit(this.matchersClass
, jasmine
.Matchers
);
714 jasmine
.Matchers
.wrapInto_(jasmine
.Matchers
.prototype, this.matchersClass
);
718 jasmine
.Env
.prototype.setTimeout
= jasmine
.setTimeout
;
719 jasmine
.Env
.prototype.clearTimeout
= jasmine
.clearTimeout
;
720 jasmine
.Env
.prototype.setInterval
= jasmine
.setInterval
;
721 jasmine
.Env
.prototype.clearInterval
= jasmine
.clearInterval
;
724 * @returns an object containing jasmine version build info, if set.
726 jasmine
.Env
.prototype.version = function () {
727 if (jasmine
.version_
) {
728 return jasmine
.version_
;
730 throw new Error('Version not set');
735 * @returns string containing jasmine version build info, if set.
737 jasmine
.Env
.prototype.versionString = function() {
738 if (!jasmine
.version_
) {
739 return "version unknown";
742 var version
= this.version();
743 var versionString
= version
.major
+ "." + version
.minor
+ "." + version
.build
;
744 if (version
.release_candidate
) {
745 versionString
+= ".rc" + version
.release_candidate
747 versionString
+= " revision " + version
.revision
;
748 return versionString
;
752 * @returns a sequential integer starting at 0
754 jasmine
.Env
.prototype.nextSpecId = function () {
755 return this.nextSpecId_
++;
759 * @returns a sequential integer starting at 0
761 jasmine
.Env
.prototype.nextSuiteId = function () {
762 return this.nextSuiteId_
++;
766 * Register a reporter to receive status updates from Jasmine.
767 * @param {jasmine.Reporter} reporter An object which will receive status updates.
769 jasmine
.Env
.prototype.addReporter = function(reporter
) {
770 this.reporter
.addReporter(reporter
);
773 jasmine
.Env
.prototype.execute = function() {
774 this.currentRunner_
.execute();
777 jasmine
.Env
.prototype.describe = function(description
, specDefinitions
) {
778 var suite
= new jasmine
.Suite(this, description
, specDefinitions
, this.currentSuite
);
780 var parentSuite
= this.currentSuite
;
782 parentSuite
.add(suite
);
784 this.currentRunner_
.add(suite
);
787 this.currentSuite
= suite
;
789 var declarationError
= null;
791 specDefinitions
.call(suite
);
793 declarationError
= e
;
796 if (declarationError
) {
797 this.it("encountered a declaration exception", function() {
798 throw declarationError
;
802 this.currentSuite
= parentSuite
;
807 jasmine
.Env
.prototype.beforeEach = function(beforeEachFunction
) {
808 if (this.currentSuite
) {
809 this.currentSuite
.beforeEach(beforeEachFunction
);
811 this.currentRunner_
.beforeEach(beforeEachFunction
);
815 jasmine
.Env
.prototype.currentRunner = function () {
816 return this.currentRunner_
;
819 jasmine
.Env
.prototype.afterEach = function(afterEachFunction
) {
820 if (this.currentSuite
) {
821 this.currentSuite
.afterEach(afterEachFunction
);
823 this.currentRunner_
.afterEach(afterEachFunction
);
828 jasmine
.Env
.prototype.xdescribe = function(desc
, specDefinitions
) {
830 execute: function() {
835 jasmine
.Env
.prototype.it = function(description
, func
) {
836 var spec
= new jasmine
.Spec(this, this.currentSuite
, description
);
837 this.currentSuite
.add(spec
);
838 this.currentSpec
= spec
;
847 jasmine
.Env
.prototype.xit = function(desc
, func
) {
849 id
: this.nextSpecId(),
855 jasmine
.Env
.prototype.compareObjects_ = function(a
, b
, mismatchKeys
, mismatchValues
) {
856 if (a
.__Jasmine_been_here_before__
=== b
&& b
.__Jasmine_been_here_before__
=== a
) {
860 a
.__Jasmine_been_here_before__
= b
;
861 b
.__Jasmine_been_here_before__
= a
;
863 var hasKey = function(obj
, keyName
) {
864 return obj
!== null && obj
[keyName
] !== jasmine
.undefined;
867 for (var property
in b
) {
868 if (!hasKey(a
, property
) && hasKey(b
, property
)) {
869 mismatchKeys
.push("expected has key '" + property
+ "', but missing from actual.");
872 for (property
in a
) {
873 if (!hasKey(b
, property
) && hasKey(a
, property
)) {
874 mismatchKeys
.push("expected missing key '" + property
+ "', but present in actual.");
877 for (property
in b
) {
878 if (property
== '__Jasmine_been_here_before__') continue;
879 if (!this.equals_(a
[property
], b
[property
], mismatchKeys
, mismatchValues
)) {
880 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.");
884 if (jasmine
.isArray_(a
) && jasmine
.isArray_(b
) && a
.length
!= b
.length
) {
885 mismatchValues
.push("arrays were not the same length");
888 delete a
.__Jasmine_been_here_before__
;
889 delete b
.__Jasmine_been_here_before__
;
890 return (mismatchKeys
.length
=== 0 && mismatchValues
.length
=== 0);
893 jasmine
.Env
.prototype.equals_ = function(a
, b
, mismatchKeys
, mismatchValues
) {
894 mismatchKeys
= mismatchKeys
|| [];
895 mismatchValues
= mismatchValues
|| [];
897 for (var i
= 0; i
< this.equalityTesters_
.length
; i
++) {
898 var equalityTester
= this.equalityTesters_
[i
];
899 var result
= equalityTester(a
, b
, this, mismatchKeys
, mismatchValues
);
900 if (result
!== jasmine
.undefined) return result
;
903 if (a
=== b
) return true;
905 if (a
=== jasmine
.undefined || a
=== null || b
=== jasmine
.undefined || b
=== null) {
906 return (a
== jasmine
.undefined && b
== jasmine
.undefined);
909 if (jasmine
.isDomNode(a
) && jasmine
.isDomNode(b
)) {
913 if (a
instanceof Date
&& b
instanceof Date
) {
914 return a
.getTime() == b
.getTime();
917 if (a
instanceof jasmine
.Matchers
.Any
) {
921 if (b
instanceof jasmine
.Matchers
.Any
) {
925 if (jasmine
.isString_(a
) && jasmine
.isString_(b
)) {
929 if (jasmine
.isNumber_(a
) && jasmine
.isNumber_(b
)) {
933 if (typeof a
=== "object" && typeof b
=== "object") {
934 return this.compareObjects_(a
, b
, mismatchKeys
, mismatchValues
);
941 jasmine
.Env
.prototype.contains_ = function(haystack
, needle
) {
942 if (jasmine
.isArray_(haystack
)) {
943 for (var i
= 0; i
< haystack
.length
; i
++) {
944 if (this.equals_(haystack
[i
], needle
)) return true;
948 return haystack
.indexOf(needle
) >= 0;
951 jasmine
.Env
.prototype.addEqualityTester = function(equalityTester
) {
952 this.equalityTesters_
.push(equalityTester
);
954 /** No-op base class for Jasmine reporters.
958 jasmine
.Reporter = function() {
961 //noinspection JSUnusedLocalSymbols
962 jasmine
.Reporter
.prototype.reportRunnerStarting = function(runner
) {
965 //noinspection JSUnusedLocalSymbols
966 jasmine
.Reporter
.prototype.reportRunnerResults = function(runner
) {
969 //noinspection JSUnusedLocalSymbols
970 jasmine
.Reporter
.prototype.reportSuiteResults = function(suite
) {
973 //noinspection JSUnusedLocalSymbols
974 jasmine
.Reporter
.prototype.reportSpecStarting = function(spec
) {
977 //noinspection JSUnusedLocalSymbols
978 jasmine
.Reporter
.prototype.reportSpecResults = function(spec
) {
981 //noinspection JSUnusedLocalSymbols
982 jasmine
.Reporter
.prototype.log = function(str
) {
986 * Blocks are functions with executable code that make up a spec.
989 * @param {jasmine.Env} env
990 * @param {Function} func
991 * @param {jasmine.Spec} spec
993 jasmine
.Block = function(env
, func
, spec
) {
999 jasmine
.Block
.prototype.execute = function(onComplete
) {
1001 this.func
.apply(this.spec
);
1007 /** JavaScript API reporter.
1011 jasmine
.JsApiReporter = function() {
1012 this.started
= false;
1013 this.finished
= false;
1018 jasmine
.JsApiReporter
.prototype.reportRunnerStarting = function(runner
) {
1019 this.started
= true;
1020 var suites
= runner
.topLevelSuites();
1021 for (var i
= 0; i
< suites
.length
; i
++) {
1022 var suite
= suites
[i
];
1023 this.suites_
.push(this.summarize_(suite
));
1027 jasmine
.JsApiReporter
.prototype.suites = function() {
1028 return this.suites_
;
1031 jasmine
.JsApiReporter
.prototype.summarize_ = function(suiteOrSpec
) {
1032 var isSuite
= suiteOrSpec
instanceof jasmine
.Suite
;
1035 name
: suiteOrSpec
.description
,
1036 type
: isSuite
? 'suite' : 'spec',
1041 var children
= suiteOrSpec
.children();
1042 for (var i
= 0; i
< children
.length
; i
++) {
1043 summary
.children
.push(this.summarize_(children
[i
]));
1049 jasmine
.JsApiReporter
.prototype.results = function() {
1050 return this.results_
;
1053 jasmine
.JsApiReporter
.prototype.resultsForSpec = function(specId
) {
1054 return this.results_
[specId
];
1057 //noinspection JSUnusedLocalSymbols
1058 jasmine
.JsApiReporter
.prototype.reportRunnerResults = function(runner
) {
1059 this.finished
= true;
1062 //noinspection JSUnusedLocalSymbols
1063 jasmine
.JsApiReporter
.prototype.reportSuiteResults = function(suite
) {
1066 //noinspection JSUnusedLocalSymbols
1067 jasmine
.JsApiReporter
.prototype.reportSpecResults = function(spec
) {
1068 this.results_
[spec
.id
] = {
1069 messages
: spec
.results().getItems(),
1070 result
: spec
.results().failedCount
> 0 ? "failed" : "passed"
1074 //noinspection JSUnusedLocalSymbols
1075 jasmine
.JsApiReporter
.prototype.log = function(str
) {
1078 jasmine
.JsApiReporter
.prototype.resultsForSpecs = function(specIds
){
1080 for (var i
= 0; i
< specIds
.length
; i
++) {
1081 var specId
= specIds
[i
];
1082 results
[specId
] = this.summarizeResult_(this.results_
[specId
]);
1087 jasmine
.JsApiReporter
.prototype.summarizeResult_ = function(result
){
1088 var summaryMessages
= [];
1089 var messagesLength
= result
.messages
.length
;
1090 for (var messageIndex
= 0; messageIndex
< messagesLength
; messageIndex
++) {
1091 var resultMessage
= result
.messages
[messageIndex
];
1092 summaryMessages
.push({
1093 text
: resultMessage
.type
== 'log' ? resultMessage
.toString() : jasmine
.undefined,
1094 passed
: resultMessage
.passed
? resultMessage
.passed() : true,
1095 type
: resultMessage
.type
,
1096 message
: resultMessage
.message
,
1098 stack
: resultMessage
.passed
&& !resultMessage
.passed() ? resultMessage
.trace
.stack
: jasmine
.undefined
1104 result
: result
.result
,
1105 messages
: summaryMessages
1111 * @param {jasmine.Env} env
1113 * @param {jasmine.Spec} spec
1115 jasmine
.Matchers = function(env
, actual
, spec
, opt_isNot
) {
1117 this.actual
= actual
;
1119 this.isNot
= opt_isNot
|| false;
1120 this.reportWasCalled_
= false;
1123 // todo: @deprecated as of Jasmine 0.11, remove soon [xw]
1124 jasmine
.Matchers
.pp = function(str
) {
1125 throw new Error("jasmine.Matchers.pp() is no longer supported, please use jasmine.pp() instead!");
1128 // todo: @deprecated Deprecated as of Jasmine 0.10. Rewrite your custom matchers to return true or false. [xw]
1129 jasmine
.Matchers
.prototype.report = function(result
, failing_message
, details
) {
1130 throw new Error("As of jasmine 0.11, custom matchers must be implemented differently -- please see jasmine docs");
1133 jasmine
.Matchers
.wrapInto_ = function(prototype, matchersClass
) {
1134 for (var methodName
in prototype) {
1135 if (methodName
== 'report') continue;
1136 var orig
= prototype[methodName
];
1137 matchersClass
.prototype[methodName
] = jasmine
.Matchers
.matcherFn_(methodName
, orig
);
1141 jasmine
.Matchers
.matcherFn_ = function(matcherName
, matcherFunction
) {
1143 var matcherArgs
= jasmine
.util
.argsToArray(arguments
);
1144 var result
= matcherFunction
.apply(this, arguments
);
1150 if (this.reportWasCalled_
) return result
;
1155 message
= this.message
.apply(this, arguments
);
1156 if (jasmine
.isArray_(message
)) {
1157 message
= message
[this.isNot
? 1 : 0];
1160 var englishyPredicate
= matcherName
.replace(/[A-Z]/g, function(s
) { return ' ' + s
.toLowerCase(); });
1161 message
= "Expected " + jasmine
.pp(this.actual
) + (this.isNot
? " not " : " ") + englishyPredicate
;
1162 if (matcherArgs
.length
> 0) {
1163 for (var i
= 0; i
< matcherArgs
.length
; i
++) {
1164 if (i
> 0) message
+= ",";
1165 message
+= " " + jasmine
.pp(matcherArgs
[i
]);
1171 var expectationResult
= new jasmine
.ExpectationResult({
1172 matcherName
: matcherName
,
1174 expected
: matcherArgs
.length
> 1 ? matcherArgs
: matcherArgs
[0],
1175 actual
: this.actual
,
1178 this.spec
.addMatcherResult(expectationResult
);
1179 return jasmine
.undefined;
1187 * toBe: compares the actual to the expected using ===
1190 jasmine
.Matchers
.prototype.toBe = function(expected
) {
1191 return this.actual
=== expected
;
1195 * toNotBe: compares the actual to the expected using !==
1197 * @deprecated as of 1.0. Use not.toBe() instead.
1199 jasmine
.Matchers
.prototype.toNotBe = function(expected
) {
1200 return this.actual
!== expected
;
1204 * toEqual: compares the actual to the expected using common sense equality. Handles Objects, Arrays, etc.
1208 jasmine
.Matchers
.prototype.toEqual = function(expected
) {
1209 return this.env
.equals_(this.actual
, expected
);
1213 * toNotEqual: compares the actual to the expected using the ! of jasmine.Matchers.toEqual
1215 * @deprecated as of 1.0. Use not.toNotEqual() instead.
1217 jasmine
.Matchers
.prototype.toNotEqual = function(expected
) {
1218 return !this.env
.equals_(this.actual
, expected
);
1222 * Matcher that compares the actual to the expected using a regular expression. Constructs a RegExp, so takes
1223 * a pattern or a String.
1227 jasmine
.Matchers
.prototype.toMatch = function(expected
) {
1228 return new RegExp(expected
).test(this.actual
);
1232 * Matcher that compares the actual to the expected using the boolean inverse of jasmine.Matchers.toMatch
1234 * @deprecated as of 1.0. Use not.toMatch() instead.
1236 jasmine
.Matchers
.prototype.toNotMatch = function(expected
) {
1237 return !(new RegExp(expected
).test(this.actual
));
1241 * Matcher that compares the actual to jasmine.undefined.
1243 jasmine
.Matchers
.prototype.toBeDefined = function() {
1244 return (this.actual
!== jasmine
.undefined);
1248 * Matcher that compares the actual to jasmine.undefined.
1250 jasmine
.Matchers
.prototype.toBeUndefined = function() {
1251 return (this.actual
=== jasmine
.undefined);
1255 * Matcher that compares the actual to null.
1257 jasmine
.Matchers
.prototype.toBeNull = function() {
1258 return (this.actual
=== null);
1262 * Matcher that boolean not-nots the actual.
1264 jasmine
.Matchers
.prototype.toBeTruthy = function() {
1265 return !!this.actual
;
1270 * Matcher that boolean nots the actual.
1272 jasmine
.Matchers
.prototype.toBeFalsy = function() {
1273 return !this.actual
;
1278 * Matcher that checks to see if the actual, a Jasmine spy, was called.
1280 jasmine
.Matchers
.prototype.toHaveBeenCalled = function() {
1281 if (arguments
.length
> 0) {
1282 throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
1285 if (!jasmine
.isSpy(this.actual
)) {
1286 throw new Error('Expected a spy, but got ' + jasmine
.pp(this.actual
) + '.');
1289 this.message = function() {
1291 "Expected spy " + this.actual
.identity
+ " to have been called.",
1292 "Expected spy " + this.actual
.identity
+ " not to have been called."
1296 return this.actual
.wasCalled
;
1299 /** @deprecated Use expect(xxx).toHaveBeenCalled() instead */
1300 jasmine
.Matchers
.prototype.wasCalled
= jasmine
.Matchers
.prototype.toHaveBeenCalled
;
1303 * Matcher that checks to see if the actual, a Jasmine spy, was not called.
1305 * @deprecated Use expect(xxx).not.toHaveBeenCalled() instead
1307 jasmine
.Matchers
.prototype.wasNotCalled = function() {
1308 if (arguments
.length
> 0) {
1309 throw new Error('wasNotCalled does not take arguments');
1312 if (!jasmine
.isSpy(this.actual
)) {
1313 throw new Error('Expected a spy, but got ' + jasmine
.pp(this.actual
) + '.');
1316 this.message = function() {
1318 "Expected spy " + this.actual
.identity
+ " to not have been called.",
1319 "Expected spy " + this.actual
.identity
+ " to have been called."
1323 return !this.actual
.wasCalled
;
1327 * Matcher that checks to see if the actual, a Jasmine spy, was called with a set of parameters.
1332 jasmine
.Matchers
.prototype.toHaveBeenCalledWith = function() {
1333 var expectedArgs
= jasmine
.util
.argsToArray(arguments
);
1334 if (!jasmine
.isSpy(this.actual
)) {
1335 throw new Error('Expected a spy, but got ' + jasmine
.pp(this.actual
) + '.');
1337 this.message = function() {
1338 if (this.actual
.callCount
=== 0) {
1339 // todo: what should the failure message for .not.toHaveBeenCalledWith() be? is this right? test better. [xw]
1341 "Expected spy " + this.actual
.identity
+ " to have been called with " + jasmine
.pp(expectedArgs
) + " but it was never called.",
1342 "Expected spy " + this.actual
.identity
+ " not to have been called with " + jasmine
.pp(expectedArgs
) + " but it was."
1346 "Expected spy " + this.actual
.identity
+ " to have been called with " + jasmine
.pp(expectedArgs
) + " but was called with " + jasmine
.pp(this.actual
.argsForCall
),
1347 "Expected spy " + this.actual
.identity
+ " not to have been called with " + jasmine
.pp(expectedArgs
) + " but was called with " + jasmine
.pp(this.actual
.argsForCall
)
1352 return this.env
.contains_(this.actual
.argsForCall
, expectedArgs
);
1355 /** @deprecated Use expect(xxx).toHaveBeenCalledWith() instead */
1356 jasmine
.Matchers
.prototype.wasCalledWith
= jasmine
.Matchers
.prototype.toHaveBeenCalledWith
;
1358 /** @deprecated Use expect(xxx).not.toHaveBeenCalledWith() instead */
1359 jasmine
.Matchers
.prototype.wasNotCalledWith = function() {
1360 var expectedArgs
= jasmine
.util
.argsToArray(arguments
);
1361 if (!jasmine
.isSpy(this.actual
)) {
1362 throw new Error('Expected a spy, but got ' + jasmine
.pp(this.actual
) + '.');
1365 this.message = function() {
1367 "Expected spy not to have been called with " + jasmine
.pp(expectedArgs
) + " but it was",
1368 "Expected spy to have been called with " + jasmine
.pp(expectedArgs
) + " but it was"
1372 return !this.env
.contains_(this.actual
.argsForCall
, expectedArgs
);
1376 * Matcher that checks that the expected item is an element in the actual Array.
1378 * @param {Object} expected
1380 jasmine
.Matchers
.prototype.toContain = function(expected
) {
1381 return this.env
.contains_(this.actual
, expected
);
1385 * Matcher that checks that the expected item is NOT an element in the actual Array.
1387 * @param {Object} expected
1388 * @deprecated as of 1.0. Use not.toNotContain() instead.
1390 jasmine
.Matchers
.prototype.toNotContain = function(expected
) {
1391 return !this.env
.contains_(this.actual
, expected
);
1394 jasmine
.Matchers
.prototype.toBeLessThan = function(expected
) {
1395 return this.actual
< expected
;
1398 jasmine
.Matchers
.prototype.toBeGreaterThan = function(expected
) {
1399 return this.actual
> expected
;
1403 * Matcher that checks that the expected item is equal to the actual item
1404 * up to a given level of decimal precision (default 2).
1406 * @param {Number} expected
1407 * @param {Number} precision
1409 jasmine
.Matchers
.prototype.toBeCloseTo = function(expected
, precision
) {
1410 if (!(precision
=== 0)) {
1411 precision
= precision
|| 2;
1413 var multiplier
= Math
.pow(10, precision
);
1414 var actual
= Math
.round(this.actual
* multiplier
);
1415 expected
= Math
.round(expected
* multiplier
);
1416 return expected
== actual
;
1420 * Matcher that checks that the expected exception was thrown by the actual.
1422 * @param {String} expected
1424 jasmine
.Matchers
.prototype.toThrow = function(expected
) {
1427 if (typeof this.actual
!= 'function') {
1428 throw new Error('Actual is not a function');
1436 result
= (expected
=== jasmine
.undefined || this.env
.equals_(exception
.message
|| exception
, expected
.message
|| expected
));
1439 var not
= this.isNot
? "not " : "";
1441 this.message = function() {
1442 if (exception
&& (expected
=== jasmine
.undefined || !this.env
.equals_(exception
.message
|| exception
, expected
.message
|| expected
))) {
1443 return ["Expected function " + not
+ "to throw", expected
? expected
.message
|| expected
: "an exception", ", but it threw", exception
.message
|| exception
].join(' ');
1445 return "Expected function to throw an exception.";
1452 jasmine
.Matchers
.Any = function(expectedClass
) {
1453 this.expectedClass
= expectedClass
;
1456 jasmine
.Matchers
.Any
.prototype.matches = function(other
) {
1457 if (this.expectedClass
== String
) {
1458 return typeof other
== 'string' || other
instanceof String
;
1461 if (this.expectedClass
== Number
) {
1462 return typeof other
== 'number' || other
instanceof Number
;
1465 if (this.expectedClass
== Function
) {
1466 return typeof other
== 'function' || other
instanceof Function
;
1469 if (this.expectedClass
== Object
) {
1470 return typeof other
== 'object';
1473 return other
instanceof this.expectedClass
;
1476 jasmine
.Matchers
.Any
.prototype.toString = function() {
1477 return '<jasmine.any(' + this.expectedClass
+ ')>';
1483 jasmine
.MultiReporter = function() {
1484 this.subReporters_
= [];
1486 jasmine
.util
.inherit(jasmine
.MultiReporter
, jasmine
.Reporter
);
1488 jasmine
.MultiReporter
.prototype.addReporter = function(reporter
) {
1489 this.subReporters_
.push(reporter
);
1493 var functionNames
= [
1494 "reportRunnerStarting",
1495 "reportRunnerResults",
1496 "reportSuiteResults",
1497 "reportSpecStarting",
1498 "reportSpecResults",
1501 for (var i
= 0; i
< functionNames
.length
; i
++) {
1502 var functionName
= functionNames
[i
];
1503 jasmine
.MultiReporter
.prototype[functionName
] = (function(functionName
) {
1505 for (var j
= 0; j
< this.subReporters_
.length
; j
++) {
1506 var subReporter
= this.subReporters_
[j
];
1507 if (subReporter
[functionName
]) {
1508 subReporter
[functionName
].apply(subReporter
, arguments
);
1516 * Holds results for a set of Jasmine spec. Allows for the results array to hold another jasmine.NestedResults
1520 jasmine
.NestedResults = function() {
1522 * The total count of results
1524 this.totalCount
= 0;
1526 * Number of passed results
1528 this.passedCount
= 0;
1530 * Number of failed results
1532 this.failedCount
= 0;
1534 * Was this suite/spec skipped?
1536 this.skipped
= false;
1544 * Roll up the result counts.
1548 jasmine
.NestedResults
.prototype.rollupCounts = function(result
) {
1549 this.totalCount
+= result
.totalCount
;
1550 this.passedCount
+= result
.passedCount
;
1551 this.failedCount
+= result
.failedCount
;
1555 * Adds a log message.
1556 * @param values Array of message parts which will be concatenated later.
1558 jasmine
.NestedResults
.prototype.log = function(values
) {
1559 this.items_
.push(new jasmine
.MessageResult(values
));
1563 * Getter for the results: message & results.
1565 jasmine
.NestedResults
.prototype.getItems = function() {
1570 * Adds a result, tracking counts (total, passed, & failed)
1571 * @param {jasmine.ExpectationResult|jasmine.NestedResults} result
1573 jasmine
.NestedResults
.prototype.addResult = function(result
) {
1574 if (result
.type
!= 'log') {
1575 if (result
.items_
) {
1576 this.rollupCounts(result
);
1579 if (result
.passed()) {
1586 this.items_
.push(result
);
1590 * @returns {Boolean} True if <b>everything</b> below passed
1592 jasmine
.NestedResults
.prototype.passed = function() {
1593 return this.passedCount
=== this.totalCount
;
1596 * Base class for pretty printing for expectation results.
1598 jasmine
.PrettyPrinter = function() {
1599 this.ppNestLevel_
= 0;
1603 * Formats a value in a nice, human-readable string.
1607 jasmine
.PrettyPrinter
.prototype.format = function(value
) {
1608 if (this.ppNestLevel_
> 40) {
1609 throw new Error('jasmine.PrettyPrinter: format() nested too deeply!');
1612 this.ppNestLevel_
++;
1614 if (value
=== jasmine
.undefined) {
1615 this.emitScalar('undefined');
1616 } else if (value
=== null) {
1617 this.emitScalar('null');
1618 } else if (value
=== jasmine
.getGlobal()) {
1619 this.emitScalar('<global>');
1620 } else if (value
instanceof jasmine
.Matchers
.Any
) {
1621 this.emitScalar(value
.toString());
1622 } else if (typeof value
=== 'string') {
1623 this.emitString(value
);
1624 } else if (jasmine
.isSpy(value
)) {
1625 this.emitScalar("spy on " + value
.identity
);
1626 } else if (value
instanceof RegExp
) {
1627 this.emitScalar(value
.toString());
1628 } else if (typeof value
=== 'function') {
1629 this.emitScalar('Function');
1630 } else if (typeof value
.nodeType
=== 'number') {
1631 this.emitScalar('HTMLNode');
1632 } else if (value
instanceof Date
) {
1633 this.emitScalar('Date(' + value
+ ')');
1634 } else if (value
.__Jasmine_been_here_before__
) {
1635 this.emitScalar('<circular reference: ' + (jasmine
.isArray_(value
) ? 'Array' : 'Object') + '>');
1636 } else if (jasmine
.isArray_(value
) || typeof value
== 'object') {
1637 value
.__Jasmine_been_here_before__
= true;
1638 if (jasmine
.isArray_(value
)) {
1639 this.emitArray(value
);
1641 this.emitObject(value
);
1643 delete value
.__Jasmine_been_here_before__
;
1645 this.emitScalar(value
.toString());
1648 this.ppNestLevel_
--;
1652 jasmine
.PrettyPrinter
.prototype.iterateObject = function(obj
, fn
) {
1653 for (var property
in obj
) {
1654 if (property
== '__Jasmine_been_here_before__') continue;
1655 fn(property
, obj
.__lookupGetter__
? (obj
.__lookupGetter__(property
) !== jasmine
.undefined &&
1656 obj
.__lookupGetter__(property
) !== null) : false);
1660 jasmine
.PrettyPrinter
.prototype.emitArray
= jasmine
.unimplementedMethod_
;
1661 jasmine
.PrettyPrinter
.prototype.emitObject
= jasmine
.unimplementedMethod_
;
1662 jasmine
.PrettyPrinter
.prototype.emitScalar
= jasmine
.unimplementedMethod_
;
1663 jasmine
.PrettyPrinter
.prototype.emitString
= jasmine
.unimplementedMethod_
;
1665 jasmine
.StringPrettyPrinter = function() {
1666 jasmine
.PrettyPrinter
.call(this);
1670 jasmine
.util
.inherit(jasmine
.StringPrettyPrinter
, jasmine
.PrettyPrinter
);
1672 jasmine
.StringPrettyPrinter
.prototype.emitScalar = function(value
) {
1676 jasmine
.StringPrettyPrinter
.prototype.emitString = function(value
) {
1677 this.append("'" + value
+ "'");
1680 jasmine
.StringPrettyPrinter
.prototype.emitArray = function(array
) {
1682 for (var i
= 0; i
< array
.length
; i
++) {
1686 this.format(array
[i
]);
1691 jasmine
.StringPrettyPrinter
.prototype.emitObject = function(obj
) {
1696 this.iterateObject(obj
, function(property
, isGetter
) {
1703 self
.append(property
);
1706 self
.append('<getter>');
1708 self
.format(obj
[property
]);
1715 jasmine
.StringPrettyPrinter
.prototype.append = function(value
) {
1716 this.string
+= value
;
1718 jasmine
.Queue = function(env
) {
1721 this.running
= false;
1727 jasmine
.Queue
.prototype.addBefore = function(block
) {
1728 this.blocks
.unshift(block
);
1731 jasmine
.Queue
.prototype.add = function(block
) {
1732 this.blocks
.push(block
);
1735 jasmine
.Queue
.prototype.insertNext = function(block
) {
1736 this.blocks
.splice((this.index
+ this.offset
+ 1), 0, block
);
1740 jasmine
.Queue
.prototype.start = function(onComplete
) {
1741 this.running
= true;
1742 this.onComplete
= onComplete
;
1746 jasmine
.Queue
.prototype.isRunning = function() {
1747 return this.running
;
1750 jasmine
.Queue
.LOOP_DONT_RECURSE
= true;
1752 jasmine
.Queue
.prototype.next_ = function() {
1759 if (self
.index
< self
.blocks
.length
&& !this.abort
) {
1760 var calledSynchronously
= true;
1761 var completedSynchronously
= false;
1763 var onComplete = function () {
1764 if (jasmine
.Queue
.LOOP_DONT_RECURSE
&& calledSynchronously
) {
1765 completedSynchronously
= true;
1769 if (self
.blocks
[self
.index
].abort
) {
1776 var now
= new Date().getTime();
1777 if (self
.env
.updateInterval
&& now
- self
.env
.lastUpdate
> self
.env
.updateInterval
) {
1778 self
.env
.lastUpdate
= now
;
1779 self
.env
.setTimeout(function() {
1783 if (jasmine
.Queue
.LOOP_DONT_RECURSE
&& completedSynchronously
) {
1790 self
.blocks
[self
.index
].execute(onComplete
);
1792 calledSynchronously
= false;
1793 if (completedSynchronously
) {
1798 self
.running
= false;
1799 if (self
.onComplete
) {
1806 jasmine
.Queue
.prototype.results = function() {
1807 var results
= new jasmine
.NestedResults();
1808 for (var i
= 0; i
< this.blocks
.length
; i
++) {
1809 if (this.blocks
[i
].results
) {
1810 results
.addResult(this.blocks
[i
].results());
1821 * @param {jasmine.Env} env
1823 jasmine
.Runner = function(env
) {
1826 self
.queue
= new jasmine
.Queue(env
);
1832 jasmine
.Runner
.prototype.execute = function() {
1834 if (self
.env
.reporter
.reportRunnerStarting
) {
1835 self
.env
.reporter
.reportRunnerStarting(this);
1837 self
.queue
.start(function () {
1838 self
.finishCallback();
1842 jasmine
.Runner
.prototype.beforeEach = function(beforeEachFunction
) {
1843 beforeEachFunction
.typeName
= 'beforeEach';
1844 this.before_
.splice(0,0,beforeEachFunction
);
1847 jasmine
.Runner
.prototype.afterEach = function(afterEachFunction
) {
1848 afterEachFunction
.typeName
= 'afterEach';
1849 this.after_
.splice(0,0,afterEachFunction
);
1853 jasmine
.Runner
.prototype.finishCallback = function() {
1854 this.env
.reporter
.reportRunnerResults(this);
1857 jasmine
.Runner
.prototype.addSuite = function(suite
) {
1858 this.suites_
.push(suite
);
1861 jasmine
.Runner
.prototype.add = function(block
) {
1862 if (block
instanceof jasmine
.Suite
) {
1863 this.addSuite(block
);
1865 this.queue
.add(block
);
1868 jasmine
.Runner
.prototype.specs = function () {
1869 var suites
= this.suites();
1871 for (var i
= 0; i
< suites
.length
; i
++) {
1872 specs
= specs
.concat(suites
[i
].specs());
1877 jasmine
.Runner
.prototype.suites = function() {
1878 return this.suites_
;
1881 jasmine
.Runner
.prototype.topLevelSuites = function() {
1882 var topLevelSuites
= [];
1883 for (var i
= 0; i
< this.suites_
.length
; i
++) {
1884 if (!this.suites_
[i
].parentSuite
) {
1885 topLevelSuites
.push(this.suites_
[i
]);
1888 return topLevelSuites
;
1891 jasmine
.Runner
.prototype.results = function() {
1892 return this.queue
.results();
1895 * Internal representation of a Jasmine specification, or test.
1898 * @param {jasmine.Env} env
1899 * @param {jasmine.Suite} suite
1900 * @param {String} description
1902 jasmine
.Spec = function(env
, suite
, description
) {
1904 throw new Error('jasmine.Env() required');
1907 throw new Error('jasmine.Suite() required');
1910 spec
.id
= env
.nextSpecId
? env
.nextSpecId() : null;
1913 spec
.description
= description
;
1914 spec
.queue
= new jasmine
.Queue(env
);
1916 spec
.afterCallbacks
= [];
1919 spec
.results_
= new jasmine
.NestedResults();
1920 spec
.results_
.description
= description
;
1921 spec
.matchersClass
= null;
1924 jasmine
.Spec
.prototype.getFullName = function() {
1925 return this.suite
.getFullName() + ' ' + this.description
+ '.';
1929 jasmine
.Spec
.prototype.results = function() {
1930 return this.results_
;
1934 * All parameters are pretty-printed and concatenated together, then written to the spec's output.
1936 * Be careful not to leave calls to <code>jasmine.log</code> in production code.
1938 jasmine
.Spec
.prototype.log = function() {
1939 return this.results_
.log(arguments
);
1942 jasmine
.Spec
.prototype.runs = function (func
) {
1943 var block
= new jasmine
.Block(this.env
, func
, this);
1944 this.addToQueue(block
);
1948 jasmine
.Spec
.prototype.addToQueue = function (block
) {
1949 if (this.queue
.isRunning()) {
1950 this.queue
.insertNext(block
);
1952 this.queue
.add(block
);
1957 * @param {jasmine.ExpectationResult} result
1959 jasmine
.Spec
.prototype.addMatcherResult = function(result
) {
1960 this.results_
.addResult(result
);
1963 jasmine
.Spec
.prototype.expect = function(actual
) {
1964 var positive
= new (this.getMatchersClass_())(this.env
, actual
, this);
1965 positive
.not
= new (this.getMatchersClass_())(this.env
, actual
, this, true);
1970 * Waits a fixed time period before moving to the next block.
1972 * @deprecated Use waitsFor() instead
1973 * @param {Number} timeout milliseconds to wait
1975 jasmine
.Spec
.prototype.waits = function(timeout
) {
1976 var waitsFunc
= new jasmine
.WaitsBlock(this.env
, timeout
, this);
1977 this.addToQueue(waitsFunc
);
1982 * Waits for the latchFunction to return true before proceeding to the next block.
1984 * @param {Function} latchFunction
1985 * @param {String} optional_timeoutMessage
1986 * @param {Number} optional_timeout
1988 jasmine
.Spec
.prototype.waitsFor = function(latchFunction
, optional_timeoutMessage
, optional_timeout
) {
1989 var latchFunction_
= null;
1990 var optional_timeoutMessage_
= null;
1991 var optional_timeout_
= null;
1993 for (var i
= 0; i
< arguments
.length
; i
++) {
1994 var arg
= arguments
[i
];
1995 switch (typeof arg
) {
1997 latchFunction_
= arg
;
2000 optional_timeoutMessage_
= arg
;
2003 optional_timeout_
= arg
;
2008 var waitsForFunc
= new jasmine
.WaitsForBlock(this.env
, optional_timeout_
, latchFunction_
, optional_timeoutMessage_
, this);
2009 this.addToQueue(waitsForFunc
);
2013 jasmine
.Spec
.prototype.fail = function (e
) {
2014 var expectationResult
= new jasmine
.ExpectationResult({
2016 message
: e
? jasmine
.util
.formatException(e
) : 'Exception',
2017 trace
: { stack
: e
.stack
}
2019 this.results_
.addResult(expectationResult
);
2022 jasmine
.Spec
.prototype.getMatchersClass_ = function() {
2023 return this.matchersClass
|| this.env
.matchersClass
;
2026 jasmine
.Spec
.prototype.addMatchers = function(matchersPrototype
) {
2027 var parent
= this.getMatchersClass_();
2028 var newMatchersClass = function() {
2029 parent
.apply(this, arguments
);
2031 jasmine
.util
.inherit(newMatchersClass
, parent
);
2032 jasmine
.Matchers
.wrapInto_(matchersPrototype
, newMatchersClass
);
2033 this.matchersClass
= newMatchersClass
;
2036 jasmine
.Spec
.prototype.finishCallback = function() {
2037 this.env
.reporter
.reportSpecResults(this);
2040 jasmine
.Spec
.prototype.finish = function(onComplete
) {
2041 this.removeAllSpies();
2042 this.finishCallback();
2048 jasmine
.Spec
.prototype.after = function(doAfter
) {
2049 if (this.queue
.isRunning()) {
2050 this.queue
.add(new jasmine
.Block(this.env
, doAfter
, this));
2052 this.afterCallbacks
.unshift(doAfter
);
2056 jasmine
.Spec
.prototype.execute = function(onComplete
) {
2058 if (!spec
.env
.specFilter(spec
)) {
2059 spec
.results_
.skipped
= true;
2060 spec
.finish(onComplete
);
2064 this.env
.reporter
.reportSpecStarting(this);
2066 spec
.env
.currentSpec
= spec
;
2068 spec
.addBeforesAndAftersToQueue();
2070 spec
.queue
.start(function () {
2071 spec
.finish(onComplete
);
2075 jasmine
.Spec
.prototype.addBeforesAndAftersToQueue = function() {
2076 var runner
= this.env
.currentRunner();
2079 for (var suite
= this.suite
; suite
; suite
= suite
.parentSuite
) {
2080 for (i
= 0; i
< suite
.before_
.length
; i
++) {
2081 this.queue
.addBefore(new jasmine
.Block(this.env
, suite
.before_
[i
], this));
2084 for (i
= 0; i
< runner
.before_
.length
; i
++) {
2085 this.queue
.addBefore(new jasmine
.Block(this.env
, runner
.before_
[i
], this));
2087 for (i
= 0; i
< this.afterCallbacks
.length
; i
++) {
2088 this.queue
.add(new jasmine
.Block(this.env
, this.afterCallbacks
[i
], this));
2090 for (suite
= this.suite
; suite
; suite
= suite
.parentSuite
) {
2091 for (i
= 0; i
< suite
.after_
.length
; i
++) {
2092 this.queue
.add(new jasmine
.Block(this.env
, suite
.after_
[i
], this));
2095 for (i
= 0; i
< runner
.after_
.length
; i
++) {
2096 this.queue
.add(new jasmine
.Block(this.env
, runner
.after_
[i
], this));
2100 jasmine
.Spec
.prototype.explodes = function() {
2101 throw 'explodes function should not have been called';
2104 jasmine
.Spec
.prototype.spyOn = function(obj
, methodName
, ignoreMethodDoesntExist
) {
2105 if (obj
== jasmine
.undefined) {
2106 throw "spyOn could not find an object to spy upon for " + methodName
+ "()";
2109 if (!ignoreMethodDoesntExist
&& obj
[methodName
] === jasmine
.undefined) {
2110 throw methodName
+ '() method does not exist';
2113 if (!ignoreMethodDoesntExist
&& obj
[methodName
] && obj
[methodName
].isSpy
) {
2114 throw new Error(methodName
+ ' has already been spied upon');
2117 var spyObj
= jasmine
.createSpy(methodName
);
2119 this.spies_
.push(spyObj
);
2120 spyObj
.baseObj
= obj
;
2121 spyObj
.methodName
= methodName
;
2122 spyObj
.originalValue
= obj
[methodName
];
2124 obj
[methodName
] = spyObj
;
2129 jasmine
.Spec
.prototype.removeAllSpies = function() {
2130 for (var i
= 0; i
< this.spies_
.length
; i
++) {
2131 var spy
= this.spies_
[i
];
2132 spy
.baseObj
[spy
.methodName
] = spy
.originalValue
;
2138 * Internal representation of a Jasmine suite.
2141 * @param {jasmine.Env} env
2142 * @param {String} description
2143 * @param {Function} specDefinitions
2144 * @param {jasmine.Suite} parentSuite
2146 jasmine
.Suite = function(env
, description
, specDefinitions
, parentSuite
) {
2148 self
.id
= env
.nextSuiteId
? env
.nextSuiteId() : null;
2149 self
.description
= description
;
2150 self
.queue
= new jasmine
.Queue(env
);
2151 self
.parentSuite
= parentSuite
;
2155 self
.children_
= [];
2160 jasmine
.Suite
.prototype.getFullName = function() {
2161 var fullName
= this.description
;
2162 for (var parentSuite
= this.parentSuite
; parentSuite
; parentSuite
= parentSuite
.parentSuite
) {
2163 fullName
= parentSuite
.description
+ ' ' + fullName
;
2168 jasmine
.Suite
.prototype.finish = function(onComplete
) {
2169 this.env
.reporter
.reportSuiteResults(this);
2170 this.finished
= true;
2171 if (typeof(onComplete
) == 'function') {
2176 jasmine
.Suite
.prototype.beforeEach = function(beforeEachFunction
) {
2177 beforeEachFunction
.typeName
= 'beforeEach';
2178 this.before_
.unshift(beforeEachFunction
);
2181 jasmine
.Suite
.prototype.afterEach = function(afterEachFunction
) {
2182 afterEachFunction
.typeName
= 'afterEach';
2183 this.after_
.unshift(afterEachFunction
);
2186 jasmine
.Suite
.prototype.results = function() {
2187 return this.queue
.results();
2190 jasmine
.Suite
.prototype.add = function(suiteOrSpec
) {
2191 this.children_
.push(suiteOrSpec
);
2192 if (suiteOrSpec
instanceof jasmine
.Suite
) {
2193 this.suites_
.push(suiteOrSpec
);
2194 this.env
.currentRunner().addSuite(suiteOrSpec
);
2196 this.specs_
.push(suiteOrSpec
);
2198 this.queue
.add(suiteOrSpec
);
2201 jasmine
.Suite
.prototype.specs = function() {
2205 jasmine
.Suite
.prototype.suites = function() {
2206 return this.suites_
;
2209 jasmine
.Suite
.prototype.children = function() {
2210 return this.children_
;
2213 jasmine
.Suite
.prototype.execute = function(onComplete
) {
2215 this.queue
.start(function () {
2216 self
.finish(onComplete
);
2219 jasmine
.WaitsBlock = function(env
, timeout
, spec
) {
2220 this.timeout
= timeout
;
2221 jasmine
.Block
.call(this, env
, null, spec
);
2224 jasmine
.util
.inherit(jasmine
.WaitsBlock
, jasmine
.Block
);
2226 jasmine
.WaitsBlock
.prototype.execute = function (onComplete
) {
2227 if (jasmine
.VERBOSE
) {
2228 this.env
.reporter
.log('>> Jasmine waiting for ' + this.timeout
+ ' ms...');
2230 this.env
.setTimeout(function () {
2235 * A block which waits for some condition to become true, with timeout.
2238 * @extends jasmine.Block
2239 * @param {jasmine.Env} env The Jasmine environment.
2240 * @param {Number} timeout The maximum time in milliseconds to wait for the condition to become true.
2241 * @param {Function} latchFunction A function which returns true when the desired condition has been met.
2242 * @param {String} message The message to display if the desired condition hasn't been met within the given time period.
2243 * @param {jasmine.Spec} spec The Jasmine spec.
2245 jasmine
.WaitsForBlock = function(env
, timeout
, latchFunction
, message
, spec
) {
2246 this.timeout
= timeout
|| env
.defaultTimeoutInterval
;
2247 this.latchFunction
= latchFunction
;
2248 this.message
= message
;
2249 this.totalTimeSpentWaitingForLatch
= 0;
2250 jasmine
.Block
.call(this, env
, null, spec
);
2252 jasmine
.util
.inherit(jasmine
.WaitsForBlock
, jasmine
.Block
);
2254 jasmine
.WaitsForBlock
.TIMEOUT_INCREMENT
= 10;
2256 jasmine
.WaitsForBlock
.prototype.execute = function(onComplete
) {
2257 if (jasmine
.VERBOSE
) {
2258 this.env
.reporter
.log('>> Jasmine waiting for ' + (this.message
|| 'something to happen'));
2260 var latchFunctionResult
;
2262 latchFunctionResult
= this.latchFunction
.apply(this.spec
);
2269 if (latchFunctionResult
) {
2271 } else if (this.totalTimeSpentWaitingForLatch
>= this.timeout
) {
2272 var message
= 'timed out after ' + this.timeout
+ ' msec waiting for ' + (this.message
|| 'something to happen');
2281 this.totalTimeSpentWaitingForLatch
+= jasmine
.WaitsForBlock
.TIMEOUT_INCREMENT
;
2283 this.env
.setTimeout(function() {
2284 self
.execute(onComplete
);
2285 }, jasmine
.WaitsForBlock
.TIMEOUT_INCREMENT
);
2288 // Mock setTimeout, clearTimeout
2289 // Contributed by Pivotal Computer Systems, www.pivotalsf.com
2291 jasmine
.FakeTimer = function() {
2295 self
.setTimeout = function(funcToCall
, millis
) {
2296 self
.timeoutsMade
++;
2297 self
.scheduleFunction(self
.timeoutsMade
, funcToCall
, millis
, false);
2298 return self
.timeoutsMade
;
2301 self
.setInterval = function(funcToCall
, millis
) {
2302 self
.timeoutsMade
++;
2303 self
.scheduleFunction(self
.timeoutsMade
, funcToCall
, millis
, true);
2304 return self
.timeoutsMade
;
2307 self
.clearTimeout = function(timeoutKey
) {
2308 self
.scheduledFunctions
[timeoutKey
] = jasmine
.undefined;
2311 self
.clearInterval = function(timeoutKey
) {
2312 self
.scheduledFunctions
[timeoutKey
] = jasmine
.undefined;
2317 jasmine
.FakeTimer
.prototype.reset = function() {
2318 this.timeoutsMade
= 0;
2319 this.scheduledFunctions
= {};
2323 jasmine
.FakeTimer
.prototype.tick = function(millis
) {
2324 var oldMillis
= this.nowMillis
;
2325 var newMillis
= oldMillis
+ millis
;
2326 this.runFunctionsWithinRange(oldMillis
, newMillis
);
2327 this.nowMillis
= newMillis
;
2330 jasmine
.FakeTimer
.prototype.runFunctionsWithinRange = function(oldMillis
, nowMillis
) {
2332 var funcsToRun
= [];
2333 for (var timeoutKey
in this.scheduledFunctions
) {
2334 scheduledFunc
= this.scheduledFunctions
[timeoutKey
];
2335 if (scheduledFunc
!= jasmine
.undefined &&
2336 scheduledFunc
.runAtMillis
>= oldMillis
&&
2337 scheduledFunc
.runAtMillis
<= nowMillis
) {
2338 funcsToRun
.push(scheduledFunc
);
2339 this.scheduledFunctions
[timeoutKey
] = jasmine
.undefined;
2343 if (funcsToRun
.length
> 0) {
2344 funcsToRun
.sort(function(a
, b
) {
2345 return a
.runAtMillis
- b
.runAtMillis
;
2347 for (var i
= 0; i
< funcsToRun
.length
; ++i
) {
2349 var funcToRun
= funcsToRun
[i
];
2350 this.nowMillis
= funcToRun
.runAtMillis
;
2351 funcToRun
.funcToCall();
2352 if (funcToRun
.recurring
) {
2353 this.scheduleFunction(funcToRun
.timeoutKey
,
2354 funcToRun
.funcToCall
,
2361 this.runFunctionsWithinRange(oldMillis
, nowMillis
);
2365 jasmine
.FakeTimer
.prototype.scheduleFunction = function(timeoutKey
, funcToCall
, millis
, recurring
) {
2366 this.scheduledFunctions
[timeoutKey
] = {
2367 runAtMillis
: this.nowMillis
+ millis
,
2368 funcToCall
: funcToCall
,
2369 recurring
: recurring
,
2370 timeoutKey
: timeoutKey
,
2379 defaultFakeTimer
: new jasmine
.FakeTimer(),
2382 jasmine
.Clock
.assertInstalled();
2383 jasmine
.Clock
.defaultFakeTimer
.reset();
2386 tick: function(millis
) {
2387 jasmine
.Clock
.assertInstalled();
2388 jasmine
.Clock
.defaultFakeTimer
.tick(millis
);
2391 runFunctionsWithinRange: function(oldMillis
, nowMillis
) {
2392 jasmine
.Clock
.defaultFakeTimer
.runFunctionsWithinRange(oldMillis
, nowMillis
);
2395 scheduleFunction: function(timeoutKey
, funcToCall
, millis
, recurring
) {
2396 jasmine
.Clock
.defaultFakeTimer
.scheduleFunction(timeoutKey
, funcToCall
, millis
, recurring
);
2399 useMock: function() {
2400 if (!jasmine
.Clock
.isInstalled()) {
2401 var spec
= jasmine
.getEnv().currentSpec
;
2402 spec
.after(jasmine
.Clock
.uninstallMock
);
2404 jasmine
.Clock
.installMock();
2408 installMock: function() {
2409 jasmine
.Clock
.installed
= jasmine
.Clock
.defaultFakeTimer
;
2412 uninstallMock: function() {
2413 jasmine
.Clock
.assertInstalled();
2414 jasmine
.Clock
.installed
= jasmine
.Clock
.real
;
2418 setTimeout
: jasmine
.getGlobal().setTimeout
,
2419 clearTimeout
: jasmine
.getGlobal().clearTimeout
,
2420 setInterval
: jasmine
.getGlobal().setInterval
,
2421 clearInterval
: jasmine
.getGlobal().clearInterval
2424 assertInstalled: function() {
2425 if (!jasmine
.Clock
.isInstalled()) {
2426 throw new Error("Mock clock is not installed, use jasmine.Clock.useMock()");
2430 isInstalled: function() {
2431 return jasmine
.Clock
.installed
== jasmine
.Clock
.defaultFakeTimer
;
2436 jasmine
.Clock
.installed
= jasmine
.Clock
.real
;
2438 //else for IE support
2439 jasmine
.getGlobal().setTimeout = function(funcToCall
, millis
) {
2440 if (jasmine
.Clock
.installed
.setTimeout
.apply
) {
2441 return jasmine
.Clock
.installed
.setTimeout
.apply(this, arguments
);
2443 return jasmine
.Clock
.installed
.setTimeout(funcToCall
, millis
);
2447 jasmine
.getGlobal().setInterval = function(funcToCall
, millis
) {
2448 if (jasmine
.Clock
.installed
.setInterval
.apply
) {
2449 return jasmine
.Clock
.installed
.setInterval
.apply(this, arguments
);
2451 return jasmine
.Clock
.installed
.setInterval(funcToCall
, millis
);
2455 jasmine
.getGlobal().clearTimeout = function(timeoutKey
) {
2456 if (jasmine
.Clock
.installed
.clearTimeout
.apply
) {
2457 return jasmine
.Clock
.installed
.clearTimeout
.apply(this, arguments
);
2459 return jasmine
.Clock
.installed
.clearTimeout(timeoutKey
);
2463 jasmine
.getGlobal().clearInterval = function(timeoutKey
) {
2464 if (jasmine
.Clock
.installed
.clearTimeout
.apply
) {
2465 return jasmine
.Clock
.installed
.clearInterval
.apply(this, arguments
);
2467 return jasmine
.Clock
.installed
.clearInterval(timeoutKey
);
2475 "revision": 1308965645,
2476 "release_candidate": 2