2 Copyright (c) 2008-2013 Pivotal Labs
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 function getJasmineRequireObj() {
24 if (typeof module !== "undefined" && module.exports) {
27 window.jasmineRequire = window.jasmineRequire || {};
28 return window.jasmineRequire;
32 getJasmineRequireObj().core = function(jRequire) {
36 j$.util = jRequire.util();
37 j$.Any = jRequire.Any();
38 j$.CallTracker = jRequire.CallTracker();
39 j$.Clock = jRequire.Clock();
40 j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
41 j$.Env = jRequire.Env(j$);
42 j$.ExceptionFormatter = jRequire.ExceptionFormatter();
43 j$.Expectation = jRequire.Expectation();
44 j$.buildExpectationResult = jRequire.buildExpectationResult();
45 j$.JsApiReporter = jRequire.JsApiReporter();
46 j$.matchersUtil = jRequire.matchersUtil(j$);
47 j$.ObjectContaining = jRequire.ObjectContaining(j$);
48 j$.pp = jRequire.pp(j$);
49 j$.QueueRunner = jRequire.QueueRunner();
50 j$.ReportDispatcher = jRequire.ReportDispatcher();
51 j$.Spec = jRequire.Spec(j$);
52 j$.SpyStrategy = jRequire.SpyStrategy();
53 j$.Suite = jRequire.Suite();
54 j$.Timer = jRequire.Timer();
55 j$.version = jRequire.version();
57 j$.matchers = jRequire.requireMatchers(jRequire, j$);
62 getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
63 var availableMatchers = [
77 "toHaveBeenCalledWith",
84 for (var i = 0; i < availableMatchers.length; i++) {
85 var name = availableMatchers[i];
86 matchers[name] = jRequire[name](j$);
92 getJasmineRequireObj().base = function(j$) {
93 j$.unimplementedMethod_ = function() {
94 throw new Error("unimplemented method");
97 j$.MAX_PRETTY_PRINT_DEPTH = 40;
98 j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
100 j$.getGlobal = (function() {
101 var jasmineGlobal = eval.call(null, "this");
103 return jasmineGlobal;
107 j$.getEnv = function(options) {
108 var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
109 //jasmine. singletons in here (setTimeout blah blah).
113 j$.isArray_ = function(value) {
114 return j$.isA_("Array", value);
117 j$.isString_ = function(value) {
118 return j$.isA_("String", value);
121 j$.isNumber_ = function(value) {
122 return j$.isA_("Number", value);
125 j$.isA_ = function(typeName, value) {
126 return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
129 j$.isDomNode = function(obj) {
130 return obj.nodeType > 0;
133 j$.any = function(clazz) {
134 return new j$.Any(clazz);
137 j$.objectContaining = function(sample) {
138 return new j$.ObjectContaining(sample);
141 j$.createSpy = function(name, originalFn) {
143 var spyStrategy = new j$.SpyStrategy({
146 getSpy: function() { return spy; }
148 callTracker = new j$.CallTracker(),
152 args: Array.prototype.slice.apply(arguments)
154 return spyStrategy.exec.apply(this, arguments);
157 for (var prop in originalFn) {
158 if (prop === 'and' || prop === 'calls') {
159 throw new Error("Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon");
162 spy[prop] = originalFn[prop];
165 spy.and = spyStrategy;
166 spy.calls = callTracker;
171 j$.isSpy = function(putativeSpy) {
175 return putativeSpy.and instanceof j$.SpyStrategy &&
176 putativeSpy.calls instanceof j$.CallTracker;
179 j$.createSpyObj = function(baseName, methodNames) {
180 if (!j$.isArray_(methodNames) || methodNames.length === 0) {
181 throw "createSpyObj requires a non-empty array of method names to create spies for";
184 for (var i = 0; i < methodNames.length; i++) {
185 obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
191 getJasmineRequireObj().util = function() {
195 util.inherit = function(childClass, parentClass) {
196 var Subclass = function() {
198 Subclass.prototype = parentClass.prototype;
199 childClass.prototype = new Subclass();
202 util.htmlEscape = function(str) {
206 return str.replace(/&/g, '&')
207 .replace(/</g, '<')
208 .replace(/>/g, '>');
211 util.argsToArray = function(args) {
212 var arrayOfArgs = [];
213 for (var i = 0; i < args.length; i++) {
214 arrayOfArgs.push(args[i]);
219 util.isUndefined = function(obj) {
220 return obj === void 0;
226 getJasmineRequireObj().Spec = function(j$) {
227 function Spec(attrs) {
228 this.expectationFactory = attrs.expectationFactory;
229 this.resultCallback = attrs.resultCallback || function() {};
231 this.description = attrs.description || '';
233 this.beforeFns = attrs.beforeFns || function() { return []; };
234 this.afterFns = attrs.afterFns || function() { return []; };
235 this.onStart = attrs.onStart || function() {};
236 this.exceptionFormatter = attrs.exceptionFormatter || function() {};
237 this.getSpecName = attrs.getSpecName || function() { return ''; };
238 this.expectationResultFactory = attrs.expectationResultFactory || function() { };
239 this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
240 this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
242 this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout};
250 description: this.description,
251 fullName: this.getFullName(),
252 failedExpectations: []
256 Spec.prototype.addExpectationResult = function(passed, data) {
260 this.result.failedExpectations.push(this.expectationResultFactory(data));
263 Spec.prototype.expect = function(actual) {
264 return this.expectationFactory(actual, this);
267 Spec.prototype.execute = function(onComplete) {
273 if (this.markedPending || this.disabled) {
278 function timeoutable(fn) {
279 return function(done) {
280 timeout = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
281 onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
283 }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
285 var callDone = function() {
290 fn.call(this, callDone); //TODO: do we care about more than 1 arg?
294 function clearTimeoutable() {
295 Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]);
299 var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()),
300 allTimeoutableFns = [];
301 for (var i = 0; i < allFns.length; i++) {
303 allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn);
306 this.queueRunnerFactory({
307 fns: allTimeoutableFns,
308 onException: onException,
312 function onException(e) {
314 if (Spec.isPendingSpecException(e)) {
319 self.addExpectationResult(false, {
328 function complete() {
329 self.result.status = self.status();
330 self.resultCallback(self.result);
338 Spec.prototype.disable = function() {
339 this.disabled = true;
342 Spec.prototype.pend = function() {
343 this.markedPending = true;
346 Spec.prototype.status = function() {
351 if (this.markedPending) {
355 if (this.result.failedExpectations.length > 0) {
362 Spec.prototype.getFullName = function() {
363 return this.getSpecName(this);
366 Spec.pendingSpecExceptionMessage = "=> marked Pending";
368 Spec.isPendingSpecException = function(e) {
369 return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1;
375 if (typeof window == void 0 && typeof exports == "object") {
376 exports.Spec = jasmineRequire.Spec;
379 getJasmineRequireObj().Env = function(j$) {
380 function Env(options) {
381 options = options || {};
384 var global = options.global || j$.getGlobal();
386 var totalSpecsDefined = 0;
388 var catchExceptions = true;
390 var realSetTimeout = j$.getGlobal().setTimeout;
391 var realClearTimeout = j$.getGlobal().clearTimeout;
392 this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler());
394 var runnableLookupTable = {};
398 var currentSpec = null;
399 var currentSuite = null;
401 var reporter = new j$.ReportDispatcher([
410 this.specFilter = function() {
414 var equalityTesters = [];
416 var customEqualityTesters = [];
417 this.addCustomEqualityTester = function(tester) {
418 customEqualityTesters.push(tester);
421 j$.Expectation.addCoreMatchers(j$.matchers);
424 var getNextSpecId = function() {
425 return 'spec' + nextSpecId++;
429 var getNextSuiteId = function() {
430 return 'suite' + nextSuiteId++;
433 var expectationFactory = function(actual, spec) {
434 return j$.Expectation.Factory({
435 util: j$.matchersUtil,
436 customEqualityTesters: customEqualityTesters,
438 addExpectationResult: addExpectationResult
441 function addExpectationResult(passed, result) {
442 return spec.addExpectationResult(passed, result);
446 var specStarted = function(spec) {
448 reporter.specStarted(spec.result);
451 var beforeFns = function(suite) {
455 befores = befores.concat(suite.beforeFns);
456 suite = suite.parentSuite;
458 return befores.reverse();
462 var afterFns = function(suite) {
466 afters = afters.concat(suite.afterFns);
467 suite = suite.parentSuite;
473 var getSpecName = function(spec, suite) {
474 return suite.getFullName() + ' ' + spec.description;
477 // TODO: we may just be able to pass in the fn instead of wrapping here
478 var buildExpectationResult = j$.buildExpectationResult,
479 exceptionFormatter = new j$.ExceptionFormatter(),
480 expectationResultFactory = function(attrs) {
481 attrs.messageFormatter = exceptionFormatter.message;
482 attrs.stackFormatter = exceptionFormatter.stack;
484 return buildExpectationResult(attrs);
487 // TODO: fix this naming, and here's where the value comes in
488 this.catchExceptions = function(value) {
489 catchExceptions = !!value;
490 return catchExceptions;
493 this.catchingExceptions = function() {
494 return catchExceptions;
497 var maximumSpecCallbackDepth = 20;
498 var currentSpecCallbackDepth = 0;
500 function clearStack(fn) {
501 currentSpecCallbackDepth++;
502 if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
503 currentSpecCallbackDepth = 0;
504 realSetTimeout(fn, 0);
510 var catchException = function(e) {
511 return j$.Spec.isPendingSpecException(e) || catchExceptions;
514 var queueRunnerFactory = function(options) {
515 options.catchException = catchException;
516 options.clearStack = options.clearStack || clearStack;
518 new j$.QueueRunner(options).execute();
521 var topSuite = new j$.Suite({
523 id: getNextSuiteId(),
524 description: 'Jasmine__TopLevel__Suite',
525 queueRunner: queueRunnerFactory,
526 resultCallback: function() {} // TODO - hook this up
528 runnableLookupTable[topSuite.id] = topSuite;
529 currentSuite = topSuite;
531 this.topSuite = function() {
535 this.execute = function(runnablesToRun) {
536 runnablesToRun = runnablesToRun || [topSuite.id];
539 for(var i = 0; i < runnablesToRun.length; i++) {
540 var runnable = runnableLookupTable[runnablesToRun[i]];
541 allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
544 reporter.jasmineStarted({
545 totalSpecsDefined: totalSpecsDefined
548 queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
551 this.addReporter = function(reporterToAdd) {
552 reporter.addReporter(reporterToAdd);
555 this.addMatchers = function(matchersToAdd) {
556 j$.Expectation.addMatchers(matchersToAdd);
559 this.spyOn = function(obj, methodName) {
560 if (j$.util.isUndefined(obj)) {
561 throw new Error("spyOn could not find an object to spy upon for " + methodName + "()");
564 if (j$.util.isUndefined(obj[methodName])) {
565 throw new Error(methodName + '() method does not exist');
568 if (obj[methodName] && j$.isSpy(obj[methodName])) {
569 //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
570 throw new Error(methodName + ' has already been spied upon');
573 var spy = j$.createSpy(methodName, obj[methodName]);
578 methodName: methodName,
579 originalValue: obj[methodName]
582 obj[methodName] = spy;
587 var suiteFactory = function(description) {
588 var suite = new j$.Suite({
590 id: getNextSuiteId(),
591 description: description,
592 parentSuite: currentSuite,
593 queueRunner: queueRunnerFactory,
594 onStart: suiteStarted,
595 resultCallback: function(attrs) {
596 reporter.suiteDone(attrs);
600 runnableLookupTable[suite.id] = suite;
604 this.describe = function(description, specDefinitions) {
605 var suite = suiteFactory(description);
607 var parentSuite = currentSuite;
608 parentSuite.addChild(suite);
609 currentSuite = suite;
611 var declarationError = null;
613 specDefinitions.call(suite);
615 declarationError = e;
618 if (declarationError) {
619 this.it("encountered a declaration exception", function() {
620 throw declarationError;
624 currentSuite = parentSuite;
629 this.xdescribe = function(description, specDefinitions) {
630 var suite = this.describe(description, specDefinitions);
635 var specFactory = function(description, fn, suite) {
638 var spec = new j$.Spec({
640 beforeFns: beforeFns(suite),
641 afterFns: afterFns(suite),
642 expectationFactory: expectationFactory,
643 exceptionFormatter: exceptionFormatter,
644 resultCallback: specResultCallback,
645 getSpecName: function(spec) {
646 return getSpecName(spec, suite);
648 onStart: specStarted,
649 description: description,
650 expectationResultFactory: expectationResultFactory,
651 queueRunnerFactory: queueRunnerFactory,
653 timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout}
656 runnableLookupTable[spec.id] = spec;
658 if (!self.specFilter(spec)) {
664 function removeAllSpies() {
665 for (var i = 0; i < spies.length; i++) {
666 var spyEntry = spies[i];
667 spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
672 function specResultCallback(result) {
674 j$.Expectation.resetMatchers();
675 customEqualityTesters = [];
677 reporter.specDone(result);
681 var suiteStarted = function(suite) {
682 reporter.suiteStarted(suite.result);
685 this.it = function(description, fn) {
686 var spec = specFactory(description, fn, currentSuite);
687 currentSuite.addChild(spec);
691 this.xit = function(description, fn) {
692 var spec = this.it(description, fn);
697 this.expect = function(actual) {
698 return currentSpec.expect(actual);
701 this.beforeEach = function(beforeEachFunction) {
702 currentSuite.beforeEach(beforeEachFunction);
705 this.afterEach = function(afterEachFunction) {
706 currentSuite.afterEach(afterEachFunction);
709 this.pending = function() {
710 throw j$.Spec.pendingSpecExceptionMessage;
717 getJasmineRequireObj().JsApiReporter = function() {
721 elapsed: function(){ return 0; }
724 function JsApiReporter(options) {
725 var timer = options.timer || noopTimer,
728 this.started = false;
729 this.finished = false;
731 this.jasmineStarted = function() {
739 this.jasmineDone = function() {
740 this.finished = true;
741 executionTime = timer.elapsed();
745 this.status = function() {
751 this.suiteStarted = function(result) {
755 this.suiteDone = function(result) {
759 function storeSuite(result) {
760 suites[result.id] = result;
763 this.suites = function() {
768 this.specStarted = function(result) { };
770 this.specDone = function(result) {
774 this.specResults = function(index, length) {
775 return specs.slice(index, index + length);
778 this.specs = function() {
782 this.executionTime = function() {
783 return executionTime;
788 return JsApiReporter;
791 getJasmineRequireObj().Any = function() {
793 function Any(expectedObject) {
794 this.expectedObject = expectedObject;
797 Any.prototype.jasmineMatches = function(other) {
798 if (this.expectedObject == String) {
799 return typeof other == 'string' || other instanceof String;
802 if (this.expectedObject == Number) {
803 return typeof other == 'number' || other instanceof Number;
806 if (this.expectedObject == Function) {
807 return typeof other == 'function' || other instanceof Function;
810 if (this.expectedObject == Object) {
811 return typeof other == 'object';
814 if (this.expectedObject == Boolean) {
815 return typeof other == 'boolean';
818 return other instanceof this.expectedObject;
821 Any.prototype.jasmineToString = function() {
822 return '<jasmine.any(' + this.expectedClass + ')>';
828 getJasmineRequireObj().CallTracker = function() {
830 function CallTracker() {
833 this.track = function(context) {
837 this.any = function() {
838 return !!calls.length;
841 this.count = function() {
845 this.argsFor = function(index) {
846 var call = calls[index];
847 return call ? call.args : [];
850 this.all = function() {
854 this.allArgs = function() {
856 for(var i = 0; i < calls.length; i++){
857 callArgs.push(calls[i].args);
863 this.first = function() {
867 this.mostRecent = function() {
868 return calls[calls.length - 1];
871 this.reset = function() {
879 getJasmineRequireObj().Clock = function() {
880 function Clock(global, delayedFunctionScheduler) {
882 realTimingFunctions = {
883 setTimeout: global.setTimeout,
884 clearTimeout: global.clearTimeout,
885 setInterval: global.setInterval,
886 clearInterval: global.clearInterval
888 fakeTimingFunctions = {
889 setTimeout: setTimeout,
890 clearTimeout: clearTimeout,
891 setInterval: setInterval,
892 clearInterval: clearInterval
897 self.install = function() {
898 replace(global, fakeTimingFunctions);
899 timer = fakeTimingFunctions;
903 self.uninstall = function() {
904 delayedFunctionScheduler.reset();
905 replace(global, realTimingFunctions);
906 timer = realTimingFunctions;
910 self.setTimeout = function(fn, delay, params) {
912 if (arguments.length > 2) {
913 throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill");
915 return timer.setTimeout(fn, delay);
917 return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
920 self.setInterval = function(fn, delay, params) {
922 if (arguments.length > 2) {
923 throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill");
925 return timer.setInterval(fn, delay);
927 return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
930 self.clearTimeout = function(id) {
931 return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
934 self.clearInterval = function(id) {
935 return Function.prototype.call.apply(timer.clearInterval, [global, id]);
938 self.tick = function(millis) {
940 delayedFunctionScheduler.tick(millis);
942 throw new Error("Mock clock is not installed, use jasmine.clock().install()");
948 function legacyIE() {
949 //if these methods are polyfilled, apply will be present
950 return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
953 function replace(dest, source) {
954 for (var prop in source) {
955 dest[prop] = source[prop];
959 function setTimeout(fn, delay) {
960 return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
963 function clearTimeout(id) {
964 return delayedFunctionScheduler.removeFunctionWithId(id);
967 function setInterval(fn, interval) {
968 return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
971 function clearInterval(id) {
972 return delayedFunctionScheduler.removeFunctionWithId(id);
975 function argSlice(argsObj, n) {
976 return Array.prototype.slice.call(argsObj, 2);
983 getJasmineRequireObj().DelayedFunctionScheduler = function() {
984 function DelayedFunctionScheduler() {
986 var scheduledLookup = [];
987 var scheduledFunctions = {};
989 var delayedFnCount = 0;
991 self.tick = function(millis) {
992 millis = millis || 0;
993 var endTime = currentTime + millis;
995 runScheduledFunctions(endTime);
996 currentTime = endTime;
999 self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
1001 if (typeof(funcToCall) === 'string') {
1002 /* jshint evil: true */
1003 f = function() { return eval(funcToCall); };
1004 /* jshint evil: false */
1009 millis = millis || 0;
1010 timeoutKey = timeoutKey || ++delayedFnCount;
1011 runAtMillis = runAtMillis || (currentTime + millis);
1013 var funcToSchedule = {
1014 runAtMillis: runAtMillis,
1016 recurring: recurring,
1018 timeoutKey: timeoutKey,
1022 if (runAtMillis in scheduledFunctions) {
1023 scheduledFunctions[runAtMillis].push(funcToSchedule);
1025 scheduledFunctions[runAtMillis] = [funcToSchedule];
1026 scheduledLookup.push(runAtMillis);
1027 scheduledLookup.sort(function (a, b) {
1035 self.removeFunctionWithId = function(timeoutKey) {
1036 for (var runAtMillis in scheduledFunctions) {
1037 var funcs = scheduledFunctions[runAtMillis];
1038 var i = indexOfFirstToPass(funcs, function (func) {
1039 return func.timeoutKey === timeoutKey;
1043 if (funcs.length === 1) {
1044 delete scheduledFunctions[runAtMillis];
1045 deleteFromLookup(runAtMillis);
1050 // intervals get rescheduled when executed, so there's never more
1051 // than a single scheduled function with a given timeoutKey
1057 self.reset = function() {
1059 scheduledLookup = [];
1060 scheduledFunctions = {};
1066 function indexOfFirstToPass(array, testFn) {
1069 for (var i = 0; i < array.length; ++i) {
1070 if (testFn(array[i])) {
1079 function deleteFromLookup(key) {
1080 var value = Number(key);
1081 var i = indexOfFirstToPass(scheduledLookup, function (millis) {
1082 return millis === value;
1086 scheduledLookup.splice(i, 1);
1090 function reschedule(scheduledFn) {
1091 self.scheduleFunction(scheduledFn.funcToCall,
1095 scheduledFn.timeoutKey,
1096 scheduledFn.runAtMillis + scheduledFn.millis);
1099 function runScheduledFunctions(endTime) {
1100 if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
1105 currentTime = scheduledLookup.shift();
1107 var funcsToRun = scheduledFunctions[currentTime];
1108 delete scheduledFunctions[currentTime];
1110 for (var i = 0; i < funcsToRun.length; ++i) {
1111 var funcToRun = funcsToRun[i];
1112 funcToRun.funcToCall.apply(null, funcToRun.params || []);
1114 if (funcToRun.recurring) {
1115 reschedule(funcToRun);
1118 } while (scheduledLookup.length > 0 &&
1119 // checking first if we're out of time prevents setTimeout(0)
1120 // scheduled in a funcToRun from forcing an extra iteration
1121 currentTime !== endTime &&
1122 scheduledLookup[0] <= endTime);
1126 return DelayedFunctionScheduler;
1129 getJasmineRequireObj().ExceptionFormatter = function() {
1130 function ExceptionFormatter() {
1131 this.message = function(error) {
1132 var message = error.name +
1136 if (error.fileName || error.sourceURL) {
1137 message += " in " + (error.fileName || error.sourceURL);
1140 if (error.line || error.lineNumber) {
1141 message += " (line " + (error.line || error.lineNumber) + ")";
1147 this.stack = function(error) {
1148 return error ? error.stack : null;
1152 return ExceptionFormatter;
1155 getJasmineRequireObj().Expectation = function() {
1159 function Expectation(options) {
1160 this.util = options.util || { buildFailureMessage: function() {} };
1161 this.customEqualityTesters = options.customEqualityTesters || [];
1162 this.actual = options.actual;
1163 this.addExpectationResult = options.addExpectationResult || function(){};
1164 this.isNot = options.isNot;
1166 for (var matcherName in matchers) {
1167 this[matcherName] = matchers[matcherName];
1171 Expectation.prototype.wrapCompare = function(name, matcherFactory) {
1173 var args = Array.prototype.slice.call(arguments, 0),
1174 expected = args.slice(0),
1177 args.unshift(this.actual);
1179 var matcher = matcherFactory(this.util, this.customEqualityTesters),
1180 matcherCompare = matcher.compare;
1182 function defaultNegativeCompare() {
1183 var result = matcher.compare.apply(null, args);
1184 result.pass = !result.pass;
1189 matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
1192 var result = matcherCompare.apply(null, args);
1195 if (!result.message) {
1196 args.unshift(this.isNot);
1198 message = this.util.buildFailureMessage.apply(null, args);
1200 message = result.message;
1204 if (expected.length == 1) {
1205 expected = expected[0];
1208 // TODO: how many of these params are needed?
1209 this.addExpectationResult(
1213 passed: result.pass,
1215 actual: this.actual,
1216 expected: expected // TODO: this may need to be arrayified/sliced
1222 Expectation.addCoreMatchers = function(matchers) {
1223 var prototype = Expectation.prototype;
1224 for (var matcherName in matchers) {
1225 var matcher = matchers[matcherName];
1226 prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
1230 Expectation.addMatchers = function(matchersToAdd) {
1231 for (var name in matchersToAdd) {
1232 var matcher = matchersToAdd[name];
1233 matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
1237 Expectation.resetMatchers = function() {
1238 for (var name in matchers) {
1239 delete matchers[name];
1243 Expectation.Factory = function(options) {
1244 options = options || {};
1246 var expect = new Expectation(options);
1248 // TODO: this would be nice as its own Object - NegativeExpectation
1249 // TODO: copy instead of mutate options
1250 options.isNot = true;
1251 expect.not = new Expectation(options);
1259 //TODO: expectation result may make more sense as a presentation of an expectation.
1260 getJasmineRequireObj().buildExpectationResult = function() {
1261 function buildExpectationResult(options) {
1262 var messageFormatter = options.messageFormatter || function() {},
1263 stackFormatter = options.stackFormatter || function() {};
1266 matcherName: options.matcherName,
1267 expected: options.expected,
1268 actual: options.actual,
1271 passed: options.passed
1274 function message() {
1275 if (options.passed) {
1277 } else if (options.message) {
1278 return options.message;
1279 } else if (options.error) {
1280 return messageFormatter(options.error);
1286 if (options.passed) {
1290 var error = options.error;
1293 throw new Error(message());
1298 return stackFormatter(error);
1302 return buildExpectationResult;
1305 getJasmineRequireObj().ObjectContaining = function(j$) {
1307 function ObjectContaining(sample) {
1308 this.sample = sample;
1311 ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
1312 if (typeof(this.sample) !== "object") { throw new Error("You must provide an object to objectContaining, not '"+this.sample+"'."); }
1314 mismatchKeys = mismatchKeys || [];
1315 mismatchValues = mismatchValues || [];
1317 var hasKey = function(obj, keyName) {
1318 return obj !== null && !j$.util.isUndefined(obj[keyName]);
1321 for (var property in this.sample) {
1322 if (!hasKey(other, property) && hasKey(this.sample, property)) {
1323 mismatchKeys.push("expected has key '" + property + "', but missing from actual.");
1325 else if (!j$.matchersUtil.equals(this.sample[property], other[property])) {
1326 mismatchValues.push("'" + property + "' was '" + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + "' in actual, but was '" + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + "' in expected.");
1330 return (mismatchKeys.length === 0 && mismatchValues.length === 0);
1333 ObjectContaining.prototype.jasmineToString = function() {
1334 return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>";
1337 return ObjectContaining;
1340 getJasmineRequireObj().pp = function(j$) {
1342 function PrettyPrinter() {
1343 this.ppNestLevel_ = 0;
1346 PrettyPrinter.prototype.format = function(value) {
1347 this.ppNestLevel_++;
1349 if (j$.util.isUndefined(value)) {
1350 this.emitScalar('undefined');
1351 } else if (value === null) {
1352 this.emitScalar('null');
1353 } else if (value === j$.getGlobal()) {
1354 this.emitScalar('<global>');
1355 } else if (value.jasmineToString) {
1356 this.emitScalar(value.jasmineToString());
1357 } else if (typeof value === 'string') {
1358 this.emitString(value);
1359 } else if (j$.isSpy(value)) {
1360 this.emitScalar("spy on " + value.and.identity());
1361 } else if (value instanceof RegExp) {
1362 this.emitScalar(value.toString());
1363 } else if (typeof value === 'function') {
1364 this.emitScalar('Function');
1365 } else if (typeof value.nodeType === 'number') {
1366 this.emitScalar('HTMLNode');
1367 } else if (value instanceof Date) {
1368 this.emitScalar('Date(' + value + ')');
1369 } else if (value.__Jasmine_been_here_before__) {
1370 this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
1371 } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
1372 value.__Jasmine_been_here_before__ = true;
1373 if (j$.isArray_(value)) {
1374 this.emitArray(value);
1376 this.emitObject(value);
1378 delete value.__Jasmine_been_here_before__;
1380 this.emitScalar(value.toString());
1383 this.ppNestLevel_--;
1387 PrettyPrinter.prototype.iterateObject = function(obj, fn) {
1388 for (var property in obj) {
1389 if (!obj.hasOwnProperty(property)) { continue; }
1390 if (property == '__Jasmine_been_here_before__') { continue; }
1391 fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
1392 obj.__lookupGetter__(property) !== null) : false);
1396 PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
1397 PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
1398 PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
1399 PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
1401 function StringPrettyPrinter() {
1402 PrettyPrinter.call(this);
1407 j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
1409 StringPrettyPrinter.prototype.emitScalar = function(value) {
1413 StringPrettyPrinter.prototype.emitString = function(value) {
1414 this.append("'" + value + "'");
1417 StringPrettyPrinter.prototype.emitArray = function(array) {
1418 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1419 this.append("Array");
1424 for (var i = 0; i < array.length; i++) {
1428 this.format(array[i]);
1433 StringPrettyPrinter.prototype.emitObject = function(obj) {
1434 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
1435 this.append("Object");
1443 this.iterateObject(obj, function(property, isGetter) {
1450 self.append(property);
1453 self.append('<getter>');
1455 self.format(obj[property]);
1462 StringPrettyPrinter.prototype.append = function(value) {
1463 this.string += value;
1466 return function(value) {
1467 var stringPrettyPrinter = new StringPrettyPrinter();
1468 stringPrettyPrinter.format(value);
1469 return stringPrettyPrinter.string;
1473 getJasmineRequireObj().QueueRunner = function() {
1475 function QueueRunner(attrs) {
1476 this.fns = attrs.fns || [];
1477 this.onComplete = attrs.onComplete || function() {};
1478 this.clearStack = attrs.clearStack || function(fn) {fn();};
1479 this.onException = attrs.onException || function() {};
1480 this.catchException = attrs.catchException || function() { return true; };
1481 this.userContext = {};
1484 QueueRunner.prototype.execute = function() {
1485 this.run(this.fns, 0);
1488 QueueRunner.prototype.run = function(fns, recursiveIndex) {
1489 var length = fns.length,
1493 for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
1494 var fn = fns[iterativeIndex];
1495 if (fn.length > 0) {
1496 return attemptAsync(fn);
1502 var runnerDone = iterativeIndex >= length;
1505 this.clearStack(this.onComplete);
1508 function attemptSync(fn) {
1510 fn.call(self.userContext);
1516 function attemptAsync(fn) {
1517 var next = function () { self.run(fns, iterativeIndex + 1); };
1520 fn.call(self.userContext, next);
1527 function handleException(e) {
1528 self.onException(e);
1529 if (!self.catchException(e)) {
1530 //TODO: set a var when we catch an exception and
1531 //use a finally block to close the loop in a nice way..
1540 getJasmineRequireObj().ReportDispatcher = function() {
1541 function ReportDispatcher(methods) {
1543 var dispatchedMethods = methods || [];
1545 for (var i = 0; i < dispatchedMethods.length; i++) {
1546 var method = dispatchedMethods[i];
1547 this[method] = (function(m) {
1549 dispatch(m, arguments);
1556 this.addReporter = function(reporter) {
1557 reporters.push(reporter);
1562 function dispatch(method, args) {
1563 for (var i = 0; i < reporters.length; i++) {
1564 var reporter = reporters[i];
1565 if (reporter[method]) {
1566 reporter[method].apply(reporter, args);
1572 return ReportDispatcher;
1576 getJasmineRequireObj().SpyStrategy = function() {
1578 function SpyStrategy(options) {
1579 options = options || {};
1581 var identity = options.name || "unknown",
1582 originalFn = options.fn || function() {},
1583 getSpy = options.getSpy || function() {},
1584 plan = function() {};
1586 this.identity = function() {
1590 this.exec = function() {
1591 return plan.apply(this, arguments);
1594 this.callThrough = function() {
1599 this.returnValue = function(value) {
1606 this.throwError = function(something) {
1607 var error = (something instanceof Error) ? something : new Error(something);
1614 this.callFake = function(fn) {
1619 this.stub = function(fn) {
1620 plan = function() {};
1628 getJasmineRequireObj().Suite = function() {
1629 function Suite(attrs) {
1630 this.env = attrs.env;
1632 this.parentSuite = attrs.parentSuite;
1633 this.description = attrs.description;
1634 this.onStart = attrs.onStart || function() {};
1635 this.resultCallback = attrs.resultCallback || function() {};
1636 this.clearStack = attrs.clearStack || function(fn) {fn();};
1638 this.beforeFns = [];
1640 this.queueRunner = attrs.queueRunner || function() {};
1641 this.disabled = false;
1647 status: this.disabled ? 'disabled' : '',
1648 description: this.description,
1649 fullName: this.getFullName()
1653 Suite.prototype.getFullName = function() {
1654 var fullName = this.description;
1655 for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
1656 if (parentSuite.parentSuite) {
1657 fullName = parentSuite.description + ' ' + fullName;
1663 Suite.prototype.disable = function() {
1664 this.disabled = true;
1667 Suite.prototype.beforeEach = function(fn) {
1668 this.beforeFns.unshift(fn);
1671 Suite.prototype.afterEach = function(fn) {
1672 this.afterFns.unshift(fn);
1675 Suite.prototype.addChild = function(child) {
1676 this.children.push(child);
1679 Suite.prototype.execute = function(onComplete) {
1681 if (this.disabled) {
1688 for (var i = 0; i < this.children.length; i++) {
1689 allFns.push(wrapChildAsAsync(this.children[i]));
1696 onComplete: complete
1699 function complete() {
1700 self.resultCallback(self.result);
1707 function wrapChildAsAsync(child) {
1708 return function(done) { child.execute(done); };
1715 if (typeof window == void 0 && typeof exports == "object") {
1716 exports.Suite = jasmineRequire.Suite;
1719 getJasmineRequireObj().Timer = function() {
1720 function Timer(options) {
1721 options = options || {};
1723 var now = options.now || function() { return new Date().getTime(); },
1726 this.start = function() {
1730 this.elapsed = function() {
1731 return now() - startTime;
1738 getJasmineRequireObj().matchersUtil = function(j$) {
1739 // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
1742 equals: function(a, b, customTesters) {
1743 customTesters = customTesters || [];
1745 return eq(a, b, [], [], customTesters);
1748 contains: function(haystack, needle, customTesters) {
1749 customTesters = customTesters || [];
1751 if (Object.prototype.toString.apply(haystack) === "[object Array]") {
1752 for (var i = 0; i < haystack.length; i++) {
1753 if (eq(haystack[i], needle, [], [], customTesters)) {
1759 return haystack.indexOf(needle) >= 0;
1762 buildFailureMessage: function() {
1763 var args = Array.prototype.slice.call(arguments, 0),
1764 matcherName = args[0],
1767 expected = args.slice(3),
1768 englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
1770 var message = "Expected " +
1772 (isNot ? " not " : " ") +
1775 if (expected.length > 0) {
1776 for (var i = 0; i < expected.length; i++) {
1780 message += " " + j$.pp(expected[i]);
1784 return message + ".";
1788 // Equality function lovingly adapted from isEqual in
1789 // [Underscore](http://underscorejs.org)
1790 function eq(a, b, aStack, bStack, customTesters) {
1793 for (var i = 0; i < customTesters.length; i++) {
1794 var customTesterResult = customTesters[i](a, b);
1795 if (!j$.util.isUndefined(customTesterResult)) {
1796 return customTesterResult;
1800 if (a instanceof j$.Any) {
1801 result = a.jasmineMatches(b);
1807 if (b instanceof j$.Any) {
1808 result = b.jasmineMatches(a);
1814 if (b instanceof j$.ObjectContaining) {
1815 result = b.jasmineMatches(a);
1821 if (a instanceof Error && b instanceof Error) {
1822 return a.message == b.message;
1825 // Identical objects are equal. `0 === -0`, but they aren't identical.
1826 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
1827 if (a === b) { return a !== 0 || 1 / a == 1 / b; }
1828 // A strict comparison is necessary because `null == undefined`.
1829 if (a === null || b === null) { return a === b; }
1830 var className = Object.prototype.toString.call(a);
1831 if (className != Object.prototype.toString.call(b)) { return false; }
1832 switch (className) {
1833 // Strings, numbers, dates, and booleans are compared by value.
1834 case '[object String]':
1835 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
1836 // equivalent to `new String("5")`.
1837 return a == String(b);
1838 case '[object Number]':
1839 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
1840 // other numeric values.
1841 return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
1842 case '[object Date]':
1843 case '[object Boolean]':
1844 // Coerce dates and booleans to numeric primitive values. Dates are compared by their
1845 // millisecond representations. Note that invalid dates with millisecond representations
1846 // of `NaN` are not equivalent.
1848 // RegExps are compared by their source patterns and flags.
1849 case '[object RegExp]':
1850 return a.source == b.source &&
1851 a.global == b.global &&
1852 a.multiline == b.multiline &&
1853 a.ignoreCase == b.ignoreCase;
1855 if (typeof a != 'object' || typeof b != 'object') { return false; }
1856 // Assume equality for cyclic structures. The algorithm for detecting cyclic
1857 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
1858 var length = aStack.length;
1860 // Linear search. Performance is inversely proportional to the number of
1861 // unique nested structures.
1862 if (aStack[length] == a) { return bStack[length] == b; }
1864 // Add the first object to the stack of traversed objects.
1868 // Recursively compare objects and arrays.
1869 if (className == '[object Array]') {
1870 // Compare array lengths to determine if a deep comparison is necessary.
1872 result = size == b.length;
1874 // Deep compare the contents, ignoring non-numeric properties.
1876 if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
1880 // Objects with different constructors are not equivalent, but `Object`s
1881 // from different frames are.
1882 var aCtor = a.constructor, bCtor = b.constructor;
1883 if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
1884 isFunction(bCtor) && (bCtor instanceof bCtor))) {
1887 // Deep compare objects.
1888 for (var key in a) {
1890 // Count the expected number of properties.
1892 // Deep compare each member.
1893 if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
1896 // Ensure that both objects contain the same number of properties.
1899 if (has(b, key) && !(size--)) { break; }
1904 // Remove the first object from the stack of traversed objects.
1910 function has(obj, key) {
1911 return obj.hasOwnProperty(key);
1914 function isFunction(obj) {
1915 return typeof obj === 'function';
1920 getJasmineRequireObj().toBe = function() {
1923 compare: function(actual, expected) {
1925 pass: actual === expected
1934 getJasmineRequireObj().toBeCloseTo = function() {
1936 function toBeCloseTo() {
1938 compare: function(actual, expected, precision) {
1939 if (precision !== 0) {
1940 precision = precision || 2;
1944 pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
1953 getJasmineRequireObj().toBeDefined = function() {
1954 function toBeDefined() {
1956 compare: function(actual) {
1958 pass: (void 0 !== actual)
1967 getJasmineRequireObj().toBeFalsy = function() {
1968 function toBeFalsy() {
1970 compare: function(actual) {
1981 getJasmineRequireObj().toBeGreaterThan = function() {
1983 function toBeGreaterThan() {
1985 compare: function(actual, expected) {
1987 pass: actual > expected
1993 return toBeGreaterThan;
1997 getJasmineRequireObj().toBeLessThan = function() {
1998 function toBeLessThan() {
2001 compare: function(actual, expected) {
2003 pass: actual < expected
2009 return toBeLessThan;
2011 getJasmineRequireObj().toBeNaN = function(j$) {
2013 function toBeNaN() {
2015 compare: function(actual) {
2017 pass: (actual !== actual)
2021 result.message = "Expected actual not to be NaN.";
2023 result.message = "Expected " + j$.pp(actual) + " to be NaN.";
2034 getJasmineRequireObj().toBeNull = function() {
2036 function toBeNull() {
2038 compare: function(actual) {
2040 pass: actual === null
2049 getJasmineRequireObj().toBeTruthy = function() {
2051 function toBeTruthy() {
2053 compare: function(actual) {
2064 getJasmineRequireObj().toBeUndefined = function() {
2066 function toBeUndefined() {
2068 compare: function(actual) {
2070 pass: void 0 === actual
2076 return toBeUndefined;
2079 getJasmineRequireObj().toContain = function() {
2080 function toContain(util, customEqualityTesters) {
2081 customEqualityTesters = customEqualityTesters || [];
2084 compare: function(actual, expected) {
2087 pass: util.contains(actual, expected, customEqualityTesters)
2096 getJasmineRequireObj().toEqual = function() {
2098 function toEqual(util, customEqualityTesters) {
2099 customEqualityTesters = customEqualityTesters || [];
2102 compare: function(actual, expected) {
2107 result.pass = util.equals(actual, expected, customEqualityTesters);
2117 getJasmineRequireObj().toHaveBeenCalled = function(j$) {
2119 function toHaveBeenCalled() {
2121 compare: function(actual) {
2124 if (!j$.isSpy(actual)) {
2125 throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
2128 if (arguments.length > 1) {
2129 throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
2132 result.pass = actual.calls.any();
2134 result.message = result.pass ?
2135 "Expected spy " + actual.and.identity() + " not to have been called." :
2136 "Expected spy " + actual.and.identity() + " to have been called.";
2143 return toHaveBeenCalled;
2146 getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
2148 function toHaveBeenCalledWith(util) {
2150 compare: function() {
2151 var args = Array.prototype.slice.call(arguments, 0),
2153 expectedArgs = args.slice(1),
2154 result = { pass: false };
2156 if (!j$.isSpy(actual)) {
2157 throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
2160 if (!actual.calls.any()) {
2161 result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but it was never called.";
2165 if (util.contains(actual.calls.allArgs(), expectedArgs)) {
2167 result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was.";
2169 result.message = "Expected spy " + actual.and.identity() + " to have been called with " + j$.pp(expectedArgs) + " but actual calls were " + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + ".";
2177 return toHaveBeenCalledWith;
2180 getJasmineRequireObj().toMatch = function() {
2182 function toMatch() {
2184 compare: function(actual, expected) {
2185 var regexp = new RegExp(expected);
2188 pass: regexp.test(actual)
2197 getJasmineRequireObj().toThrow = function(j$) {
2199 function toThrow(util) {
2201 compare: function(actual, expected) {
2202 var result = { pass: false },
2206 if (typeof actual != "function") {
2207 throw new Error("Actual is not a Function");
2218 result.message = "Expected function to throw an exception.";
2222 if (arguments.length == 1) {
2224 result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + ".";
2229 if (util.equals(thrown, expected)) {
2231 result.message = "Expected function not to throw " + j$.pp(expected) + ".";
2233 result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + ".";
2244 getJasmineRequireObj().toThrowError = function(j$) {
2245 function toThrowError (util) {
2247 compare: function(actual) {
2256 if (typeof actual != "function") {
2257 throw new Error("Actual is not a Function");
2260 extractExpectedParams.apply(null, arguments);
2270 return fail("Expected function to throw an Error.");
2273 if (!(thrown instanceof Error)) {
2274 return fail("Expected function to throw an Error, but it threw " + thrown + ".");
2277 if (arguments.length == 1) {
2278 return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + ".");
2282 name = fnNameFor(errorType);
2283 constructorName = fnNameFor(thrown.constructor);
2286 if (errorType && message) {
2287 if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
2288 return pass("Expected function not to throw " + name + " with message \"" + message + "\".");
2290 return fail("Expected function to throw " + name + " with message \"" + message +
2291 "\", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2295 if (errorType && regexp) {
2296 if (thrown.constructor == errorType && regexp.test(thrown.message)) {
2297 return pass("Expected function not to throw " + name + " with message matching " + regexp + ".");
2299 return fail("Expected function to throw " + name + " with message matching " + regexp +
2300 ", but it threw " + constructorName + " with message \"" + thrown.message + "\".");
2305 if (thrown.constructor == errorType) {
2306 return pass("Expected function not to throw " + name + ".");
2308 return fail("Expected function to throw " + name + ", but it threw " + constructorName + ".");
2313 if (thrown.message == message) {
2314 return pass("Expected function not to throw an exception with message " + j$.pp(message) + ".");
2316 return fail("Expected function to throw an exception with message " + j$.pp(message) +
2317 ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2322 if (regexp.test(thrown.message)) {
2323 return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + ".");
2325 return fail("Expected function to throw an exception with a message matching " + j$.pp(regexp) +
2326 ", but it threw an exception with message " + j$.pp(thrown.message) + ".");
2330 function fnNameFor(func) {
2331 return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
2334 function pass(notMessage) {
2341 function fail(message) {
2348 function extractExpectedParams() {
2349 if (arguments.length == 1) {
2353 if (arguments.length == 2) {
2354 var expected = arguments[1];
2356 if (expected instanceof RegExp) {
2358 } else if (typeof expected == "string") {
2360 } else if (checkForAnErrorType(expected)) {
2361 errorType = expected;
2364 if (!(errorType || message || regexp)) {
2365 throw new Error("Expected is not an Error, string, or RegExp.");
2368 if (checkForAnErrorType(arguments[1])) {
2369 errorType = arguments[1];
2371 throw new Error("Expected error type is not an Error.");
2374 if (arguments[2] instanceof RegExp) {
2375 regexp = arguments[2];
2376 } else if (typeof arguments[2] == "string") {
2377 message = arguments[2];
2379 throw new Error("Expected error message is not a string or RegExp.");
2384 function checkForAnErrorType(type) {
2385 if (typeof type !== "function") {
2389 var Surrogate = function() {};
2390 Surrogate.prototype = type.prototype;
2391 return (new Surrogate()) instanceof Error;
2397 return toThrowError;
2400 getJasmineRequireObj().version = function() {