github.com/kvattikuti/drone@v0.2.1-0.20140603034306-d400229a327a/cmd/droned/assets/test/lib/jasmine-2.0.0/jasmine.js (about) 1 /* 2 Copyright (c) 2008-2013 Pivotal Labs 3 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: 11 12 The above copyright notice and this permission notice shall be 13 included in all copies or substantial portions of the Software. 14 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. 22 */ 23 function getJasmineRequireObj() { 24 if (typeof module !== "undefined" && module.exports) { 25 return exports; 26 } else { 27 window.jasmineRequire = window.jasmineRequire || {}; 28 return window.jasmineRequire; 29 } 30 } 31 32 getJasmineRequireObj().core = function(jRequire) { 33 var j$ = {}; 34 35 jRequire.base(j$); 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(); 56 57 j$.matchers = jRequire.requireMatchers(jRequire, j$); 58 59 return j$; 60 }; 61 62 getJasmineRequireObj().requireMatchers = function(jRequire, j$) { 63 var availableMatchers = [ 64 "toBe", 65 "toBeCloseTo", 66 "toBeDefined", 67 "toBeFalsy", 68 "toBeGreaterThan", 69 "toBeLessThan", 70 "toBeNaN", 71 "toBeNull", 72 "toBeTruthy", 73 "toBeUndefined", 74 "toContain", 75 "toEqual", 76 "toHaveBeenCalled", 77 "toHaveBeenCalledWith", 78 "toMatch", 79 "toThrow", 80 "toThrowError" 81 ], 82 matchers = {}; 83 84 for (var i = 0; i < availableMatchers.length; i++) { 85 var name = availableMatchers[i]; 86 matchers[name] = jRequire[name](j$); 87 } 88 89 return matchers; 90 }; 91 92 getJasmineRequireObj().base = function(j$) { 93 j$.unimplementedMethod_ = function() { 94 throw new Error("unimplemented method"); 95 }; 96 97 j$.MAX_PRETTY_PRINT_DEPTH = 40; 98 j$.DEFAULT_TIMEOUT_INTERVAL = 5000; 99 100 j$.getGlobal = (function() { 101 var jasmineGlobal = eval.call(null, "this"); 102 return function() { 103 return jasmineGlobal; 104 }; 105 })(); 106 107 j$.getEnv = function(options) { 108 var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options); 109 //jasmine. singletons in here (setTimeout blah blah). 110 return env; 111 }; 112 113 j$.isArray_ = function(value) { 114 return j$.isA_("Array", value); 115 }; 116 117 j$.isString_ = function(value) { 118 return j$.isA_("String", value); 119 }; 120 121 j$.isNumber_ = function(value) { 122 return j$.isA_("Number", value); 123 }; 124 125 j$.isA_ = function(typeName, value) { 126 return Object.prototype.toString.apply(value) === '[object ' + typeName + ']'; 127 }; 128 129 j$.isDomNode = function(obj) { 130 return obj.nodeType > 0; 131 }; 132 133 j$.any = function(clazz) { 134 return new j$.Any(clazz); 135 }; 136 137 j$.objectContaining = function(sample) { 138 return new j$.ObjectContaining(sample); 139 }; 140 141 j$.createSpy = function(name, originalFn) { 142 143 var spyStrategy = new j$.SpyStrategy({ 144 name: name, 145 fn: originalFn, 146 getSpy: function() { return spy; } 147 }), 148 callTracker = new j$.CallTracker(), 149 spy = function() { 150 callTracker.track({ 151 object: this, 152 args: Array.prototype.slice.apply(arguments) 153 }); 154 return spyStrategy.exec.apply(this, arguments); 155 }; 156 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"); 160 } 161 162 spy[prop] = originalFn[prop]; 163 } 164 165 spy.and = spyStrategy; 166 spy.calls = callTracker; 167 168 return spy; 169 }; 170 171 j$.isSpy = function(putativeSpy) { 172 if (!putativeSpy) { 173 return false; 174 } 175 return putativeSpy.and instanceof j$.SpyStrategy && 176 putativeSpy.calls instanceof j$.CallTracker; 177 }; 178 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"; 182 } 183 var obj = {}; 184 for (var i = 0; i < methodNames.length; i++) { 185 obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]); 186 } 187 return obj; 188 }; 189 }; 190 191 getJasmineRequireObj().util = function() { 192 193 var util = {}; 194 195 util.inherit = function(childClass, parentClass) { 196 var Subclass = function() { 197 }; 198 Subclass.prototype = parentClass.prototype; 199 childClass.prototype = new Subclass(); 200 }; 201 202 util.htmlEscape = function(str) { 203 if (!str) { 204 return str; 205 } 206 return str.replace(/&/g, '&') 207 .replace(/</g, '<') 208 .replace(/>/g, '>'); 209 }; 210 211 util.argsToArray = function(args) { 212 var arrayOfArgs = []; 213 for (var i = 0; i < args.length; i++) { 214 arrayOfArgs.push(args[i]); 215 } 216 return arrayOfArgs; 217 }; 218 219 util.isUndefined = function(obj) { 220 return obj === void 0; 221 }; 222 223 return util; 224 }; 225 226 getJasmineRequireObj().Spec = function(j$) { 227 function Spec(attrs) { 228 this.expectationFactory = attrs.expectationFactory; 229 this.resultCallback = attrs.resultCallback || function() {}; 230 this.id = attrs.id; 231 this.description = attrs.description || ''; 232 this.fn = attrs.fn; 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; }; 241 242 this.timer = attrs.timer || {setTimeout: setTimeout, clearTimeout: clearTimeout}; 243 244 if (!this.fn) { 245 this.pend(); 246 } 247 248 this.result = { 249 id: this.id, 250 description: this.description, 251 fullName: this.getFullName(), 252 failedExpectations: [] 253 }; 254 } 255 256 Spec.prototype.addExpectationResult = function(passed, data) { 257 if (passed) { 258 return; 259 } 260 this.result.failedExpectations.push(this.expectationResultFactory(data)); 261 }; 262 263 Spec.prototype.expect = function(actual) { 264 return this.expectationFactory(actual, this); 265 }; 266 267 Spec.prototype.execute = function(onComplete) { 268 var self = this, 269 timeout; 270 271 this.onStart(this); 272 273 if (this.markedPending || this.disabled) { 274 complete(); 275 return; 276 } 277 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.')); 282 done(); 283 }, j$.DEFAULT_TIMEOUT_INTERVAL]]); 284 285 var callDone = function() { 286 clearTimeoutable(); 287 done(); 288 }; 289 290 fn.call(this, callDone); //TODO: do we care about more than 1 arg? 291 }; 292 } 293 294 function clearTimeoutable() { 295 Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeout]]); 296 timeout = void 0; 297 } 298 299 var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns()), 300 allTimeoutableFns = []; 301 for (var i = 0; i < allFns.length; i++) { 302 var fn = allFns[i]; 303 allTimeoutableFns.push(fn.length > 0 ? timeoutable(fn) : fn); 304 } 305 306 this.queueRunnerFactory({ 307 fns: allTimeoutableFns, 308 onException: onException, 309 onComplete: complete 310 }); 311 312 function onException(e) { 313 clearTimeoutable(); 314 if (Spec.isPendingSpecException(e)) { 315 self.pend(); 316 return; 317 } 318 319 self.addExpectationResult(false, { 320 matcherName: "", 321 passed: false, 322 expected: "", 323 actual: "", 324 error: e 325 }); 326 } 327 328 function complete() { 329 self.result.status = self.status(); 330 self.resultCallback(self.result); 331 332 if (onComplete) { 333 onComplete(); 334 } 335 } 336 }; 337 338 Spec.prototype.disable = function() { 339 this.disabled = true; 340 }; 341 342 Spec.prototype.pend = function() { 343 this.markedPending = true; 344 }; 345 346 Spec.prototype.status = function() { 347 if (this.disabled) { 348 return 'disabled'; 349 } 350 351 if (this.markedPending) { 352 return 'pending'; 353 } 354 355 if (this.result.failedExpectations.length > 0) { 356 return 'failed'; 357 } else { 358 return 'passed'; 359 } 360 }; 361 362 Spec.prototype.getFullName = function() { 363 return this.getSpecName(this); 364 }; 365 366 Spec.pendingSpecExceptionMessage = "=> marked Pending"; 367 368 Spec.isPendingSpecException = function(e) { 369 return e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1; 370 }; 371 372 return Spec; 373 }; 374 375 if (typeof window == void 0 && typeof exports == "object") { 376 exports.Spec = jasmineRequire.Spec; 377 } 378 379 getJasmineRequireObj().Env = function(j$) { 380 function Env(options) { 381 options = options || {}; 382 383 var self = this; 384 var global = options.global || j$.getGlobal(); 385 386 var totalSpecsDefined = 0; 387 388 var catchExceptions = true; 389 390 var realSetTimeout = j$.getGlobal().setTimeout; 391 var realClearTimeout = j$.getGlobal().clearTimeout; 392 this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler()); 393 394 var runnableLookupTable = {}; 395 396 var spies = []; 397 398 var currentSpec = null; 399 var currentSuite = null; 400 401 var reporter = new j$.ReportDispatcher([ 402 "jasmineStarted", 403 "jasmineDone", 404 "suiteStarted", 405 "suiteDone", 406 "specStarted", 407 "specDone" 408 ]); 409 410 this.specFilter = function() { 411 return true; 412 }; 413 414 var equalityTesters = []; 415 416 var customEqualityTesters = []; 417 this.addCustomEqualityTester = function(tester) { 418 customEqualityTesters.push(tester); 419 }; 420 421 j$.Expectation.addCoreMatchers(j$.matchers); 422 423 var nextSpecId = 0; 424 var getNextSpecId = function() { 425 return 'spec' + nextSpecId++; 426 }; 427 428 var nextSuiteId = 0; 429 var getNextSuiteId = function() { 430 return 'suite' + nextSuiteId++; 431 }; 432 433 var expectationFactory = function(actual, spec) { 434 return j$.Expectation.Factory({ 435 util: j$.matchersUtil, 436 customEqualityTesters: customEqualityTesters, 437 actual: actual, 438 addExpectationResult: addExpectationResult 439 }); 440 441 function addExpectationResult(passed, result) { 442 return spec.addExpectationResult(passed, result); 443 } 444 }; 445 446 var specStarted = function(spec) { 447 currentSpec = spec; 448 reporter.specStarted(spec.result); 449 }; 450 451 var beforeFns = function(suite) { 452 return function() { 453 var befores = []; 454 while(suite) { 455 befores = befores.concat(suite.beforeFns); 456 suite = suite.parentSuite; 457 } 458 return befores.reverse(); 459 }; 460 }; 461 462 var afterFns = function(suite) { 463 return function() { 464 var afters = []; 465 while(suite) { 466 afters = afters.concat(suite.afterFns); 467 suite = suite.parentSuite; 468 } 469 return afters; 470 }; 471 }; 472 473 var getSpecName = function(spec, suite) { 474 return suite.getFullName() + ' ' + spec.description; 475 }; 476 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; 483 484 return buildExpectationResult(attrs); 485 }; 486 487 // TODO: fix this naming, and here's where the value comes in 488 this.catchExceptions = function(value) { 489 catchExceptions = !!value; 490 return catchExceptions; 491 }; 492 493 this.catchingExceptions = function() { 494 return catchExceptions; 495 }; 496 497 var maximumSpecCallbackDepth = 20; 498 var currentSpecCallbackDepth = 0; 499 500 function clearStack(fn) { 501 currentSpecCallbackDepth++; 502 if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) { 503 currentSpecCallbackDepth = 0; 504 realSetTimeout(fn, 0); 505 } else { 506 fn(); 507 } 508 } 509 510 var catchException = function(e) { 511 return j$.Spec.isPendingSpecException(e) || catchExceptions; 512 }; 513 514 var queueRunnerFactory = function(options) { 515 options.catchException = catchException; 516 options.clearStack = options.clearStack || clearStack; 517 518 new j$.QueueRunner(options).execute(); 519 }; 520 521 var topSuite = new j$.Suite({ 522 env: this, 523 id: getNextSuiteId(), 524 description: 'Jasmine__TopLevel__Suite', 525 queueRunner: queueRunnerFactory, 526 resultCallback: function() {} // TODO - hook this up 527 }); 528 runnableLookupTable[topSuite.id] = topSuite; 529 currentSuite = topSuite; 530 531 this.topSuite = function() { 532 return topSuite; 533 }; 534 535 this.execute = function(runnablesToRun) { 536 runnablesToRun = runnablesToRun || [topSuite.id]; 537 538 var allFns = []; 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)); 542 } 543 544 reporter.jasmineStarted({ 545 totalSpecsDefined: totalSpecsDefined 546 }); 547 548 queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone}); 549 }; 550 551 this.addReporter = function(reporterToAdd) { 552 reporter.addReporter(reporterToAdd); 553 }; 554 555 this.addMatchers = function(matchersToAdd) { 556 j$.Expectation.addMatchers(matchersToAdd); 557 }; 558 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 + "()"); 562 } 563 564 if (j$.util.isUndefined(obj[methodName])) { 565 throw new Error(methodName + '() method does not exist'); 566 } 567 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'); 571 } 572 573 var spy = j$.createSpy(methodName, obj[methodName]); 574 575 spies.push({ 576 spy: spy, 577 baseObj: obj, 578 methodName: methodName, 579 originalValue: obj[methodName] 580 }); 581 582 obj[methodName] = spy; 583 584 return spy; 585 }; 586 587 var suiteFactory = function(description) { 588 var suite = new j$.Suite({ 589 env: self, 590 id: getNextSuiteId(), 591 description: description, 592 parentSuite: currentSuite, 593 queueRunner: queueRunnerFactory, 594 onStart: suiteStarted, 595 resultCallback: function(attrs) { 596 reporter.suiteDone(attrs); 597 } 598 }); 599 600 runnableLookupTable[suite.id] = suite; 601 return suite; 602 }; 603 604 this.describe = function(description, specDefinitions) { 605 var suite = suiteFactory(description); 606 607 var parentSuite = currentSuite; 608 parentSuite.addChild(suite); 609 currentSuite = suite; 610 611 var declarationError = null; 612 try { 613 specDefinitions.call(suite); 614 } catch (e) { 615 declarationError = e; 616 } 617 618 if (declarationError) { 619 this.it("encountered a declaration exception", function() { 620 throw declarationError; 621 }); 622 } 623 624 currentSuite = parentSuite; 625 626 return suite; 627 }; 628 629 this.xdescribe = function(description, specDefinitions) { 630 var suite = this.describe(description, specDefinitions); 631 suite.disable(); 632 return suite; 633 }; 634 635 var specFactory = function(description, fn, suite) { 636 totalSpecsDefined++; 637 638 var spec = new j$.Spec({ 639 id: getNextSpecId(), 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); 647 }, 648 onStart: specStarted, 649 description: description, 650 expectationResultFactory: expectationResultFactory, 651 queueRunnerFactory: queueRunnerFactory, 652 fn: fn, 653 timer: {setTimeout: realSetTimeout, clearTimeout: realClearTimeout} 654 }); 655 656 runnableLookupTable[spec.id] = spec; 657 658 if (!self.specFilter(spec)) { 659 spec.disable(); 660 } 661 662 return spec; 663 664 function removeAllSpies() { 665 for (var i = 0; i < spies.length; i++) { 666 var spyEntry = spies[i]; 667 spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue; 668 } 669 spies = []; 670 } 671 672 function specResultCallback(result) { 673 removeAllSpies(); 674 j$.Expectation.resetMatchers(); 675 customEqualityTesters = []; 676 currentSpec = null; 677 reporter.specDone(result); 678 } 679 }; 680 681 var suiteStarted = function(suite) { 682 reporter.suiteStarted(suite.result); 683 }; 684 685 this.it = function(description, fn) { 686 var spec = specFactory(description, fn, currentSuite); 687 currentSuite.addChild(spec); 688 return spec; 689 }; 690 691 this.xit = function(description, fn) { 692 var spec = this.it(description, fn); 693 spec.pend(); 694 return spec; 695 }; 696 697 this.expect = function(actual) { 698 return currentSpec.expect(actual); 699 }; 700 701 this.beforeEach = function(beforeEachFunction) { 702 currentSuite.beforeEach(beforeEachFunction); 703 }; 704 705 this.afterEach = function(afterEachFunction) { 706 currentSuite.afterEach(afterEachFunction); 707 }; 708 709 this.pending = function() { 710 throw j$.Spec.pendingSpecExceptionMessage; 711 }; 712 } 713 714 return Env; 715 }; 716 717 getJasmineRequireObj().JsApiReporter = function() { 718 719 var noopTimer = { 720 start: function(){}, 721 elapsed: function(){ return 0; } 722 }; 723 724 function JsApiReporter(options) { 725 var timer = options.timer || noopTimer, 726 status = "loaded"; 727 728 this.started = false; 729 this.finished = false; 730 731 this.jasmineStarted = function() { 732 this.started = true; 733 status = 'started'; 734 timer.start(); 735 }; 736 737 var executionTime; 738 739 this.jasmineDone = function() { 740 this.finished = true; 741 executionTime = timer.elapsed(); 742 status = 'done'; 743 }; 744 745 this.status = function() { 746 return status; 747 }; 748 749 var suites = {}; 750 751 this.suiteStarted = function(result) { 752 storeSuite(result); 753 }; 754 755 this.suiteDone = function(result) { 756 storeSuite(result); 757 }; 758 759 function storeSuite(result) { 760 suites[result.id] = result; 761 } 762 763 this.suites = function() { 764 return suites; 765 }; 766 767 var specs = []; 768 this.specStarted = function(result) { }; 769 770 this.specDone = function(result) { 771 specs.push(result); 772 }; 773 774 this.specResults = function(index, length) { 775 return specs.slice(index, index + length); 776 }; 777 778 this.specs = function() { 779 return specs; 780 }; 781 782 this.executionTime = function() { 783 return executionTime; 784 }; 785 786 } 787 788 return JsApiReporter; 789 }; 790 791 getJasmineRequireObj().Any = function() { 792 793 function Any(expectedObject) { 794 this.expectedObject = expectedObject; 795 } 796 797 Any.prototype.jasmineMatches = function(other) { 798 if (this.expectedObject == String) { 799 return typeof other == 'string' || other instanceof String; 800 } 801 802 if (this.expectedObject == Number) { 803 return typeof other == 'number' || other instanceof Number; 804 } 805 806 if (this.expectedObject == Function) { 807 return typeof other == 'function' || other instanceof Function; 808 } 809 810 if (this.expectedObject == Object) { 811 return typeof other == 'object'; 812 } 813 814 if (this.expectedObject == Boolean) { 815 return typeof other == 'boolean'; 816 } 817 818 return other instanceof this.expectedObject; 819 }; 820 821 Any.prototype.jasmineToString = function() { 822 return '<jasmine.any(' + this.expectedClass + ')>'; 823 }; 824 825 return Any; 826 }; 827 828 getJasmineRequireObj().CallTracker = function() { 829 830 function CallTracker() { 831 var calls = []; 832 833 this.track = function(context) { 834 calls.push(context); 835 }; 836 837 this.any = function() { 838 return !!calls.length; 839 }; 840 841 this.count = function() { 842 return calls.length; 843 }; 844 845 this.argsFor = function(index) { 846 var call = calls[index]; 847 return call ? call.args : []; 848 }; 849 850 this.all = function() { 851 return calls; 852 }; 853 854 this.allArgs = function() { 855 var callArgs = []; 856 for(var i = 0; i < calls.length; i++){ 857 callArgs.push(calls[i].args); 858 } 859 860 return callArgs; 861 }; 862 863 this.first = function() { 864 return calls[0]; 865 }; 866 867 this.mostRecent = function() { 868 return calls[calls.length - 1]; 869 }; 870 871 this.reset = function() { 872 calls = []; 873 }; 874 } 875 876 return CallTracker; 877 }; 878 879 getJasmineRequireObj().Clock = function() { 880 function Clock(global, delayedFunctionScheduler) { 881 var self = this, 882 realTimingFunctions = { 883 setTimeout: global.setTimeout, 884 clearTimeout: global.clearTimeout, 885 setInterval: global.setInterval, 886 clearInterval: global.clearInterval 887 }, 888 fakeTimingFunctions = { 889 setTimeout: setTimeout, 890 clearTimeout: clearTimeout, 891 setInterval: setInterval, 892 clearInterval: clearInterval 893 }, 894 installed = false, 895 timer; 896 897 self.install = function() { 898 replace(global, fakeTimingFunctions); 899 timer = fakeTimingFunctions; 900 installed = true; 901 }; 902 903 self.uninstall = function() { 904 delayedFunctionScheduler.reset(); 905 replace(global, realTimingFunctions); 906 timer = realTimingFunctions; 907 installed = false; 908 }; 909 910 self.setTimeout = function(fn, delay, params) { 911 if (legacyIE()) { 912 if (arguments.length > 2) { 913 throw new Error("IE < 9 cannot support extra params to setTimeout without a polyfill"); 914 } 915 return timer.setTimeout(fn, delay); 916 } 917 return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]); 918 }; 919 920 self.setInterval = function(fn, delay, params) { 921 if (legacyIE()) { 922 if (arguments.length > 2) { 923 throw new Error("IE < 9 cannot support extra params to setInterval without a polyfill"); 924 } 925 return timer.setInterval(fn, delay); 926 } 927 return Function.prototype.apply.apply(timer.setInterval, [global, arguments]); 928 }; 929 930 self.clearTimeout = function(id) { 931 return Function.prototype.call.apply(timer.clearTimeout, [global, id]); 932 }; 933 934 self.clearInterval = function(id) { 935 return Function.prototype.call.apply(timer.clearInterval, [global, id]); 936 }; 937 938 self.tick = function(millis) { 939 if (installed) { 940 delayedFunctionScheduler.tick(millis); 941 } else { 942 throw new Error("Mock clock is not installed, use jasmine.clock().install()"); 943 } 944 }; 945 946 return self; 947 948 function legacyIE() { 949 //if these methods are polyfilled, apply will be present 950 return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply; 951 } 952 953 function replace(dest, source) { 954 for (var prop in source) { 955 dest[prop] = source[prop]; 956 } 957 } 958 959 function setTimeout(fn, delay) { 960 return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2)); 961 } 962 963 function clearTimeout(id) { 964 return delayedFunctionScheduler.removeFunctionWithId(id); 965 } 966 967 function setInterval(fn, interval) { 968 return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true); 969 } 970 971 function clearInterval(id) { 972 return delayedFunctionScheduler.removeFunctionWithId(id); 973 } 974 975 function argSlice(argsObj, n) { 976 return Array.prototype.slice.call(argsObj, 2); 977 } 978 } 979 980 return Clock; 981 }; 982 983 getJasmineRequireObj().DelayedFunctionScheduler = function() { 984 function DelayedFunctionScheduler() { 985 var self = this; 986 var scheduledLookup = []; 987 var scheduledFunctions = {}; 988 var currentTime = 0; 989 var delayedFnCount = 0; 990 991 self.tick = function(millis) { 992 millis = millis || 0; 993 var endTime = currentTime + millis; 994 995 runScheduledFunctions(endTime); 996 currentTime = endTime; 997 }; 998 999 self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) { 1000 var f; 1001 if (typeof(funcToCall) === 'string') { 1002 /* jshint evil: true */ 1003 f = function() { return eval(funcToCall); }; 1004 /* jshint evil: false */ 1005 } else { 1006 f = funcToCall; 1007 } 1008 1009 millis = millis || 0; 1010 timeoutKey = timeoutKey || ++delayedFnCount; 1011 runAtMillis = runAtMillis || (currentTime + millis); 1012 1013 var funcToSchedule = { 1014 runAtMillis: runAtMillis, 1015 funcToCall: f, 1016 recurring: recurring, 1017 params: params, 1018 timeoutKey: timeoutKey, 1019 millis: millis 1020 }; 1021 1022 if (runAtMillis in scheduledFunctions) { 1023 scheduledFunctions[runAtMillis].push(funcToSchedule); 1024 } else { 1025 scheduledFunctions[runAtMillis] = [funcToSchedule]; 1026 scheduledLookup.push(runAtMillis); 1027 scheduledLookup.sort(function (a, b) { 1028 return a - b; 1029 }); 1030 } 1031 1032 return timeoutKey; 1033 }; 1034 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; 1040 }); 1041 1042 if (i > -1) { 1043 if (funcs.length === 1) { 1044 delete scheduledFunctions[runAtMillis]; 1045 deleteFromLookup(runAtMillis); 1046 } else { 1047 funcs.splice(i, 1); 1048 } 1049 1050 // intervals get rescheduled when executed, so there's never more 1051 // than a single scheduled function with a given timeoutKey 1052 break; 1053 } 1054 } 1055 }; 1056 1057 self.reset = function() { 1058 currentTime = 0; 1059 scheduledLookup = []; 1060 scheduledFunctions = {}; 1061 delayedFnCount = 0; 1062 }; 1063 1064 return self; 1065 1066 function indexOfFirstToPass(array, testFn) { 1067 var index = -1; 1068 1069 for (var i = 0; i < array.length; ++i) { 1070 if (testFn(array[i])) { 1071 index = i; 1072 break; 1073 } 1074 } 1075 1076 return index; 1077 } 1078 1079 function deleteFromLookup(key) { 1080 var value = Number(key); 1081 var i = indexOfFirstToPass(scheduledLookup, function (millis) { 1082 return millis === value; 1083 }); 1084 1085 if (i > -1) { 1086 scheduledLookup.splice(i, 1); 1087 } 1088 } 1089 1090 function reschedule(scheduledFn) { 1091 self.scheduleFunction(scheduledFn.funcToCall, 1092 scheduledFn.millis, 1093 scheduledFn.params, 1094 true, 1095 scheduledFn.timeoutKey, 1096 scheduledFn.runAtMillis + scheduledFn.millis); 1097 } 1098 1099 function runScheduledFunctions(endTime) { 1100 if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) { 1101 return; 1102 } 1103 1104 do { 1105 currentTime = scheduledLookup.shift(); 1106 1107 var funcsToRun = scheduledFunctions[currentTime]; 1108 delete scheduledFunctions[currentTime]; 1109 1110 for (var i = 0; i < funcsToRun.length; ++i) { 1111 var funcToRun = funcsToRun[i]; 1112 funcToRun.funcToCall.apply(null, funcToRun.params || []); 1113 1114 if (funcToRun.recurring) { 1115 reschedule(funcToRun); 1116 } 1117 } 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); 1123 } 1124 } 1125 1126 return DelayedFunctionScheduler; 1127 }; 1128 1129 getJasmineRequireObj().ExceptionFormatter = function() { 1130 function ExceptionFormatter() { 1131 this.message = function(error) { 1132 var message = error.name + 1133 ': ' + 1134 error.message; 1135 1136 if (error.fileName || error.sourceURL) { 1137 message += " in " + (error.fileName || error.sourceURL); 1138 } 1139 1140 if (error.line || error.lineNumber) { 1141 message += " (line " + (error.line || error.lineNumber) + ")"; 1142 } 1143 1144 return message; 1145 }; 1146 1147 this.stack = function(error) { 1148 return error ? error.stack : null; 1149 }; 1150 } 1151 1152 return ExceptionFormatter; 1153 }; 1154 1155 getJasmineRequireObj().Expectation = function() { 1156 1157 var matchers = {}; 1158 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; 1165 1166 for (var matcherName in matchers) { 1167 this[matcherName] = matchers[matcherName]; 1168 } 1169 } 1170 1171 Expectation.prototype.wrapCompare = function(name, matcherFactory) { 1172 return function() { 1173 var args = Array.prototype.slice.call(arguments, 0), 1174 expected = args.slice(0), 1175 message = ""; 1176 1177 args.unshift(this.actual); 1178 1179 var matcher = matcherFactory(this.util, this.customEqualityTesters), 1180 matcherCompare = matcher.compare; 1181 1182 function defaultNegativeCompare() { 1183 var result = matcher.compare.apply(null, args); 1184 result.pass = !result.pass; 1185 return result; 1186 } 1187 1188 if (this.isNot) { 1189 matcherCompare = matcher.negativeCompare || defaultNegativeCompare; 1190 } 1191 1192 var result = matcherCompare.apply(null, args); 1193 1194 if (!result.pass) { 1195 if (!result.message) { 1196 args.unshift(this.isNot); 1197 args.unshift(name); 1198 message = this.util.buildFailureMessage.apply(null, args); 1199 } else { 1200 message = result.message; 1201 } 1202 } 1203 1204 if (expected.length == 1) { 1205 expected = expected[0]; 1206 } 1207 1208 // TODO: how many of these params are needed? 1209 this.addExpectationResult( 1210 result.pass, 1211 { 1212 matcherName: name, 1213 passed: result.pass, 1214 message: message, 1215 actual: this.actual, 1216 expected: expected // TODO: this may need to be arrayified/sliced 1217 } 1218 ); 1219 }; 1220 }; 1221 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); 1227 } 1228 }; 1229 1230 Expectation.addMatchers = function(matchersToAdd) { 1231 for (var name in matchersToAdd) { 1232 var matcher = matchersToAdd[name]; 1233 matchers[name] = Expectation.prototype.wrapCompare(name, matcher); 1234 } 1235 }; 1236 1237 Expectation.resetMatchers = function() { 1238 for (var name in matchers) { 1239 delete matchers[name]; 1240 } 1241 }; 1242 1243 Expectation.Factory = function(options) { 1244 options = options || {}; 1245 1246 var expect = new Expectation(options); 1247 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); 1252 1253 return expect; 1254 }; 1255 1256 return Expectation; 1257 }; 1258 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() {}; 1264 1265 return { 1266 matcherName: options.matcherName, 1267 expected: options.expected, 1268 actual: options.actual, 1269 message: message(), 1270 stack: stack(), 1271 passed: options.passed 1272 }; 1273 1274 function message() { 1275 if (options.passed) { 1276 return "Passed."; 1277 } else if (options.message) { 1278 return options.message; 1279 } else if (options.error) { 1280 return messageFormatter(options.error); 1281 } 1282 return ""; 1283 } 1284 1285 function stack() { 1286 if (options.passed) { 1287 return ""; 1288 } 1289 1290 var error = options.error; 1291 if (!error) { 1292 try { 1293 throw new Error(message()); 1294 } catch (e) { 1295 error = e; 1296 } 1297 } 1298 return stackFormatter(error); 1299 } 1300 } 1301 1302 return buildExpectationResult; 1303 }; 1304 1305 getJasmineRequireObj().ObjectContaining = function(j$) { 1306 1307 function ObjectContaining(sample) { 1308 this.sample = sample; 1309 } 1310 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+"'."); } 1313 1314 mismatchKeys = mismatchKeys || []; 1315 mismatchValues = mismatchValues || []; 1316 1317 var hasKey = function(obj, keyName) { 1318 return obj !== null && !j$.util.isUndefined(obj[keyName]); 1319 }; 1320 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."); 1324 } 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."); 1327 } 1328 } 1329 1330 return (mismatchKeys.length === 0 && mismatchValues.length === 0); 1331 }; 1332 1333 ObjectContaining.prototype.jasmineToString = function() { 1334 return "<jasmine.objectContaining(" + j$.pp(this.sample) + ")>"; 1335 }; 1336 1337 return ObjectContaining; 1338 }; 1339 1340 getJasmineRequireObj().pp = function(j$) { 1341 1342 function PrettyPrinter() { 1343 this.ppNestLevel_ = 0; 1344 } 1345 1346 PrettyPrinter.prototype.format = function(value) { 1347 this.ppNestLevel_++; 1348 try { 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); 1375 } else { 1376 this.emitObject(value); 1377 } 1378 delete value.__Jasmine_been_here_before__; 1379 } else { 1380 this.emitScalar(value.toString()); 1381 } 1382 } finally { 1383 this.ppNestLevel_--; 1384 } 1385 }; 1386 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); 1393 } 1394 }; 1395 1396 PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_; 1397 PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_; 1398 PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_; 1399 PrettyPrinter.prototype.emitString = j$.unimplementedMethod_; 1400 1401 function StringPrettyPrinter() { 1402 PrettyPrinter.call(this); 1403 1404 this.string = ''; 1405 } 1406 1407 j$.util.inherit(StringPrettyPrinter, PrettyPrinter); 1408 1409 StringPrettyPrinter.prototype.emitScalar = function(value) { 1410 this.append(value); 1411 }; 1412 1413 StringPrettyPrinter.prototype.emitString = function(value) { 1414 this.append("'" + value + "'"); 1415 }; 1416 1417 StringPrettyPrinter.prototype.emitArray = function(array) { 1418 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { 1419 this.append("Array"); 1420 return; 1421 } 1422 1423 this.append('[ '); 1424 for (var i = 0; i < array.length; i++) { 1425 if (i > 0) { 1426 this.append(', '); 1427 } 1428 this.format(array[i]); 1429 } 1430 this.append(' ]'); 1431 }; 1432 1433 StringPrettyPrinter.prototype.emitObject = function(obj) { 1434 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) { 1435 this.append("Object"); 1436 return; 1437 } 1438 1439 var self = this; 1440 this.append('{ '); 1441 var first = true; 1442 1443 this.iterateObject(obj, function(property, isGetter) { 1444 if (first) { 1445 first = false; 1446 } else { 1447 self.append(', '); 1448 } 1449 1450 self.append(property); 1451 self.append(' : '); 1452 if (isGetter) { 1453 self.append('<getter>'); 1454 } else { 1455 self.format(obj[property]); 1456 } 1457 }); 1458 1459 this.append(' }'); 1460 }; 1461 1462 StringPrettyPrinter.prototype.append = function(value) { 1463 this.string += value; 1464 }; 1465 1466 return function(value) { 1467 var stringPrettyPrinter = new StringPrettyPrinter(); 1468 stringPrettyPrinter.format(value); 1469 return stringPrettyPrinter.string; 1470 }; 1471 }; 1472 1473 getJasmineRequireObj().QueueRunner = function() { 1474 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 = {}; 1482 } 1483 1484 QueueRunner.prototype.execute = function() { 1485 this.run(this.fns, 0); 1486 }; 1487 1488 QueueRunner.prototype.run = function(fns, recursiveIndex) { 1489 var length = fns.length, 1490 self = this, 1491 iterativeIndex; 1492 1493 for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) { 1494 var fn = fns[iterativeIndex]; 1495 if (fn.length > 0) { 1496 return attemptAsync(fn); 1497 } else { 1498 attemptSync(fn); 1499 } 1500 } 1501 1502 var runnerDone = iterativeIndex >= length; 1503 1504 if (runnerDone) { 1505 this.clearStack(this.onComplete); 1506 } 1507 1508 function attemptSync(fn) { 1509 try { 1510 fn.call(self.userContext); 1511 } catch (e) { 1512 handleException(e); 1513 } 1514 } 1515 1516 function attemptAsync(fn) { 1517 var next = function () { self.run(fns, iterativeIndex + 1); }; 1518 1519 try { 1520 fn.call(self.userContext, next); 1521 } catch (e) { 1522 handleException(e); 1523 next(); 1524 } 1525 } 1526 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.. 1532 throw e; 1533 } 1534 } 1535 }; 1536 1537 return QueueRunner; 1538 }; 1539 1540 getJasmineRequireObj().ReportDispatcher = function() { 1541 function ReportDispatcher(methods) { 1542 1543 var dispatchedMethods = methods || []; 1544 1545 for (var i = 0; i < dispatchedMethods.length; i++) { 1546 var method = dispatchedMethods[i]; 1547 this[method] = (function(m) { 1548 return function() { 1549 dispatch(m, arguments); 1550 }; 1551 }(method)); 1552 } 1553 1554 var reporters = []; 1555 1556 this.addReporter = function(reporter) { 1557 reporters.push(reporter); 1558 }; 1559 1560 return this; 1561 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); 1567 } 1568 } 1569 } 1570 } 1571 1572 return ReportDispatcher; 1573 }; 1574 1575 1576 getJasmineRequireObj().SpyStrategy = function() { 1577 1578 function SpyStrategy(options) { 1579 options = options || {}; 1580 1581 var identity = options.name || "unknown", 1582 originalFn = options.fn || function() {}, 1583 getSpy = options.getSpy || function() {}, 1584 plan = function() {}; 1585 1586 this.identity = function() { 1587 return identity; 1588 }; 1589 1590 this.exec = function() { 1591 return plan.apply(this, arguments); 1592 }; 1593 1594 this.callThrough = function() { 1595 plan = originalFn; 1596 return getSpy(); 1597 }; 1598 1599 this.returnValue = function(value) { 1600 plan = function() { 1601 return value; 1602 }; 1603 return getSpy(); 1604 }; 1605 1606 this.throwError = function(something) { 1607 var error = (something instanceof Error) ? something : new Error(something); 1608 plan = function() { 1609 throw error; 1610 }; 1611 return getSpy(); 1612 }; 1613 1614 this.callFake = function(fn) { 1615 plan = fn; 1616 return getSpy(); 1617 }; 1618 1619 this.stub = function(fn) { 1620 plan = function() {}; 1621 return getSpy(); 1622 }; 1623 } 1624 1625 return SpyStrategy; 1626 }; 1627 1628 getJasmineRequireObj().Suite = function() { 1629 function Suite(attrs) { 1630 this.env = attrs.env; 1631 this.id = attrs.id; 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();}; 1637 1638 this.beforeFns = []; 1639 this.afterFns = []; 1640 this.queueRunner = attrs.queueRunner || function() {}; 1641 this.disabled = false; 1642 1643 this.children = []; 1644 1645 this.result = { 1646 id: this.id, 1647 status: this.disabled ? 'disabled' : '', 1648 description: this.description, 1649 fullName: this.getFullName() 1650 }; 1651 } 1652 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; 1658 } 1659 } 1660 return fullName; 1661 }; 1662 1663 Suite.prototype.disable = function() { 1664 this.disabled = true; 1665 }; 1666 1667 Suite.prototype.beforeEach = function(fn) { 1668 this.beforeFns.unshift(fn); 1669 }; 1670 1671 Suite.prototype.afterEach = function(fn) { 1672 this.afterFns.unshift(fn); 1673 }; 1674 1675 Suite.prototype.addChild = function(child) { 1676 this.children.push(child); 1677 }; 1678 1679 Suite.prototype.execute = function(onComplete) { 1680 var self = this; 1681 if (this.disabled) { 1682 complete(); 1683 return; 1684 } 1685 1686 var allFns = []; 1687 1688 for (var i = 0; i < this.children.length; i++) { 1689 allFns.push(wrapChildAsAsync(this.children[i])); 1690 } 1691 1692 this.onStart(this); 1693 1694 this.queueRunner({ 1695 fns: allFns, 1696 onComplete: complete 1697 }); 1698 1699 function complete() { 1700 self.resultCallback(self.result); 1701 1702 if (onComplete) { 1703 onComplete(); 1704 } 1705 } 1706 1707 function wrapChildAsAsync(child) { 1708 return function(done) { child.execute(done); }; 1709 } 1710 }; 1711 1712 return Suite; 1713 }; 1714 1715 if (typeof window == void 0 && typeof exports == "object") { 1716 exports.Suite = jasmineRequire.Suite; 1717 } 1718 1719 getJasmineRequireObj().Timer = function() { 1720 function Timer(options) { 1721 options = options || {}; 1722 1723 var now = options.now || function() { return new Date().getTime(); }, 1724 startTime; 1725 1726 this.start = function() { 1727 startTime = now(); 1728 }; 1729 1730 this.elapsed = function() { 1731 return now() - startTime; 1732 }; 1733 } 1734 1735 return Timer; 1736 }; 1737 1738 getJasmineRequireObj().matchersUtil = function(j$) { 1739 // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter? 1740 1741 return { 1742 equals: function(a, b, customTesters) { 1743 customTesters = customTesters || []; 1744 1745 return eq(a, b, [], [], customTesters); 1746 }, 1747 1748 contains: function(haystack, needle, customTesters) { 1749 customTesters = customTesters || []; 1750 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)) { 1754 return true; 1755 } 1756 } 1757 return false; 1758 } 1759 return haystack.indexOf(needle) >= 0; 1760 }, 1761 1762 buildFailureMessage: function() { 1763 var args = Array.prototype.slice.call(arguments, 0), 1764 matcherName = args[0], 1765 isNot = args[1], 1766 actual = args[2], 1767 expected = args.slice(3), 1768 englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); }); 1769 1770 var message = "Expected " + 1771 j$.pp(actual) + 1772 (isNot ? " not " : " ") + 1773 englishyPredicate; 1774 1775 if (expected.length > 0) { 1776 for (var i = 0; i < expected.length; i++) { 1777 if (i > 0) { 1778 message += ","; 1779 } 1780 message += " " + j$.pp(expected[i]); 1781 } 1782 } 1783 1784 return message + "."; 1785 } 1786 }; 1787 1788 // Equality function lovingly adapted from isEqual in 1789 // [Underscore](http://underscorejs.org) 1790 function eq(a, b, aStack, bStack, customTesters) { 1791 var result = true; 1792 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; 1797 } 1798 } 1799 1800 if (a instanceof j$.Any) { 1801 result = a.jasmineMatches(b); 1802 if (result) { 1803 return true; 1804 } 1805 } 1806 1807 if (b instanceof j$.Any) { 1808 result = b.jasmineMatches(a); 1809 if (result) { 1810 return true; 1811 } 1812 } 1813 1814 if (b instanceof j$.ObjectContaining) { 1815 result = b.jasmineMatches(a); 1816 if (result) { 1817 return true; 1818 } 1819 } 1820 1821 if (a instanceof Error && b instanceof Error) { 1822 return a.message == b.message; 1823 } 1824 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. 1847 return +a == +b; 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; 1854 } 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; 1859 while (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; } 1863 } 1864 // Add the first object to the stack of traversed objects. 1865 aStack.push(a); 1866 bStack.push(b); 1867 var size = 0; 1868 // Recursively compare objects and arrays. 1869 if (className == '[object Array]') { 1870 // Compare array lengths to determine if a deep comparison is necessary. 1871 size = a.length; 1872 result = size == b.length; 1873 if (result) { 1874 // Deep compare the contents, ignoring non-numeric properties. 1875 while (size--) { 1876 if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; } 1877 } 1878 } 1879 } else { 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))) { 1885 return false; 1886 } 1887 // Deep compare objects. 1888 for (var key in a) { 1889 if (has(a, key)) { 1890 // Count the expected number of properties. 1891 size++; 1892 // Deep compare each member. 1893 if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; } 1894 } 1895 } 1896 // Ensure that both objects contain the same number of properties. 1897 if (result) { 1898 for (key in b) { 1899 if (has(b, key) && !(size--)) { break; } 1900 } 1901 result = !size; 1902 } 1903 } 1904 // Remove the first object from the stack of traversed objects. 1905 aStack.pop(); 1906 bStack.pop(); 1907 1908 return result; 1909 1910 function has(obj, key) { 1911 return obj.hasOwnProperty(key); 1912 } 1913 1914 function isFunction(obj) { 1915 return typeof obj === 'function'; 1916 } 1917 } 1918 }; 1919 1920 getJasmineRequireObj().toBe = function() { 1921 function toBe() { 1922 return { 1923 compare: function(actual, expected) { 1924 return { 1925 pass: actual === expected 1926 }; 1927 } 1928 }; 1929 } 1930 1931 return toBe; 1932 }; 1933 1934 getJasmineRequireObj().toBeCloseTo = function() { 1935 1936 function toBeCloseTo() { 1937 return { 1938 compare: function(actual, expected, precision) { 1939 if (precision !== 0) { 1940 precision = precision || 2; 1941 } 1942 1943 return { 1944 pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2) 1945 }; 1946 } 1947 }; 1948 } 1949 1950 return toBeCloseTo; 1951 }; 1952 1953 getJasmineRequireObj().toBeDefined = function() { 1954 function toBeDefined() { 1955 return { 1956 compare: function(actual) { 1957 return { 1958 pass: (void 0 !== actual) 1959 }; 1960 } 1961 }; 1962 } 1963 1964 return toBeDefined; 1965 }; 1966 1967 getJasmineRequireObj().toBeFalsy = function() { 1968 function toBeFalsy() { 1969 return { 1970 compare: function(actual) { 1971 return { 1972 pass: !!!actual 1973 }; 1974 } 1975 }; 1976 } 1977 1978 return toBeFalsy; 1979 }; 1980 1981 getJasmineRequireObj().toBeGreaterThan = function() { 1982 1983 function toBeGreaterThan() { 1984 return { 1985 compare: function(actual, expected) { 1986 return { 1987 pass: actual > expected 1988 }; 1989 } 1990 }; 1991 } 1992 1993 return toBeGreaterThan; 1994 }; 1995 1996 1997 getJasmineRequireObj().toBeLessThan = function() { 1998 function toBeLessThan() { 1999 return { 2000 2001 compare: function(actual, expected) { 2002 return { 2003 pass: actual < expected 2004 }; 2005 } 2006 }; 2007 } 2008 2009 return toBeLessThan; 2010 }; 2011 getJasmineRequireObj().toBeNaN = function(j$) { 2012 2013 function toBeNaN() { 2014 return { 2015 compare: function(actual) { 2016 var result = { 2017 pass: (actual !== actual) 2018 }; 2019 2020 if (result.pass) { 2021 result.message = "Expected actual not to be NaN."; 2022 } else { 2023 result.message = "Expected " + j$.pp(actual) + " to be NaN."; 2024 } 2025 2026 return result; 2027 } 2028 }; 2029 } 2030 2031 return toBeNaN; 2032 }; 2033 2034 getJasmineRequireObj().toBeNull = function() { 2035 2036 function toBeNull() { 2037 return { 2038 compare: function(actual) { 2039 return { 2040 pass: actual === null 2041 }; 2042 } 2043 }; 2044 } 2045 2046 return toBeNull; 2047 }; 2048 2049 getJasmineRequireObj().toBeTruthy = function() { 2050 2051 function toBeTruthy() { 2052 return { 2053 compare: function(actual) { 2054 return { 2055 pass: !!actual 2056 }; 2057 } 2058 }; 2059 } 2060 2061 return toBeTruthy; 2062 }; 2063 2064 getJasmineRequireObj().toBeUndefined = function() { 2065 2066 function toBeUndefined() { 2067 return { 2068 compare: function(actual) { 2069 return { 2070 pass: void 0 === actual 2071 }; 2072 } 2073 }; 2074 } 2075 2076 return toBeUndefined; 2077 }; 2078 2079 getJasmineRequireObj().toContain = function() { 2080 function toContain(util, customEqualityTesters) { 2081 customEqualityTesters = customEqualityTesters || []; 2082 2083 return { 2084 compare: function(actual, expected) { 2085 2086 return { 2087 pass: util.contains(actual, expected, customEqualityTesters) 2088 }; 2089 } 2090 }; 2091 } 2092 2093 return toContain; 2094 }; 2095 2096 getJasmineRequireObj().toEqual = function() { 2097 2098 function toEqual(util, customEqualityTesters) { 2099 customEqualityTesters = customEqualityTesters || []; 2100 2101 return { 2102 compare: function(actual, expected) { 2103 var result = { 2104 pass: false 2105 }; 2106 2107 result.pass = util.equals(actual, expected, customEqualityTesters); 2108 2109 return result; 2110 } 2111 }; 2112 } 2113 2114 return toEqual; 2115 }; 2116 2117 getJasmineRequireObj().toHaveBeenCalled = function(j$) { 2118 2119 function toHaveBeenCalled() { 2120 return { 2121 compare: function(actual) { 2122 var result = {}; 2123 2124 if (!j$.isSpy(actual)) { 2125 throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.'); 2126 } 2127 2128 if (arguments.length > 1) { 2129 throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith'); 2130 } 2131 2132 result.pass = actual.calls.any(); 2133 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."; 2137 2138 return result; 2139 } 2140 }; 2141 } 2142 2143 return toHaveBeenCalled; 2144 }; 2145 2146 getJasmineRequireObj().toHaveBeenCalledWith = function(j$) { 2147 2148 function toHaveBeenCalledWith(util) { 2149 return { 2150 compare: function() { 2151 var args = Array.prototype.slice.call(arguments, 0), 2152 actual = args[0], 2153 expectedArgs = args.slice(1), 2154 result = { pass: false }; 2155 2156 if (!j$.isSpy(actual)) { 2157 throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.'); 2158 } 2159 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."; 2162 return result; 2163 } 2164 2165 if (util.contains(actual.calls.allArgs(), expectedArgs)) { 2166 result.pass = true; 2167 result.message = "Expected spy " + actual.and.identity() + " not to have been called with " + j$.pp(expectedArgs) + " but it was."; 2168 } else { 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, '') + "."; 2170 } 2171 2172 return result; 2173 } 2174 }; 2175 } 2176 2177 return toHaveBeenCalledWith; 2178 }; 2179 2180 getJasmineRequireObj().toMatch = function() { 2181 2182 function toMatch() { 2183 return { 2184 compare: function(actual, expected) { 2185 var regexp = new RegExp(expected); 2186 2187 return { 2188 pass: regexp.test(actual) 2189 }; 2190 } 2191 }; 2192 } 2193 2194 return toMatch; 2195 }; 2196 2197 getJasmineRequireObj().toThrow = function(j$) { 2198 2199 function toThrow(util) { 2200 return { 2201 compare: function(actual, expected) { 2202 var result = { pass: false }, 2203 threw = false, 2204 thrown; 2205 2206 if (typeof actual != "function") { 2207 throw new Error("Actual is not a Function"); 2208 } 2209 2210 try { 2211 actual(); 2212 } catch (e) { 2213 threw = true; 2214 thrown = e; 2215 } 2216 2217 if (!threw) { 2218 result.message = "Expected function to throw an exception."; 2219 return result; 2220 } 2221 2222 if (arguments.length == 1) { 2223 result.pass = true; 2224 result.message = "Expected function not to throw, but it threw " + j$.pp(thrown) + "."; 2225 2226 return result; 2227 } 2228 2229 if (util.equals(thrown, expected)) { 2230 result.pass = true; 2231 result.message = "Expected function not to throw " + j$.pp(expected) + "."; 2232 } else { 2233 result.message = "Expected function to throw " + j$.pp(expected) + ", but it threw " + j$.pp(thrown) + "."; 2234 } 2235 2236 return result; 2237 } 2238 }; 2239 } 2240 2241 return toThrow; 2242 }; 2243 2244 getJasmineRequireObj().toThrowError = function(j$) { 2245 function toThrowError (util) { 2246 return { 2247 compare: function(actual) { 2248 var threw = false, 2249 thrown, 2250 errorType, 2251 message, 2252 regexp, 2253 name, 2254 constructorName; 2255 2256 if (typeof actual != "function") { 2257 throw new Error("Actual is not a Function"); 2258 } 2259 2260 extractExpectedParams.apply(null, arguments); 2261 2262 try { 2263 actual(); 2264 } catch (e) { 2265 threw = true; 2266 thrown = e; 2267 } 2268 2269 if (!threw) { 2270 return fail("Expected function to throw an Error."); 2271 } 2272 2273 if (!(thrown instanceof Error)) { 2274 return fail("Expected function to throw an Error, but it threw " + thrown + "."); 2275 } 2276 2277 if (arguments.length == 1) { 2278 return pass("Expected function not to throw an Error, but it threw " + fnNameFor(thrown) + "."); 2279 } 2280 2281 if (errorType) { 2282 name = fnNameFor(errorType); 2283 constructorName = fnNameFor(thrown.constructor); 2284 } 2285 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 + "\"."); 2289 } else { 2290 return fail("Expected function to throw " + name + " with message \"" + message + 2291 "\", but it threw " + constructorName + " with message \"" + thrown.message + "\"."); 2292 } 2293 } 2294 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 + "."); 2298 } else { 2299 return fail("Expected function to throw " + name + " with message matching " + regexp + 2300 ", but it threw " + constructorName + " with message \"" + thrown.message + "\"."); 2301 } 2302 } 2303 2304 if (errorType) { 2305 if (thrown.constructor == errorType) { 2306 return pass("Expected function not to throw " + name + "."); 2307 } else { 2308 return fail("Expected function to throw " + name + ", but it threw " + constructorName + "."); 2309 } 2310 } 2311 2312 if (message) { 2313 if (thrown.message == message) { 2314 return pass("Expected function not to throw an exception with message " + j$.pp(message) + "."); 2315 } else { 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) + "."); 2318 } 2319 } 2320 2321 if (regexp) { 2322 if (regexp.test(thrown.message)) { 2323 return pass("Expected function not to throw an exception with a message matching " + j$.pp(regexp) + "."); 2324 } else { 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) + "."); 2327 } 2328 } 2329 2330 function fnNameFor(func) { 2331 return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1]; 2332 } 2333 2334 function pass(notMessage) { 2335 return { 2336 pass: true, 2337 message: notMessage 2338 }; 2339 } 2340 2341 function fail(message) { 2342 return { 2343 pass: false, 2344 message: message 2345 }; 2346 } 2347 2348 function extractExpectedParams() { 2349 if (arguments.length == 1) { 2350 return; 2351 } 2352 2353 if (arguments.length == 2) { 2354 var expected = arguments[1]; 2355 2356 if (expected instanceof RegExp) { 2357 regexp = expected; 2358 } else if (typeof expected == "string") { 2359 message = expected; 2360 } else if (checkForAnErrorType(expected)) { 2361 errorType = expected; 2362 } 2363 2364 if (!(errorType || message || regexp)) { 2365 throw new Error("Expected is not an Error, string, or RegExp."); 2366 } 2367 } else { 2368 if (checkForAnErrorType(arguments[1])) { 2369 errorType = arguments[1]; 2370 } else { 2371 throw new Error("Expected error type is not an Error."); 2372 } 2373 2374 if (arguments[2] instanceof RegExp) { 2375 regexp = arguments[2]; 2376 } else if (typeof arguments[2] == "string") { 2377 message = arguments[2]; 2378 } else { 2379 throw new Error("Expected error message is not a string or RegExp."); 2380 } 2381 } 2382 } 2383 2384 function checkForAnErrorType(type) { 2385 if (typeof type !== "function") { 2386 return false; 2387 } 2388 2389 var Surrogate = function() {}; 2390 Surrogate.prototype = type.prototype; 2391 return (new Surrogate()) instanceof Error; 2392 } 2393 } 2394 }; 2395 } 2396 2397 return toThrowError; 2398 }; 2399 2400 getJasmineRequireObj().version = function() { 2401 return "2.0.0"; 2402 };