UNPKG

193 kBJavaScriptView Raw
1/*
2Copyright (c) 2008-2018 Pivotal Labs
3
4Permission is hereby granted, free of charge, to any person obtaining
5a copy of this software and associated documentation files (the
6"Software"), to deal in the Software without restriction, including
7without limitation the rights to use, copy, modify, merge, publish,
8distribute, sublicense, and/or sell copies of the Software, and to
9permit persons to whom the Software is furnished to do so, subject to
10the following conditions:
11
12The above copyright notice and this permission notice shall be
13included in all copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*/
23var getJasmineRequireObj = (function (jasmineGlobal) {
24 /* globals exports, global, module, window */
25 var jasmineRequire;
26
27 if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
28 if (typeof global !== 'undefined') {
29 jasmineGlobal = global;
30 } else {
31 jasmineGlobal = {};
32 }
33 jasmineRequire = exports;
34 } else {
35 if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
36 jasmineGlobal = window;
37 }
38 jasmineRequire = jasmineGlobal.jasmineRequire = {};
39 }
40
41 function getJasmineRequire() {
42 return jasmineRequire;
43 }
44
45 getJasmineRequire().core = function(jRequire) {
46 var j$ = {};
47
48 jRequire.base(j$, jasmineGlobal);
49 j$.util = jRequire.util(j$);
50 j$.errors = jRequire.errors();
51 j$.formatErrorMsg = jRequire.formatErrorMsg();
52 j$.Any = jRequire.Any(j$);
53 j$.Anything = jRequire.Anything(j$);
54 j$.CallTracker = jRequire.CallTracker(j$);
55 j$.MockDate = jRequire.MockDate();
56 j$.getClearStack = jRequire.clearStack(j$);
57 j$.Clock = jRequire.Clock();
58 j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(j$);
59 j$.Env = jRequire.Env(j$);
60 j$.StackTrace = jRequire.StackTrace(j$);
61 j$.ExceptionFormatter = jRequire.ExceptionFormatter(j$);
62 j$.Expectation = jRequire.Expectation();
63 j$.AsyncExpectation = jRequire.AsyncExpectation(j$);
64 j$.buildExpectationResult = jRequire.buildExpectationResult();
65 j$.JsApiReporter = jRequire.JsApiReporter();
66 j$.matchersUtil = jRequire.matchersUtil(j$);
67 j$.ObjectContaining = jRequire.ObjectContaining(j$);
68 j$.ArrayContaining = jRequire.ArrayContaining(j$);
69 j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
70 j$.pp = jRequire.pp(j$);
71 j$.QueueRunner = jRequire.QueueRunner(j$);
72 j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
73 j$.Spec = jRequire.Spec(j$);
74 j$.Spy = jRequire.Spy(j$);
75 j$.SpyFactory = jRequire.SpyFactory(j$);
76 j$.SpyRegistry = jRequire.SpyRegistry(j$);
77 j$.SpyStrategy = jRequire.SpyStrategy(j$);
78 j$.StringMatching = jRequire.StringMatching(j$);
79 j$.UserContext = jRequire.UserContext(j$);
80 j$.Suite = jRequire.Suite(j$);
81 j$.Timer = jRequire.Timer();
82 j$.TreeProcessor = jRequire.TreeProcessor();
83 j$.version = jRequire.version();
84 j$.Order = jRequire.Order();
85 j$.DiffBuilder = jRequire.DiffBuilder(j$);
86 j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
87 j$.ObjectPath = jRequire.ObjectPath(j$);
88 j$.GlobalErrors = jRequire.GlobalErrors(j$);
89
90 j$.Truthy = jRequire.Truthy(j$);
91 j$.Falsy = jRequire.Falsy(j$);
92 j$.Empty = jRequire.Empty(j$);
93 j$.NotEmpty = jRequire.NotEmpty(j$);
94
95 j$.matchers = jRequire.requireMatchers(jRequire, j$);
96
97 return j$;
98 };
99
100 return getJasmineRequire;
101})(this);
102
103getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
104 var availableMatchers = [
105 'nothing',
106 'toBe',
107 'toBeCloseTo',
108 'toBeDefined',
109 'toBeFalsy',
110 'toBeGreaterThan',
111 'toBeGreaterThanOrEqual',
112 'toBeLessThan',
113 'toBeLessThanOrEqual',
114 'toBeNaN',
115 'toBeNegativeInfinity',
116 'toBeNull',
117 'toBePositiveInfinity',
118 'toBeTruthy',
119 'toBeUndefined',
120 'toContain',
121 'toEqual',
122 'toHaveBeenCalled',
123 'toHaveBeenCalledBefore',
124 'toHaveBeenCalledTimes',
125 'toHaveBeenCalledWith',
126 'toHaveClass',
127 'toMatch',
128 'toThrow',
129 'toThrowError',
130 'toThrowMatching',
131 ],
132 matchers = {};
133
134 for (var i = 0; i < availableMatchers.length; i++) {
135 var name = availableMatchers[i];
136 matchers[name] = jRequire[name](j$);
137 }
138
139 return matchers;
140};
141
142getJasmineRequireObj().base = function(j$, jasmineGlobal) {
143 j$.unimplementedMethod_ = function() {
144 throw new Error('unimplemented method');
145 };
146
147 /**
148 * Maximum object depth the pretty printer will print to.
149 * Set this to a lower value to speed up pretty printing if you have large objects.
150 * @name jasmine.MAX_PRETTY_PRINT_DEPTH
151 */
152 j$.MAX_PRETTY_PRINT_DEPTH = 8;
153 /**
154 * Maximum number of array elements to display when pretty printing objects.
155 * This will also limit the number of keys and values displayed for an object.
156 * Elements past this number will be ellipised.
157 * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
158 */
159 j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
160 /**
161 * Maximum number of charasters to display when pretty printing objects.
162 * Characters past this number will be ellipised.
163 * @name jasmine.MAX_PRETTY_PRINT_CHARS
164 */
165 j$.MAX_PRETTY_PRINT_CHARS = 1000;
166 /**
167 * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
168 * @name jasmine.DEFAULT_TIMEOUT_INTERVAL
169 */
170 j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
171
172 j$.getGlobal = function() {
173 return jasmineGlobal;
174 };
175
176 /**
177 * Get the currently booted Jasmine Environment.
178 *
179 * @name jasmine.getEnv
180 * @function
181 * @return {Env}
182 */
183 j$.getEnv = function(options) {
184 var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
185 //jasmine. singletons in here (setTimeout blah blah).
186 return env;
187 };
188
189 j$.isArray_ = function(value) {
190 return j$.isA_('Array', value);
191 };
192
193 j$.isObject_ = function(value) {
194 return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value);
195 };
196
197 j$.isString_ = function(value) {
198 return j$.isA_('String', value);
199 };
200
201 j$.isNumber_ = function(value) {
202 return j$.isA_('Number', value);
203 };
204
205 j$.isFunction_ = function(value) {
206 return j$.isA_('Function', value);
207 };
208
209 j$.isAsyncFunction_ = function(value) {
210 return j$.isA_('AsyncFunction', value);
211 };
212
213 j$.isTypedArray_ = function(value) {
214 return j$.isA_('Float32Array', value) ||
215 j$.isA_('Float64Array', value) ||
216 j$.isA_('Int16Array', value) ||
217 j$.isA_('Int32Array', value) ||
218 j$.isA_('Int8Array', value) ||
219 j$.isA_('Uint16Array', value) ||
220 j$.isA_('Uint32Array', value) ||
221 j$.isA_('Uint8Array', value) ||
222 j$.isA_('Uint8ClampedArray', value);
223 };
224
225 j$.isA_ = function(typeName, value) {
226 return j$.getType_(value) === '[object ' + typeName + ']';
227 };
228
229 j$.isError_ = function(value) {
230 if (value instanceof Error) {
231 return true;
232 }
233 if (value && value.constructor && value.constructor.constructor &&
234 (value instanceof (value.constructor.constructor('return this')()).Error)) {
235 return true;
236 }
237 return false;
238 };
239
240 j$.getType_ = function(value) {
241 return Object.prototype.toString.apply(value);
242 };
243
244 j$.isDomNode = function(obj) {
245 // Node is a function, because constructors
246 return typeof jasmineGlobal.Node !== 'undefined' ?
247 obj instanceof jasmineGlobal.Node :
248 obj !== null &&
249 typeof obj === 'object' &&
250 typeof obj.nodeType === 'number' &&
251 typeof obj.nodeName === 'string';
252 // return obj.nodeType > 0;
253 };
254
255 j$.isMap = function(obj) {
256 return typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map;
257 };
258
259 j$.isSet = function(obj) {
260 return typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set;
261 };
262
263 j$.isPromise = function(obj) {
264 return typeof jasmineGlobal.Promise !== 'undefined' && obj && obj.constructor === jasmineGlobal.Promise;
265 };
266
267 j$.fnNameFor = function(func) {
268 if (func.name) {
269 return func.name;
270 }
271
272 var matches = func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
273 func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/);
274
275 return matches ? matches[1] : '<anonymous>';
276 };
277
278 /**
279 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
280 * that will succeed if the actual value being compared is an instance of the specified class/constructor.
281 * @name jasmine.any
282 * @function
283 * @param {Constructor} clazz - The constructor to check against.
284 */
285 j$.any = function(clazz) {
286 return new j$.Any(clazz);
287 };
288
289 /**
290 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
291 * that will succeed if the actual value being compared is not `null` and not `undefined`.
292 * @name jasmine.anything
293 * @function
294 */
295 j$.anything = function() {
296 return new j$.Anything();
297 };
298
299 /**
300 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
301 * that will succeed if the actual value being compared is `true` or anything truthy.
302 * @name jasmine.truthy
303 * @function
304 */
305 j$.truthy = function() {return new j$.Truthy();};
306
307 /**
308 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
309 * that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
310 * @name jasmine.falsy
311 * @function
312 */
313 j$.falsy = function() {return new j$.Falsy();};
314
315 /**
316 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
317 * that will succeed if the actual value being compared is empty.
318 * @name jasmine.empty
319 * @function
320 */
321 j$.empty = function() {return new j$.Empty();};
322
323 /**
324 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
325 * that will succeed if the actual value being compared is not empty.
326 * @name jasmine.notEmpty
327 * @function
328 */
329 j$.notEmpty = function() {return new j$.NotEmpty();};
330
331 /**
332 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
333 * that will succeed if the actual value being compared contains at least the keys and values.
334 * @name jasmine.objectContaining
335 * @function
336 * @param {Object} sample - The subset of properties that _must_ be in the actual.
337 */
338 j$.objectContaining = function(sample) {
339 return new j$.ObjectContaining(sample);
340 };
341
342 /**
343 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
344 * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
345 * @name jasmine.stringMatching
346 * @function
347 * @param {RegExp|String} expected
348 */
349 j$.stringMatching = function(expected) {
350 return new j$.StringMatching(expected);
351 };
352
353 /**
354 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
355 * that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
356 * @name jasmine.arrayContaining
357 * @function
358 * @param {Array} sample
359 */
360 j$.arrayContaining = function(sample) {
361 return new j$.ArrayContaining(sample);
362 };
363
364 /**
365 * Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
366 * that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
367 * @name jasmine.arrayWithExactContents
368 * @function
369 * @param {Array} sample
370 */
371 j$.arrayWithExactContents = function(sample) {
372 return new j$.ArrayWithExactContents(sample);
373 };
374
375 j$.isSpy = function(putativeSpy) {
376 if (!putativeSpy) {
377 return false;
378 }
379 return putativeSpy.and instanceof j$.SpyStrategy &&
380 putativeSpy.calls instanceof j$.CallTracker;
381 };
382};
383
384getJasmineRequireObj().util = function(j$) {
385
386 var util = {};
387
388 util.inherit = function(childClass, parentClass) {
389 var Subclass = function() {
390 };
391 Subclass.prototype = parentClass.prototype;
392 childClass.prototype = new Subclass();
393 };
394
395 util.htmlEscape = function(str) {
396 if (!str) {
397 return str;
398 }
399 return str.replace(/&/g, '&amp;')
400 .replace(/</g, '&lt;')
401 .replace(/>/g, '&gt;');
402 };
403
404 util.argsToArray = function(args) {
405 var arrayOfArgs = [];
406 for (var i = 0; i < args.length; i++) {
407 arrayOfArgs.push(args[i]);
408 }
409 return arrayOfArgs;
410 };
411
412 util.isUndefined = function(obj) {
413 return obj === void 0;
414 };
415
416 util.arrayContains = function(array, search) {
417 var i = array.length;
418 while (i--) {
419 if (array[i] === search) {
420 return true;
421 }
422 }
423 return false;
424 };
425
426 util.clone = function(obj) {
427 if (Object.prototype.toString.apply(obj) === '[object Array]') {
428 return obj.slice();
429 }
430
431 var cloned = {};
432 for (var prop in obj) {
433 if (obj.hasOwnProperty(prop)) {
434 cloned[prop] = obj[prop];
435 }
436 }
437
438 return cloned;
439 };
440
441 util.cloneArgs = function(args) {
442 var clonedArgs = [];
443 var argsAsArray = j$.util.argsToArray(args);
444 for(var i = 0; i < argsAsArray.length; i++) {
445 var str = Object.prototype.toString.apply(argsAsArray[i]),
446 primitives = /^\[object (Boolean|String|RegExp|Number)/;
447
448 // All falsey values are either primitives, `null`, or `undefined.
449 if (!argsAsArray[i] || str.match(primitives)) {
450 clonedArgs.push(argsAsArray[i]);
451 } else {
452 clonedArgs.push(j$.util.clone(argsAsArray[i]));
453 }
454 }
455 return clonedArgs;
456 };
457
458 util.getPropertyDescriptor = function(obj, methodName) {
459 var descriptor,
460 proto = obj;
461
462 do {
463 descriptor = Object.getOwnPropertyDescriptor(proto, methodName);
464 proto = Object.getPrototypeOf(proto);
465 } while (!descriptor && proto);
466
467 return descriptor;
468 };
469
470 util.objectDifference = function(obj, toRemove) {
471 var diff = {};
472
473 for (var key in obj) {
474 if (util.has(obj, key) && !util.has(toRemove, key)) {
475 diff[key] = obj[key];
476 }
477 }
478
479 return diff;
480 };
481
482 util.has = function(obj, key) {
483 return Object.prototype.hasOwnProperty.call(obj, key);
484 };
485
486 function anyMatch(pattern, lines) {
487 var i;
488
489 for (i = 0; i < lines.length; i++) {
490 if (lines[i].match(pattern)) {
491 return true;
492 }
493 }
494
495 return false;
496 }
497
498 util.errorWithStack = function errorWithStack () {
499 // Don't throw and catch if we don't have to, because it makes it harder
500 // for users to debug their code with exception breakpoints.
501 var error = new Error();
502
503 if (error.stack) {
504 return error;
505 }
506
507 // But some browsers (e.g. Phantom) only provide a stack trace if we throw.
508 try {
509 throw new Error();
510 } catch (e) {
511 return e;
512 }
513 };
514
515 function callerFile() {
516 var trace = new j$.StackTrace(util.errorWithStack());
517 return trace.frames[2].file;
518 }
519
520 util.jasmineFile = (function() {
521 var result;
522
523 return function() {
524 var trace;
525
526 if (!result) {
527 result = callerFile();
528 }
529
530 return result;
531 };
532 }());
533
534 return util;
535};
536
537getJasmineRequireObj().Spec = function(j$) {
538 function Spec(attrs) {
539 this.expectationFactory = attrs.expectationFactory;
540 this.asyncExpectationFactory = attrs.asyncExpectationFactory;
541 this.resultCallback = attrs.resultCallback || function() {};
542 this.id = attrs.id;
543 this.description = attrs.description || '';
544 this.queueableFn = attrs.queueableFn;
545 this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
546 this.userContext = attrs.userContext || function() { return {}; };
547 this.onStart = attrs.onStart || function() {};
548 this.getSpecName = attrs.getSpecName || function() { return ''; };
549 this.expectationResultFactory = attrs.expectationResultFactory || function() { };
550 this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
551 this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
552 this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
553
554 if (!this.queueableFn.fn) {
555 this.pend();
556 }
557
558 /**
559 * @typedef SpecResult
560 * @property {Int} id - The unique id of this spec.
561 * @property {String} description - The description passed to the {@link it} that created this spec.
562 * @property {String} fullName - The full description including all ancestors of this spec.
563 * @property {Expectation[]} failedExpectations - The list of expectations that failed during execution of this spec.
564 * @property {Expectation[]} passedExpectations - The list of expectations that passed during execution of this spec.
565 * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred during execution this spec.
566 * @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
567 * @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
568 */
569 this.result = {
570 id: this.id,
571 description: this.description,
572 fullName: this.getFullName(),
573 failedExpectations: [],
574 passedExpectations: [],
575 deprecationWarnings: [],
576 pendingReason: ''
577 };
578 }
579
580 Spec.prototype.addExpectationResult = function(passed, data, isError) {
581 var expectationResult = this.expectationResultFactory(data);
582 if (passed) {
583 this.result.passedExpectations.push(expectationResult);
584 } else {
585 this.result.failedExpectations.push(expectationResult);
586
587 if (this.throwOnExpectationFailure && !isError) {
588 throw new j$.errors.ExpectationFailed();
589 }
590 }
591 };
592
593 Spec.prototype.expect = function(actual) {
594 return this.expectationFactory(actual, this);
595 };
596
597 Spec.prototype.expectAsync = function(actual) {
598 return this.asyncExpectationFactory(actual, this);
599 };
600
601 Spec.prototype.execute = function(onComplete, excluded) {
602 var self = this;
603
604 var onStart = {
605 fn: function(done) {
606 self.onStart(self, done);
607 }
608 };
609
610 var complete = {
611 fn: function(done) {
612 self.queueableFn.fn = null;
613 self.result.status = self.status(excluded);
614 self.resultCallback(self.result, done);
615 }
616 };
617
618 var fns = this.beforeAndAfterFns();
619 var regularFns = fns.befores.concat(this.queueableFn);
620
621 var runnerConfig = {
622 isLeaf: true,
623 queueableFns: regularFns,
624 cleanupFns: fns.afters,
625 onException: function () {
626 self.onException.apply(self, arguments);
627 },
628 onComplete: function() {
629 onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed'));
630 },
631 userContext: this.userContext()
632 };
633
634 if (this.markedPending || excluded === true) {
635 runnerConfig.queueableFns = [];
636 runnerConfig.cleanupFns = [];
637 }
638
639 runnerConfig.queueableFns.unshift(onStart);
640 runnerConfig.cleanupFns.push(complete);
641
642 this.queueRunnerFactory(runnerConfig);
643 };
644
645 Spec.prototype.onException = function onException(e) {
646 if (Spec.isPendingSpecException(e)) {
647 this.pend(extractCustomPendingMessage(e));
648 return;
649 }
650
651 if (e instanceof j$.errors.ExpectationFailed) {
652 return;
653 }
654
655 this.addExpectationResult(false, {
656 matcherName: '',
657 passed: false,
658 expected: '',
659 actual: '',
660 error: e
661 }, true);
662 };
663
664 Spec.prototype.pend = function(message) {
665 this.markedPending = true;
666 if (message) {
667 this.result.pendingReason = message;
668 }
669 };
670
671 Spec.prototype.getResult = function() {
672 this.result.status = this.status();
673 return this.result;
674 };
675
676 Spec.prototype.status = function(excluded) {
677 if (excluded === true) {
678 return 'excluded';
679 }
680
681 if (this.markedPending) {
682 return 'pending';
683 }
684
685 if (this.result.failedExpectations.length > 0) {
686 return 'failed';
687 } else {
688 return 'passed';
689 }
690 };
691
692 Spec.prototype.getFullName = function() {
693 return this.getSpecName(this);
694 };
695
696 Spec.prototype.addDeprecationWarning = function(deprecation) {
697 if (typeof deprecation === 'string') {
698 deprecation = { message: deprecation };
699 }
700 this.result.deprecationWarnings.push(this.expectationResultFactory(deprecation));
701 };
702
703 var extractCustomPendingMessage = function(e) {
704 var fullMessage = e.toString(),
705 boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
706 boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length;
707
708 return fullMessage.substr(boilerplateEnd);
709 };
710
711 Spec.pendingSpecExceptionMessage = '=> marked Pending';
712
713 Spec.isPendingSpecException = function(e) {
714 return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1);
715 };
716
717 return Spec;
718};
719
720if (typeof window == void 0 && typeof exports == 'object') {
721 /* globals exports */
722 exports.Spec = jasmineRequire.Spec;
723}
724
725/*jshint bitwise: false*/
726
727getJasmineRequireObj().Order = function() {
728 function Order(options) {
729 this.random = 'random' in options ? options.random : true;
730 var seed = this.seed = options.seed || generateSeed();
731 this.sort = this.random ? randomOrder : naturalOrder;
732
733 function naturalOrder(items) {
734 return items;
735 }
736
737 function randomOrder(items) {
738 var copy = items.slice();
739 copy.sort(function(a, b) {
740 return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id);
741 });
742 return copy;
743 }
744
745 function generateSeed() {
746 return String(Math.random()).slice(-5);
747 }
748
749 // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function
750 // used to get a different output when the key changes slighly.
751 // We use your return to sort the children randomly in a consistent way when
752 // used in conjunction with a seed
753
754 function jenkinsHash(key) {
755 var hash, i;
756 for(hash = i = 0; i < key.length; ++i) {
757 hash += key.charCodeAt(i);
758 hash += (hash << 10);
759 hash ^= (hash >> 6);
760 }
761 hash += (hash << 3);
762 hash ^= (hash >> 11);
763 hash += (hash << 15);
764 return hash;
765 }
766
767 }
768
769 return Order;
770};
771
772getJasmineRequireObj().Env = function(j$) {
773 /**
774 * _Note:_ Do not construct this directly, Jasmine will make one during booting.
775 * @name Env
776 * @classdesc The Jasmine environment
777 * @constructor
778 */
779 function Env(options) {
780 options = options || {};
781
782 var self = this;
783 var global = options.global || j$.getGlobal();
784
785 var totalSpecsDefined = 0;
786
787 var realSetTimeout = global.setTimeout;
788 var realClearTimeout = global.clearTimeout;
789 var clearStack = j$.getClearStack(global);
790 this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
791
792 var runnableResources = {};
793
794 var currentSpec = null;
795 var currentlyExecutingSuites = [];
796 var currentDeclarationSuite = null;
797 var throwOnExpectationFailure = false;
798 var stopOnSpecFailure = false;
799 var random = true;
800 var hidingDisabled = false;
801 var seed = null;
802 var handlingLoadErrors = true;
803 var hasFailures = false;
804
805 var currentSuite = function() {
806 return currentlyExecutingSuites[currentlyExecutingSuites.length - 1];
807 };
808
809 var currentRunnable = function() {
810 return currentSpec || currentSuite();
811 };
812
813 var globalErrors = null;
814
815 var installGlobalErrors = function() {
816 if (globalErrors) {
817 return;
818 }
819
820 globalErrors = new j$.GlobalErrors();
821 globalErrors.install();
822 };
823
824 if (!options.suppressLoadErrors) {
825 installGlobalErrors();
826 globalErrors.pushListener(function(message, filename, lineno) {
827 topSuite.result.failedExpectations.push({
828 passed: false,
829 globalErrorType: 'load',
830 message: message,
831 filename: filename,
832 lineno: lineno
833 });
834 });
835 }
836
837 this.specFilter = function() {
838 return true;
839 };
840
841 this.addSpyStrategy = function(name, fn) {
842 if(!currentRunnable()) {
843 throw new Error('Custom spy strategies must be added in a before function or a spec');
844 }
845 runnableResources[currentRunnable().id].customSpyStrategies[name] = fn;
846 };
847
848 this.addCustomEqualityTester = function(tester) {
849 if(!currentRunnable()) {
850 throw new Error('Custom Equalities must be added in a before function or a spec');
851 }
852 runnableResources[currentRunnable().id].customEqualityTesters.push(tester);
853 };
854
855 this.addMatchers = function(matchersToAdd) {
856 if(!currentRunnable()) {
857 throw new Error('Matchers must be added in a before function or a spec');
858 }
859 var customMatchers = runnableResources[currentRunnable().id].customMatchers;
860 for (var matcherName in matchersToAdd) {
861 customMatchers[matcherName] = matchersToAdd[matcherName];
862 }
863 };
864
865 j$.Expectation.addCoreMatchers(j$.matchers);
866
867 var nextSpecId = 0;
868 var getNextSpecId = function() {
869 return 'spec' + nextSpecId++;
870 };
871
872 var nextSuiteId = 0;
873 var getNextSuiteId = function() {
874 return 'suite' + nextSuiteId++;
875 };
876
877 var expectationFactory = function(actual, spec) {
878 return j$.Expectation.Factory({
879 util: j$.matchersUtil,
880 customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
881 customMatchers: runnableResources[spec.id].customMatchers,
882 actual: actual,
883 addExpectationResult: addExpectationResult
884 });
885
886 function addExpectationResult(passed, result) {
887 return spec.addExpectationResult(passed, result);
888 }
889 };
890
891 var asyncExpectationFactory = function(actual, spec) {
892 return j$.AsyncExpectation.factory({
893 util: j$.matchersUtil,
894 customEqualityTesters: runnableResources[spec.id].customEqualityTesters,
895 actual: actual,
896 addExpectationResult: addExpectationResult
897 });
898
899 function addExpectationResult(passed, result) {
900 return spec.addExpectationResult(passed, result);
901 }
902 };
903
904 var defaultResourcesForRunnable = function(id, parentRunnableId) {
905 var resources = {spies: [], customEqualityTesters: [], customMatchers: {}, customSpyStrategies: {}};
906
907 if(runnableResources[parentRunnableId]){
908 resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters);
909 resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers);
910 }
911
912 runnableResources[id] = resources;
913 };
914
915 var clearResourcesForRunnable = function(id) {
916 spyRegistry.clearSpies();
917 delete runnableResources[id];
918 };
919
920 var beforeAndAfterFns = function(suite) {
921 return function() {
922 var befores = [],
923 afters = [];
924
925 while(suite) {
926 befores = befores.concat(suite.beforeFns);
927 afters = afters.concat(suite.afterFns);
928
929 suite = suite.parentSuite;
930 }
931
932 return {
933 befores: befores.reverse(),
934 afters: afters
935 };
936 };
937 };
938
939 var getSpecName = function(spec, suite) {
940 var fullName = [spec.description],
941 suiteFullName = suite.getFullName();
942
943 if (suiteFullName !== '') {
944 fullName.unshift(suiteFullName);
945 }
946 return fullName.join(' ');
947 };
948
949 // TODO: we may just be able to pass in the fn instead of wrapping here
950 var buildExpectationResult = j$.buildExpectationResult,
951 exceptionFormatter = new j$.ExceptionFormatter(),
952 expectationResultFactory = function(attrs) {
953 attrs.messageFormatter = exceptionFormatter.message;
954 attrs.stackFormatter = exceptionFormatter.stack;
955
956 return buildExpectationResult(attrs);
957 };
958
959 var maximumSpecCallbackDepth = 20;
960 var currentSpecCallbackDepth = 0;
961
962 /**
963 * Sets whether Jasmine should throw an Error when an expectation fails.
964 * This causes a spec to only have one expectation failure.
965 * @name Env#throwOnExpectationFailure
966 * @function
967 * @param {Boolean} value Whether to throw when a expectation fails
968 */
969 this.throwOnExpectationFailure = function(value) {
970 throwOnExpectationFailure = !!value;
971 };
972
973 this.throwingExpectationFailures = function() {
974 return throwOnExpectationFailure;
975 };
976
977 /**
978 * Set whether to stop suite execution when a spec fails
979 * @name Env#stopOnSpecFailure
980 * @function
981 * @param {Boolean} value Whether to stop suite execution when a spec fails
982 */
983 this.stopOnSpecFailure = function(value) {
984 stopOnSpecFailure = !!value;
985 };
986
987 this.stoppingOnSpecFailure = function() {
988 return stopOnSpecFailure;
989 };
990
991 /**
992 * Set whether to randomize test execution order
993 * @name Env#randomizeTests
994 * @function
995 * @param {Boolean} value Whether to randomize execution order
996 */
997 this.randomizeTests = function(value) {
998 random = !!value;
999 };
1000
1001 this.randomTests = function() {
1002 return random;
1003 };
1004
1005 /**
1006 * Set the random number seed for spec randomization
1007 * @name Env#seed
1008 * @function
1009 * @param {Number} value The seed value
1010 */
1011 this.seed = function(value) {
1012 if (value) {
1013 seed = value;
1014 }
1015 return seed;
1016 };
1017
1018 this.hidingDisabled = function(value) {
1019 return hidingDisabled;
1020 };
1021
1022 /**
1023 * @name Env#hideDisabled
1024 * @function
1025 */
1026 this.hideDisabled = function(value) {
1027 hidingDisabled = !!value;
1028 };
1029
1030 this.deprecated = function(deprecation) {
1031 var runnable = currentRunnable() || topSuite;
1032 runnable.addDeprecationWarning(deprecation);
1033 if(typeof console !== 'undefined' && typeof console.error === 'function') {
1034 console.error('DEPRECATION:', deprecation);
1035 }
1036 };
1037
1038 var queueRunnerFactory = function(options, args) {
1039 var failFast = false;
1040 if (options.isLeaf) {
1041 failFast = throwOnExpectationFailure;
1042 } else if (!options.isReporter) {
1043 failFast = stopOnSpecFailure;
1044 }
1045 options.clearStack = options.clearStack || clearStack;
1046 options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
1047 options.fail = self.fail;
1048 options.globalErrors = globalErrors;
1049 options.completeOnFirstError = failFast;
1050 options.onException = options.onException || function(e) {
1051 (currentRunnable() || topSuite).onException(e);
1052 };
1053 options.deprecated = self.deprecated;
1054
1055 new j$.QueueRunner(options).execute(args);
1056 };
1057
1058 var topSuite = new j$.Suite({
1059 env: this,
1060 id: getNextSuiteId(),
1061 description: 'Jasmine__TopLevel__Suite',
1062 expectationFactory: expectationFactory,
1063 asyncExpectationFactory: asyncExpectationFactory,
1064 expectationResultFactory: expectationResultFactory
1065 });
1066 defaultResourcesForRunnable(topSuite.id);
1067 currentDeclarationSuite = topSuite;
1068
1069 this.topSuite = function() {
1070 return topSuite;
1071 };
1072
1073 /**
1074 * This represents the available reporter callback for an object passed to {@link Env#addReporter}.
1075 * @interface Reporter
1076 * @see custom_reporter
1077 */
1078 var reporter = new j$.ReportDispatcher([
1079 /**
1080 * `jasmineStarted` is called after all of the specs have been loaded, but just before execution starts.
1081 * @function
1082 * @name Reporter#jasmineStarted
1083 * @param {JasmineStartedInfo} suiteInfo Information about the full Jasmine suite that is being run
1084 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1085 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1086 * @see async
1087 */
1088 'jasmineStarted',
1089 /**
1090 * When the entire suite has finished execution `jasmineDone` is called
1091 * @function
1092 * @name Reporter#jasmineDone
1093 * @param {JasmineDoneInfo} suiteInfo Information about the full Jasmine suite that just finished running.
1094 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1095 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1096 * @see async
1097 */
1098 'jasmineDone',
1099 /**
1100 * `suiteStarted` is invoked when a `describe` starts to run
1101 * @function
1102 * @name Reporter#suiteStarted
1103 * @param {SuiteResult} result Information about the individual {@link describe} being run
1104 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1105 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1106 * @see async
1107 */
1108 'suiteStarted',
1109 /**
1110 * `suiteDone` is invoked when all of the child specs and suites for a given suite have been run
1111 *
1112 * While jasmine doesn't require any specific functions, not defining a `suiteDone` will make it impossible for a reporter to know when a suite has failures in an `afterAll`.
1113 * @function
1114 * @name Reporter#suiteDone
1115 * @param {SuiteResult} result
1116 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1117 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1118 * @see async
1119 */
1120 'suiteDone',
1121 /**
1122 * `specStarted` is invoked when an `it` starts to run (including associated `beforeEach` functions)
1123 * @function
1124 * @name Reporter#specStarted
1125 * @param {SpecResult} result Information about the individual {@link it} being run
1126 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1127 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1128 * @see async
1129 */
1130 'specStarted',
1131 /**
1132 * `specDone` is invoked when an `it` and its associated `beforeEach` and `afterEach` functions have been run.
1133 *
1134 * While jasmine doesn't require any specific functions, not defining a `specDone` will make it impossible for a reporter to know when a spec has failed.
1135 * @function
1136 * @name Reporter#specDone
1137 * @param {SpecResult} result
1138 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
1139 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
1140 * @see async
1141 */
1142 'specDone'
1143 ], queueRunnerFactory);
1144
1145 this.execute = function(runnablesToRun) {
1146 var self = this;
1147 installGlobalErrors();
1148
1149 if(!runnablesToRun) {
1150 if (focusedRunnables.length) {
1151 runnablesToRun = focusedRunnables;
1152 } else {
1153 runnablesToRun = [topSuite.id];
1154 }
1155 }
1156
1157 var order = new j$.Order({
1158 random: random,
1159 seed: seed
1160 });
1161
1162 var processor = new j$.TreeProcessor({
1163 tree: topSuite,
1164 runnableIds: runnablesToRun,
1165 queueRunnerFactory: queueRunnerFactory,
1166 nodeStart: function(suite, next) {
1167 currentlyExecutingSuites.push(suite);
1168 defaultResourcesForRunnable(suite.id, suite.parentSuite.id);
1169 reporter.suiteStarted(suite.result, next);
1170 },
1171 nodeComplete: function(suite, result, next) {
1172 if (suite !== currentSuite()) {
1173 throw new Error('Tried to complete the wrong suite');
1174 }
1175
1176 clearResourcesForRunnable(suite.id);
1177 currentlyExecutingSuites.pop();
1178
1179 if (result.status === 'failed') {
1180 hasFailures = true;
1181 }
1182
1183 reporter.suiteDone(result, next);
1184 },
1185 orderChildren: function(node) {
1186 return order.sort(node.children);
1187 },
1188 excludeNode: function(spec) {
1189 return !self.specFilter(spec);
1190 }
1191 });
1192
1193 if(!processor.processTree().valid) {
1194 throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times');
1195 }
1196
1197 /**
1198 * Information passed to the {@link Reporter#jasmineStarted} event.
1199 * @typedef JasmineStartedInfo
1200 * @property {Int} totalSpecsDefined - The total number of specs defined in this suite.
1201 * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1202 */
1203 reporter.jasmineStarted({
1204 totalSpecsDefined: totalSpecsDefined,
1205 order: order
1206 }, function() {
1207 currentlyExecutingSuites.push(topSuite);
1208
1209 processor.execute(function () {
1210 clearResourcesForRunnable(topSuite.id);
1211 currentlyExecutingSuites.pop();
1212 var overallStatus, incompleteReason;
1213
1214 if (hasFailures || topSuite.result.failedExpectations.length > 0) {
1215 overallStatus = 'failed';
1216 } else if (focusedRunnables.length > 0) {
1217 overallStatus = 'incomplete';
1218 incompleteReason = 'fit() or fdescribe() was found';
1219 } else if (totalSpecsDefined === 0) {
1220 overallStatus = 'incomplete';
1221 incompleteReason = 'No specs found';
1222 } else {
1223 overallStatus = 'passed';
1224 }
1225
1226 /**
1227 * Information passed to the {@link Reporter#jasmineDone} event.
1228 * @typedef JasmineDoneInfo
1229 * @property {OverallStatus} overallStatus - The overall result of the sute: 'passed', 'failed', or 'incomplete'.
1230 * @property {IncompleteReason} incompleteReason - Explanation of why the suite was incomplete.
1231 * @property {Order} order - Information about the ordering (random or not) of this execution of the suite.
1232 * @property {Expectation[]} failedExpectations - List of expectations that failed in an {@link afterAll} at the global level.
1233 * @property {Expectation[]} deprecationWarnings - List of deprecation warnings that occurred at the global level.
1234 */
1235 reporter.jasmineDone({
1236 overallStatus: overallStatus,
1237 incompleteReason: incompleteReason,
1238 order: order,
1239 failedExpectations: topSuite.result.failedExpectations,
1240 deprecationWarnings: topSuite.result.deprecationWarnings
1241 }, function() {});
1242 });
1243 });
1244 };
1245
1246 /**
1247 * Add a custom reporter to the Jasmine environment.
1248 * @name Env#addReporter
1249 * @function
1250 * @param {Reporter} reporterToAdd The reporter to be added.
1251 * @see custom_reporter
1252 */
1253 this.addReporter = function(reporterToAdd) {
1254 reporter.addReporter(reporterToAdd);
1255 };
1256
1257 /**
1258 * Provide a fallback reporter if no other reporters have been specified.
1259 * @name Env#provideFallbackReporter
1260 * @function
1261 * @param {Reporter} reporterToAdd The reporter
1262 * @see custom_reporter
1263 */
1264 this.provideFallbackReporter = function(reporterToAdd) {
1265 reporter.provideFallbackReporter(reporterToAdd);
1266 };
1267
1268 /**
1269 * Clear all registered reporters
1270 * @name Env#clearReporters
1271 * @function
1272 */
1273 this.clearReporters = function() {
1274 reporter.clearReporters();
1275 };
1276
1277 var spyFactory = new j$.SpyFactory(function() {
1278 var runnable = currentRunnable();
1279
1280 if (runnable) {
1281 return runnableResources[runnable.id].customSpyStrategies;
1282 }
1283
1284 return {};
1285 });
1286
1287 var spyRegistry = new j$.SpyRegistry({
1288 currentSpies: function() {
1289 if(!currentRunnable()) {
1290 throw new Error('Spies must be created in a before function or a spec');
1291 }
1292 return runnableResources[currentRunnable().id].spies;
1293 },
1294 createSpy: function(name, originalFn) {
1295 return self.createSpy(name, originalFn);
1296 }
1297 });
1298
1299 this.allowRespy = function(allow){
1300 spyRegistry.allowRespy(allow);
1301 };
1302
1303 this.spyOn = function() {
1304 return spyRegistry.spyOn.apply(spyRegistry, arguments);
1305 };
1306
1307 this.spyOnProperty = function() {
1308 return spyRegistry.spyOnProperty.apply(spyRegistry, arguments);
1309 };
1310
1311 this.createSpy = function(name, originalFn) {
1312 if (arguments.length === 1 && j$.isFunction_(name)) {
1313 originalFn = name;
1314 name = originalFn.name;
1315 }
1316
1317 return spyFactory.createSpy(name, originalFn);
1318 };
1319
1320 this.createSpyObj = function(baseName, methodNames) {
1321 return spyFactory.createSpyObj(baseName, methodNames);
1322 };
1323
1324 var ensureIsFunction = function(fn, caller) {
1325 if (!j$.isFunction_(fn)) {
1326 throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
1327 }
1328 };
1329
1330 var ensureIsFunctionOrAsync = function(fn, caller) {
1331 if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
1332 throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
1333 }
1334 };
1335
1336 function ensureIsNotNested(method) {
1337 var runnable = currentRunnable();
1338 if (runnable !== null && runnable !== undefined) {
1339 throw new Error('\'' + method + '\' should only be used in \'describe\' function');
1340 }
1341 }
1342
1343 var suiteFactory = function(description) {
1344 var suite = new j$.Suite({
1345 env: self,
1346 id: getNextSuiteId(),
1347 description: description,
1348 parentSuite: currentDeclarationSuite,
1349 expectationFactory: expectationFactory,
1350 asyncExpectationFactory: asyncExpectationFactory,
1351 expectationResultFactory: expectationResultFactory,
1352 throwOnExpectationFailure: throwOnExpectationFailure
1353 });
1354
1355 return suite;
1356 };
1357
1358 this.describe = function(description, specDefinitions) {
1359 ensureIsNotNested('describe');
1360 ensureIsFunction(specDefinitions, 'describe');
1361 var suite = suiteFactory(description);
1362 if (specDefinitions.length > 0) {
1363 throw new Error('describe does not expect any arguments');
1364 }
1365 if (currentDeclarationSuite.markedPending) {
1366 suite.pend();
1367 }
1368 addSpecsToSuite(suite, specDefinitions);
1369 return suite;
1370 };
1371
1372 this.xdescribe = function(description, specDefinitions) {
1373 ensureIsNotNested('xdescribe');
1374 ensureIsFunction(specDefinitions, 'xdescribe');
1375 var suite = suiteFactory(description);
1376 suite.pend();
1377 addSpecsToSuite(suite, specDefinitions);
1378 return suite;
1379 };
1380
1381 var focusedRunnables = [];
1382
1383 this.fdescribe = function(description, specDefinitions) {
1384 ensureIsNotNested('fdescribe');
1385 ensureIsFunction(specDefinitions, 'fdescribe');
1386 var suite = suiteFactory(description);
1387 suite.isFocused = true;
1388
1389 focusedRunnables.push(suite.id);
1390 unfocusAncestor();
1391 addSpecsToSuite(suite, specDefinitions);
1392
1393 return suite;
1394 };
1395
1396 function addSpecsToSuite(suite, specDefinitions) {
1397 var parentSuite = currentDeclarationSuite;
1398 parentSuite.addChild(suite);
1399 currentDeclarationSuite = suite;
1400
1401 var declarationError = null;
1402 try {
1403 specDefinitions.call(suite);
1404 } catch (e) {
1405 declarationError = e;
1406 }
1407
1408 if (declarationError) {
1409 suite.onException(declarationError);
1410 }
1411
1412 currentDeclarationSuite = parentSuite;
1413 }
1414
1415 function findFocusedAncestor(suite) {
1416 while (suite) {
1417 if (suite.isFocused) {
1418 return suite.id;
1419 }
1420 suite = suite.parentSuite;
1421 }
1422
1423 return null;
1424 }
1425
1426 function unfocusAncestor() {
1427 var focusedAncestor = findFocusedAncestor(currentDeclarationSuite);
1428 if (focusedAncestor) {
1429 for (var i = 0; i < focusedRunnables.length; i++) {
1430 if (focusedRunnables[i] === focusedAncestor) {
1431 focusedRunnables.splice(i, 1);
1432 break;
1433 }
1434 }
1435 }
1436 }
1437
1438 var specFactory = function(description, fn, suite, timeout) {
1439 totalSpecsDefined++;
1440 var spec = new j$.Spec({
1441 id: getNextSpecId(),
1442 beforeAndAfterFns: beforeAndAfterFns(suite),
1443 expectationFactory: expectationFactory,
1444 asyncExpectationFactory: asyncExpectationFactory,
1445 resultCallback: specResultCallback,
1446 getSpecName: function(spec) {
1447 return getSpecName(spec, suite);
1448 },
1449 onStart: specStarted,
1450 description: description,
1451 expectationResultFactory: expectationResultFactory,
1452 queueRunnerFactory: queueRunnerFactory,
1453 userContext: function() { return suite.clonedSharedUserContext(); },
1454 queueableFn: {
1455 fn: fn,
1456 timeout: timeout || 0
1457 },
1458 throwOnExpectationFailure: throwOnExpectationFailure
1459 });
1460
1461 return spec;
1462
1463 function specResultCallback(result, next) {
1464 clearResourcesForRunnable(spec.id);
1465 currentSpec = null;
1466
1467 if (result.status === 'failed') {
1468 hasFailures = true;
1469 }
1470
1471 reporter.specDone(result, next);
1472 }
1473
1474 function specStarted(spec, next) {
1475 currentSpec = spec;
1476 defaultResourcesForRunnable(spec.id, suite.id);
1477 reporter.specStarted(spec.result, next);
1478 }
1479 };
1480
1481 this.it = function(description, fn, timeout) {
1482 ensureIsNotNested('it');
1483 // it() sometimes doesn't have a fn argument, so only check the type if
1484 // it's given.
1485 if (arguments.length > 1 && typeof fn !== 'undefined') {
1486 ensureIsFunctionOrAsync(fn, 'it');
1487 }
1488 var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
1489 if (currentDeclarationSuite.markedPending) {
1490 spec.pend();
1491 }
1492 currentDeclarationSuite.addChild(spec);
1493 return spec;
1494 };
1495
1496 this.xit = function(description, fn, timeout) {
1497 ensureIsNotNested('xit');
1498 // xit(), like it(), doesn't always have a fn argument, so only check the
1499 // type when needed.
1500 if (arguments.length > 1 && typeof fn !== 'undefined') {
1501 ensureIsFunctionOrAsync(fn, 'xit');
1502 }
1503 var spec = this.it.apply(this, arguments);
1504 spec.pend('Temporarily disabled with xit');
1505 return spec;
1506 };
1507
1508 this.fit = function(description, fn, timeout){
1509 ensureIsNotNested('fit');
1510 ensureIsFunctionOrAsync(fn, 'fit');
1511 var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
1512 currentDeclarationSuite.addChild(spec);
1513 focusedRunnables.push(spec.id);
1514 unfocusAncestor();
1515 return spec;
1516 };
1517
1518 this.expect = function(actual) {
1519 if (!currentRunnable()) {
1520 throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
1521 }
1522
1523 return currentRunnable().expect(actual);
1524 };
1525
1526 this.expectAsync = function(actual) {
1527 if (!currentRunnable()) {
1528 throw new Error('\'expectAsync\' was used when there was no current spec, this could be because an asynchronous test timed out');
1529 }
1530
1531 return currentRunnable().expectAsync(actual);
1532 };
1533
1534 this.beforeEach = function(beforeEachFunction, timeout) {
1535 ensureIsNotNested('beforeEach');
1536 ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
1537 currentDeclarationSuite.beforeEach({
1538 fn: beforeEachFunction,
1539 timeout: timeout || 0
1540 });
1541 };
1542
1543 this.beforeAll = function(beforeAllFunction, timeout) {
1544 ensureIsNotNested('beforeAll');
1545 ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
1546 currentDeclarationSuite.beforeAll({
1547 fn: beforeAllFunction,
1548 timeout: timeout || 0
1549 });
1550 };
1551
1552 this.afterEach = function(afterEachFunction, timeout) {
1553 ensureIsNotNested('afterEach');
1554 ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
1555 afterEachFunction.isCleanup = true;
1556 currentDeclarationSuite.afterEach({
1557 fn: afterEachFunction,
1558 timeout: timeout || 0
1559 });
1560 };
1561
1562 this.afterAll = function(afterAllFunction, timeout) {
1563 ensureIsNotNested('afterAll');
1564 ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
1565 currentDeclarationSuite.afterAll({
1566 fn: afterAllFunction,
1567 timeout: timeout || 0
1568 });
1569 };
1570
1571 this.pending = function(message) {
1572 var fullMessage = j$.Spec.pendingSpecExceptionMessage;
1573 if(message) {
1574 fullMessage += message;
1575 }
1576 throw fullMessage;
1577 };
1578
1579 this.fail = function(error) {
1580 if (!currentRunnable()) {
1581 throw new Error('\'fail\' was used when there was no current spec, this could be because an asynchronous test timed out');
1582 }
1583
1584 var message = 'Failed';
1585 if (error) {
1586 message += ': ';
1587 if (error.message) {
1588 message += error.message;
1589 } else if (j$.isString_(error)) {
1590 message += error;
1591 } else {
1592 // pretty print all kind of objects. This includes arrays.
1593 message += j$.pp(error);
1594 }
1595 }
1596
1597 currentRunnable().addExpectationResult(false, {
1598 matcherName: '',
1599 passed: false,
1600 expected: '',
1601 actual: '',
1602 message: message,
1603 error: error && error.message ? error : null
1604 });
1605
1606 if (self.throwingExpectationFailures()) {
1607 throw new Error(message);
1608 }
1609 };
1610 }
1611
1612 return Env;
1613};
1614
1615getJasmineRequireObj().JsApiReporter = function() {
1616
1617 var noopTimer = {
1618 start: function(){},
1619 elapsed: function(){ return 0; }
1620 };
1621
1622 /**
1623 * @name jsApiReporter
1624 * @classdesc {@link Reporter} added by default in `boot.js` to record results for retrieval in javascript code. An instance is made available as `jsApiReporter` on the global object.
1625 * @class
1626 * @hideconstructor
1627 */
1628 function JsApiReporter(options) {
1629 var timer = options.timer || noopTimer,
1630 status = 'loaded';
1631
1632 this.started = false;
1633 this.finished = false;
1634 this.runDetails = {};
1635
1636 this.jasmineStarted = function() {
1637 this.started = true;
1638 status = 'started';
1639 timer.start();
1640 };
1641
1642 var executionTime;
1643
1644 this.jasmineDone = function(runDetails) {
1645 this.finished = true;
1646 this.runDetails = runDetails;
1647 executionTime = timer.elapsed();
1648 status = 'done';
1649 };
1650
1651 /**
1652 * Get the current status for the Jasmine environment.
1653 * @name jsApiReporter#status
1654 * @function
1655 * @return {String} - One of `loaded`, `started`, or `done`
1656 */
1657 this.status = function() {
1658 return status;
1659 };
1660
1661 var suites = [],
1662 suites_hash = {};
1663
1664 this.suiteStarted = function(result) {
1665 suites_hash[result.id] = result;
1666 };
1667
1668 this.suiteDone = function(result) {
1669 storeSuite(result);
1670 };
1671
1672 /**
1673 * Get the results for a set of suites.
1674 *
1675 * Retrievable in slices for easier serialization.
1676 * @name jsApiReporter#suiteResults
1677 * @function
1678 * @param {Number} index - The position in the suites list to start from.
1679 * @param {Number} length - Maximum number of suite results to return.
1680 * @return {SuiteResult[]}
1681 */
1682 this.suiteResults = function(index, length) {
1683 return suites.slice(index, index + length);
1684 };
1685
1686 function storeSuite(result) {
1687 suites.push(result);
1688 suites_hash[result.id] = result;
1689 }
1690
1691 /**
1692 * Get all of the suites in a single object, with their `id` as the key.
1693 * @name jsApiReporter#suites
1694 * @function
1695 * @return {Object} - Map of suite id to {@link SuiteResult}
1696 */
1697 this.suites = function() {
1698 return suites_hash;
1699 };
1700
1701 var specs = [];
1702
1703 this.specDone = function(result) {
1704 specs.push(result);
1705 };
1706
1707 /**
1708 * Get the results for a set of specs.
1709 *
1710 * Retrievable in slices for easier serialization.
1711 * @name jsApiReporter#specResults
1712 * @function
1713 * @param {Number} index - The position in the specs list to start from.
1714 * @param {Number} length - Maximum number of specs results to return.
1715 * @return {SpecResult[]}
1716 */
1717 this.specResults = function(index, length) {
1718 return specs.slice(index, index + length);
1719 };
1720
1721 /**
1722 * Get all spec results.
1723 * @name jsApiReporter#specs
1724 * @function
1725 * @return {SpecResult[]}
1726 */
1727 this.specs = function() {
1728 return specs;
1729 };
1730
1731 /**
1732 * Get the number of milliseconds it took for the full Jasmine suite to run.
1733 * @name jsApiReporter#executionTime
1734 * @function
1735 * @return {Number}
1736 */
1737 this.executionTime = function() {
1738 return executionTime;
1739 };
1740
1741 }
1742
1743 return JsApiReporter;
1744};
1745
1746getJasmineRequireObj().Any = function(j$) {
1747
1748 function Any(expectedObject) {
1749 if (typeof expectedObject === 'undefined') {
1750 throw new TypeError(
1751 'jasmine.any() expects to be passed a constructor function. ' +
1752 'Please pass one or use jasmine.anything() to match any object.'
1753 );
1754 }
1755 this.expectedObject = expectedObject;
1756 }
1757
1758 Any.prototype.asymmetricMatch = function(other) {
1759 if (this.expectedObject == String) {
1760 return typeof other == 'string' || other instanceof String;
1761 }
1762
1763 if (this.expectedObject == Number) {
1764 return typeof other == 'number' || other instanceof Number;
1765 }
1766
1767 if (this.expectedObject == Function) {
1768 return typeof other == 'function' || other instanceof Function;
1769 }
1770
1771 if (this.expectedObject == Object) {
1772 return other !== null && typeof other == 'object';
1773 }
1774
1775 if (this.expectedObject == Boolean) {
1776 return typeof other == 'boolean';
1777 }
1778
1779 /* jshint -W122 */
1780 /* global Symbol */
1781 if (typeof Symbol != 'undefined' && this.expectedObject == Symbol) {
1782 return typeof other == 'symbol';
1783 }
1784 /* jshint +W122 */
1785
1786 return other instanceof this.expectedObject;
1787 };
1788
1789 Any.prototype.jasmineToString = function() {
1790 return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>';
1791 };
1792
1793 return Any;
1794};
1795
1796getJasmineRequireObj().Anything = function(j$) {
1797
1798 function Anything() {}
1799
1800 Anything.prototype.asymmetricMatch = function(other) {
1801 return !j$.util.isUndefined(other) && other !== null;
1802 };
1803
1804 Anything.prototype.jasmineToString = function() {
1805 return '<jasmine.anything>';
1806 };
1807
1808 return Anything;
1809};
1810
1811getJasmineRequireObj().ArrayContaining = function(j$) {
1812 function ArrayContaining(sample) {
1813 this.sample = sample;
1814 }
1815
1816 ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
1817 if (!j$.isArray_(this.sample)) {
1818 throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
1819 }
1820
1821 for (var i = 0; i < this.sample.length; i++) {
1822 var item = this.sample[i];
1823 if (!j$.matchersUtil.contains(other, item, customTesters)) {
1824 return false;
1825 }
1826 }
1827
1828 return true;
1829 };
1830
1831 ArrayContaining.prototype.jasmineToString = function () {
1832 return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
1833 };
1834
1835 return ArrayContaining;
1836};
1837
1838getJasmineRequireObj().ArrayWithExactContents = function(j$) {
1839
1840 function ArrayWithExactContents(sample) {
1841 this.sample = sample;
1842 }
1843
1844 ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
1845 if (!j$.isArray_(this.sample)) {
1846 throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
1847 }
1848
1849 if (this.sample.length !== other.length) {
1850 return false;
1851 }
1852
1853 for (var i = 0; i < this.sample.length; i++) {
1854 var item = this.sample[i];
1855 if (!j$.matchersUtil.contains(other, item, customTesters)) {
1856 return false;
1857 }
1858 }
1859
1860 return true;
1861 };
1862
1863 ArrayWithExactContents.prototype.jasmineToString = function() {
1864 return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
1865 };
1866
1867 return ArrayWithExactContents;
1868};
1869
1870getJasmineRequireObj().Empty = function (j$) {
1871
1872 function Empty() {}
1873
1874 Empty.prototype.asymmetricMatch = function (other) {
1875 if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
1876 return other.length === 0;
1877 }
1878
1879 if (j$.isMap(other) || j$.isSet(other)) {
1880 return other.size === 0;
1881 }
1882
1883 if (j$.isObject_(other)) {
1884 return Object.keys(other).length === 0;
1885 }
1886 return false;
1887 };
1888
1889 Empty.prototype.jasmineToString = function () {
1890 return '<jasmine.empty>';
1891 };
1892
1893 return Empty;
1894};
1895
1896getJasmineRequireObj().Falsy = function(j$) {
1897
1898 function Falsy() {}
1899
1900 Falsy.prototype.asymmetricMatch = function(other) {
1901 return !other;
1902 };
1903
1904 Falsy.prototype.jasmineToString = function() {
1905 return '<jasmine.falsy>';
1906 };
1907
1908 return Falsy;
1909};
1910
1911getJasmineRequireObj().NotEmpty = function (j$) {
1912
1913 function NotEmpty() {}
1914
1915 NotEmpty.prototype.asymmetricMatch = function (other) {
1916 if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
1917 return other.length !== 0;
1918 }
1919
1920 if (j$.isMap(other) || j$.isSet(other)) {
1921 return other.size !== 0;
1922 }
1923
1924 if (j$.isObject_(other)) {
1925 return Object.keys(other).length !== 0;
1926 }
1927
1928 return false;
1929 };
1930
1931 NotEmpty.prototype.jasmineToString = function () {
1932 return '<jasmine.notEmpty>';
1933 };
1934
1935 return NotEmpty;
1936};
1937
1938getJasmineRequireObj().ObjectContaining = function(j$) {
1939
1940 function ObjectContaining(sample) {
1941 this.sample = sample;
1942 }
1943
1944 function getPrototype(obj) {
1945 if (Object.getPrototypeOf) {
1946 return Object.getPrototypeOf(obj);
1947 }
1948
1949 if (obj.constructor.prototype == obj) {
1950 return null;
1951 }
1952
1953 return obj.constructor.prototype;
1954 }
1955
1956 function hasProperty(obj, property) {
1957 if (!obj) {
1958 return false;
1959 }
1960
1961 if (Object.prototype.hasOwnProperty.call(obj, property)) {
1962 return true;
1963 }
1964
1965 return hasProperty(getPrototype(obj), property);
1966 }
1967
1968 ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
1969 if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
1970
1971 for (var property in this.sample) {
1972 if (!hasProperty(other, property) ||
1973 !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
1974 return false;
1975 }
1976 }
1977
1978 return true;
1979 };
1980
1981 ObjectContaining.prototype.jasmineToString = function() {
1982 return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
1983 };
1984
1985 return ObjectContaining;
1986};
1987
1988getJasmineRequireObj().StringMatching = function(j$) {
1989
1990 function StringMatching(expected) {
1991 if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
1992 throw new Error('Expected is not a String or a RegExp');
1993 }
1994
1995 this.regexp = new RegExp(expected);
1996 }
1997
1998 StringMatching.prototype.asymmetricMatch = function(other) {
1999 return this.regexp.test(other);
2000 };
2001
2002 StringMatching.prototype.jasmineToString = function() {
2003 return '<jasmine.stringMatching(' + this.regexp + ')>';
2004 };
2005
2006 return StringMatching;
2007};
2008
2009getJasmineRequireObj().Truthy = function(j$) {
2010
2011 function Truthy() {}
2012
2013 Truthy.prototype.asymmetricMatch = function(other) {
2014 return !!other;
2015 };
2016
2017 Truthy.prototype.jasmineToString = function() {
2018 return '<jasmine.truthy>';
2019 };
2020
2021 return Truthy;
2022};
2023
2024getJasmineRequireObj().AsyncExpectation = function(j$) {
2025 var promiseForMessage = {
2026 jasmineToString: function() { return 'a promise'; }
2027 };
2028
2029 /**
2030 * Asynchronous matchers.
2031 * @namespace async-matchers
2032 */
2033 function AsyncExpectation(options) {
2034 var global = options.global || j$.getGlobal();
2035 this.util = options.util || { buildFailureMessage: function() {} };
2036 this.customEqualityTesters = options.customEqualityTesters || [];
2037 this.addExpectationResult = options.addExpectationResult || function(){};
2038 this.actual = options.actual;
2039 this.isNot = options.isNot;
2040
2041 if (!global.Promise) {
2042 throw new Error('expectAsync is unavailable because the environment does not support promises.');
2043 }
2044
2045 if (!j$.isPromise(this.actual)) {
2046 throw new Error('Expected expectAsync to be called with a promise.');
2047 }
2048
2049 ['toBeResolved', 'toBeRejected', 'toBeResolvedTo'].forEach(wrapCompare.bind(this));
2050 }
2051
2052 function wrapCompare(name) {
2053 var compare = this[name];
2054 this[name] = function() {
2055 var self = this;
2056 var args = Array.prototype.slice.call(arguments);
2057 args.unshift(this.actual);
2058
2059 // Capture the call stack here, before we go async, so that it will
2060 // contain frames that are relevant to the user instead of just parts
2061 // of Jasmine.
2062 var errorForStack = j$.util.errorWithStack();
2063
2064 return compare.apply(self, args).then(function(result) {
2065 var message;
2066
2067 if (self.isNot) {
2068 result.pass = !result.pass;
2069 }
2070
2071 args[0] = promiseForMessage;
2072 message = j$.Expectation.finalizeMessage(self.util, name, self.isNot, args, result);
2073
2074 self.addExpectationResult(result.pass, {
2075 matcherName: name,
2076 passed: result.pass,
2077 message: message,
2078 error: undefined,
2079 errorForStack: errorForStack,
2080 actual: self.actual
2081 });
2082 });
2083 };
2084 }
2085
2086 /**
2087 * Expect a promise to be resolved.
2088 * @function
2089 * @async
2090 * @name async-matchers#toBeResolved
2091 * @example
2092 * await expectAsync(aPromise).toBeResolved();
2093 * @example
2094 * return expectAsync(aPromise).toBeResolved();
2095 */
2096 AsyncExpectation.prototype.toBeResolved = function(actual) {
2097 return actual.then(
2098 function() { return {pass: true}; },
2099 function() { return {pass: false}; }
2100 );
2101 };
2102
2103 /**
2104 * Expect a promise to be rejected.
2105 * @function
2106 * @async
2107 * @name async-matchers#toBeRejected
2108 * @example
2109 * await expectAsync(aPromise).toBeRejected();
2110 * @example
2111 * return expectAsync(aPromise).toBeRejected();
2112 */
2113 AsyncExpectation.prototype.toBeRejected = function(actual) {
2114 return actual.then(
2115 function() { return {pass: false}; },
2116 function() { return {pass: true}; }
2117 );
2118 };
2119
2120 /**
2121 * Expect a promise to be resolved to a value equal to the expected, using deep equality comparison.
2122 * @function
2123 * @async
2124 * @name async-matchers#toBeResolvedTo
2125 * @param {Object} expected - Value that the promise is expected to resolve to
2126 * @example
2127 * await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
2128 * @example
2129 * return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
2130 */
2131 AsyncExpectation.prototype.toBeResolvedTo = function(actualPromise, expectedValue) {
2132 var self = this;
2133
2134 function prefix(passed) {
2135 return 'Expected a promise ' +
2136 (passed ? 'not ' : '') +
2137 'to be resolved to ' + j$.pp(expectedValue);
2138 }
2139
2140 return actualPromise.then(
2141 function(actualValue) {
2142 if (self.util.equals(actualValue, expectedValue, self.customEqualityTesters)) {
2143 return {
2144 pass: true,
2145 message: prefix(true) + '.'
2146 };
2147 } else {
2148 return {
2149 pass: false,
2150 message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
2151 };
2152 }
2153 },
2154 function() {
2155 return {
2156 pass: false,
2157 message: prefix(false) + ' but it was rejected.'
2158 };
2159 }
2160 );
2161 };
2162
2163
2164 AsyncExpectation.factory = function(options) {
2165 var expect = new AsyncExpectation(options);
2166
2167 options = j$.util.clone(options);
2168 options.isNot = true;
2169 expect.not = new AsyncExpectation(options);
2170
2171 return expect;
2172 };
2173
2174
2175 return AsyncExpectation;
2176};
2177
2178getJasmineRequireObj().CallTracker = function(j$) {
2179
2180 /**
2181 * @namespace Spy#calls
2182 */
2183 function CallTracker() {
2184 var calls = [];
2185 var opts = {};
2186
2187 this.track = function(context) {
2188 if(opts.cloneArgs) {
2189 context.args = j$.util.cloneArgs(context.args);
2190 }
2191 calls.push(context);
2192 };
2193
2194 /**
2195 * Check whether this spy has been invoked.
2196 * @name Spy#calls#any
2197 * @function
2198 * @return {Boolean}
2199 */
2200 this.any = function() {
2201 return !!calls.length;
2202 };
2203
2204 /**
2205 * Get the number of invocations of this spy.
2206 * @name Spy#calls#count
2207 * @function
2208 * @return {Integer}
2209 */
2210 this.count = function() {
2211 return calls.length;
2212 };
2213
2214 /**
2215 * Get the arguments that were passed to a specific invocation of this spy.
2216 * @name Spy#calls#argsFor
2217 * @function
2218 * @param {Integer} index The 0-based invocation index.
2219 * @return {Array}
2220 */
2221 this.argsFor = function(index) {
2222 var call = calls[index];
2223 return call ? call.args : [];
2224 };
2225
2226 /**
2227 * Get the raw calls array for this spy.
2228 * @name Spy#calls#all
2229 * @function
2230 * @return {Spy.callData[]}
2231 */
2232 this.all = function() {
2233 return calls;
2234 };
2235
2236 /**
2237 * Get all of the arguments for each invocation of this spy in the order they were received.
2238 * @name Spy#calls#allArgs
2239 * @function
2240 * @return {Array}
2241 */
2242 this.allArgs = function() {
2243 var callArgs = [];
2244 for(var i = 0; i < calls.length; i++){
2245 callArgs.push(calls[i].args);
2246 }
2247
2248 return callArgs;
2249 };
2250
2251 /**
2252 * Get the first invocation of this spy.
2253 * @name Spy#calls#first
2254 * @function
2255 * @return {ObjecSpy.callData}
2256 */
2257 this.first = function() {
2258 return calls[0];
2259 };
2260
2261 /**
2262 * Get the most recent invocation of this spy.
2263 * @name Spy#calls#mostRecent
2264 * @function
2265 * @return {ObjecSpy.callData}
2266 */
2267 this.mostRecent = function() {
2268 return calls[calls.length - 1];
2269 };
2270
2271 /**
2272 * Reset this spy as if it has never been called.
2273 * @name Spy#calls#reset
2274 * @function
2275 */
2276 this.reset = function() {
2277 calls = [];
2278 };
2279
2280 /**
2281 * Set this spy to do a shallow clone of arguments passed to each invocation.
2282 * @name Spy#calls#saveArgumentsByValue
2283 * @function
2284 */
2285 this.saveArgumentsByValue = function() {
2286 opts.cloneArgs = true;
2287 };
2288
2289 }
2290
2291 return CallTracker;
2292};
2293
2294getJasmineRequireObj().clearStack = function(j$) {
2295 var maxInlineCallCount = 10;
2296
2297 function messageChannelImpl(global, setTimeout) {
2298 var channel = new global.MessageChannel(),
2299 head = {},
2300 tail = head;
2301
2302 var taskRunning = false;
2303 channel.port1.onmessage = function() {
2304 head = head.next;
2305 var task = head.task;
2306 delete head.task;
2307
2308 if (taskRunning) {
2309 global.setTimeout(task, 0);
2310 } else {
2311 try {
2312 taskRunning = true;
2313 task();
2314 } finally {
2315 taskRunning = false;
2316 }
2317 }
2318 };
2319
2320 var currentCallCount = 0;
2321 return function clearStack(fn) {
2322 currentCallCount++;
2323
2324 if (currentCallCount < maxInlineCallCount) {
2325 tail = tail.next = { task: fn };
2326 channel.port2.postMessage(0);
2327 } else {
2328 currentCallCount = 0;
2329 setTimeout(fn);
2330 }
2331 };
2332 }
2333
2334 function getClearStack(global) {
2335 var currentCallCount = 0;
2336 var realSetTimeout = global.setTimeout;
2337 var setTimeoutImpl = function clearStack(fn) {
2338 Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
2339 };
2340
2341 if (j$.isFunction_(global.setImmediate)) {
2342 var realSetImmediate = global.setImmediate;
2343 return function(fn) {
2344 currentCallCount++;
2345
2346 if (currentCallCount < maxInlineCallCount) {
2347 realSetImmediate(fn);
2348 } else {
2349 currentCallCount = 0;
2350
2351 setTimeoutImpl(fn);
2352 }
2353 };
2354 } else if (!j$.util.isUndefined(global.MessageChannel)) {
2355 return messageChannelImpl(global, setTimeoutImpl);
2356 } else {
2357 return setTimeoutImpl;
2358 }
2359 }
2360
2361 return getClearStack;
2362};
2363
2364getJasmineRequireObj().Clock = function() {
2365
2366 /* global process */
2367 var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
2368
2369 /**
2370 * _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
2371 * @class Clock
2372 * @classdesc Jasmine's mock clock is used when testing time dependent code.
2373 */
2374 function Clock(global, delayedFunctionSchedulerFactory, mockDate) {
2375 var self = this,
2376 realTimingFunctions = {
2377 setTimeout: global.setTimeout,
2378 clearTimeout: global.clearTimeout,
2379 setInterval: global.setInterval,
2380 clearInterval: global.clearInterval
2381 },
2382 fakeTimingFunctions = {
2383 setTimeout: setTimeout,
2384 clearTimeout: clearTimeout,
2385 setInterval: setInterval,
2386 clearInterval: clearInterval
2387 },
2388 installed = false,
2389 delayedFunctionScheduler,
2390 timer;
2391
2392 self.FakeTimeout = FakeTimeout;
2393
2394 /**
2395 * Install the mock clock over the built-in methods.
2396 * @name Clock#install
2397 * @function
2398 * @return {Clock}
2399 */
2400 self.install = function() {
2401 if(!originalTimingFunctionsIntact()) {
2402 throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
2403 }
2404 replace(global, fakeTimingFunctions);
2405 timer = fakeTimingFunctions;
2406 delayedFunctionScheduler = delayedFunctionSchedulerFactory();
2407 installed = true;
2408
2409 return self;
2410 };
2411
2412 /**
2413 * Uninstall the mock clock, returning the built-in methods to their places.
2414 * @name Clock#uninstall
2415 * @function
2416 */
2417 self.uninstall = function() {
2418 delayedFunctionScheduler = null;
2419 mockDate.uninstall();
2420 replace(global, realTimingFunctions);
2421
2422 timer = realTimingFunctions;
2423 installed = false;
2424 };
2425
2426 /**
2427 * Execute a function with a mocked Clock
2428 *
2429 * The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
2430 * @name Clock#withMock
2431 * @function
2432 * @param {closure} Function The function to be called.
2433 */
2434 self.withMock = function(closure) {
2435 this.install();
2436 try {
2437 closure();
2438 } finally {
2439 this.uninstall();
2440 }
2441 };
2442
2443 /**
2444 * Instruct the installed Clock to also mock the date returned by `new Date()`
2445 * @name Clock#mockDate
2446 * @function
2447 * @param {Date} [initialDate=now] The `Date` to provide.
2448 */
2449 self.mockDate = function(initialDate) {
2450 mockDate.install(initialDate);
2451 };
2452
2453 self.setTimeout = function(fn, delay, params) {
2454 return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
2455 };
2456
2457 self.setInterval = function(fn, delay, params) {
2458 return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
2459 };
2460
2461 self.clearTimeout = function(id) {
2462 return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
2463 };
2464
2465 self.clearInterval = function(id) {
2466 return Function.prototype.call.apply(timer.clearInterval, [global, id]);
2467 };
2468
2469 /**
2470 * Tick the Clock forward, running any enqueued timeouts along the way
2471 * @name Clock#tick
2472 * @function
2473 * @param {int} millis The number of milliseconds to tick.
2474 */
2475 self.tick = function(millis) {
2476 if (installed) {
2477 delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
2478 } else {
2479 throw new Error('Mock clock is not installed, use jasmine.clock().install()');
2480 }
2481 };
2482
2483 return self;
2484
2485 function originalTimingFunctionsIntact() {
2486 return global.setTimeout === realTimingFunctions.setTimeout &&
2487 global.clearTimeout === realTimingFunctions.clearTimeout &&
2488 global.setInterval === realTimingFunctions.setInterval &&
2489 global.clearInterval === realTimingFunctions.clearInterval;
2490 }
2491
2492 function replace(dest, source) {
2493 for (var prop in source) {
2494 dest[prop] = source[prop];
2495 }
2496 }
2497
2498 function setTimeout(fn, delay) {
2499 if (!NODE_JS) {
2500 return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
2501 }
2502
2503 var timeout = new FakeTimeout();
2504
2505 delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2), false, timeout);
2506
2507 return timeout;
2508 }
2509
2510 function clearTimeout(id) {
2511 return delayedFunctionScheduler.removeFunctionWithId(id);
2512 }
2513
2514 function setInterval(fn, interval) {
2515 if (!NODE_JS) {
2516 return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
2517 }
2518
2519 var timeout = new FakeTimeout();
2520
2521 delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true, timeout);
2522
2523 return timeout;
2524 }
2525
2526 function clearInterval(id) {
2527 return delayedFunctionScheduler.removeFunctionWithId(id);
2528 }
2529
2530 function argSlice(argsObj, n) {
2531 return Array.prototype.slice.call(argsObj, n);
2532 }
2533 }
2534
2535 /**
2536 * Mocks Node.js Timeout class
2537 */
2538 function FakeTimeout() {}
2539
2540 FakeTimeout.prototype.ref = function () {
2541 return this;
2542 };
2543
2544 FakeTimeout.prototype.unref = function () {
2545 return this;
2546 };
2547
2548 return Clock;
2549};
2550
2551getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
2552 function DelayedFunctionScheduler() {
2553 var self = this;
2554 var scheduledLookup = [];
2555 var scheduledFunctions = {};
2556 var currentTime = 0;
2557 var delayedFnCount = 0;
2558 var deletedKeys = [];
2559
2560 self.tick = function(millis, tickDate) {
2561 millis = millis || 0;
2562 var endTime = currentTime + millis;
2563
2564 runScheduledFunctions(endTime, tickDate);
2565 currentTime = endTime;
2566 };
2567
2568 self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
2569 var f;
2570 if (typeof(funcToCall) === 'string') {
2571 /* jshint evil: true */
2572 f = function() { return eval(funcToCall); };
2573 /* jshint evil: false */
2574 } else {
2575 f = funcToCall;
2576 }
2577
2578 millis = millis || 0;
2579 timeoutKey = timeoutKey || ++delayedFnCount;
2580 runAtMillis = runAtMillis || (currentTime + millis);
2581
2582 var funcToSchedule = {
2583 runAtMillis: runAtMillis,
2584 funcToCall: f,
2585 recurring: recurring,
2586 params: params,
2587 timeoutKey: timeoutKey,
2588 millis: millis
2589 };
2590
2591 if (runAtMillis in scheduledFunctions) {
2592 scheduledFunctions[runAtMillis].push(funcToSchedule);
2593 } else {
2594 scheduledFunctions[runAtMillis] = [funcToSchedule];
2595 scheduledLookup.push(runAtMillis);
2596 scheduledLookup.sort(function (a, b) {
2597 return a - b;
2598 });
2599 }
2600
2601 return timeoutKey;
2602 };
2603
2604 self.removeFunctionWithId = function(timeoutKey) {
2605 deletedKeys.push(timeoutKey);
2606
2607 for (var runAtMillis in scheduledFunctions) {
2608 var funcs = scheduledFunctions[runAtMillis];
2609 var i = indexOfFirstToPass(funcs, function (func) {
2610 return func.timeoutKey === timeoutKey;
2611 });
2612
2613 if (i > -1) {
2614 if (funcs.length === 1) {
2615 delete scheduledFunctions[runAtMillis];
2616 deleteFromLookup(runAtMillis);
2617 } else {
2618 funcs.splice(i, 1);
2619 }
2620
2621 // intervals get rescheduled when executed, so there's never more
2622 // than a single scheduled function with a given timeoutKey
2623 break;
2624 }
2625 }
2626 };
2627
2628 return self;
2629
2630 function indexOfFirstToPass(array, testFn) {
2631 var index = -1;
2632
2633 for (var i = 0; i < array.length; ++i) {
2634 if (testFn(array[i])) {
2635 index = i;
2636 break;
2637 }
2638 }
2639
2640 return index;
2641 }
2642
2643 function deleteFromLookup(key) {
2644 var value = Number(key);
2645 var i = indexOfFirstToPass(scheduledLookup, function (millis) {
2646 return millis === value;
2647 });
2648
2649 if (i > -1) {
2650 scheduledLookup.splice(i, 1);
2651 }
2652 }
2653
2654 function reschedule(scheduledFn) {
2655 self.scheduleFunction(scheduledFn.funcToCall,
2656 scheduledFn.millis,
2657 scheduledFn.params,
2658 true,
2659 scheduledFn.timeoutKey,
2660 scheduledFn.runAtMillis + scheduledFn.millis);
2661 }
2662
2663 function forEachFunction(funcsToRun, callback) {
2664 for (var i = 0; i < funcsToRun.length; ++i) {
2665 callback(funcsToRun[i]);
2666 }
2667 }
2668
2669 function runScheduledFunctions(endTime, tickDate) {
2670 tickDate = tickDate || function() {};
2671 if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
2672 tickDate(endTime - currentTime);
2673 return;
2674 }
2675
2676 do {
2677 deletedKeys = [];
2678 var newCurrentTime = scheduledLookup.shift();
2679 tickDate(newCurrentTime - currentTime);
2680
2681 currentTime = newCurrentTime;
2682
2683 var funcsToRun = scheduledFunctions[currentTime];
2684
2685 delete scheduledFunctions[currentTime];
2686
2687 forEachFunction(funcsToRun, function(funcToRun) {
2688 if (funcToRun.recurring) {
2689 reschedule(funcToRun);
2690 }
2691 });
2692
2693 forEachFunction(funcsToRun, function(funcToRun) {
2694 if (j$.util.arrayContains(deletedKeys, funcToRun.timeoutKey)) {
2695 // skip a timeoutKey deleted whilst we were running
2696 return;
2697 }
2698 funcToRun.funcToCall.apply(null, funcToRun.params || []);
2699 });
2700 deletedKeys = [];
2701 } while (scheduledLookup.length > 0 &&
2702 // checking first if we're out of time prevents setTimeout(0)
2703 // scheduled in a funcToRun from forcing an extra iteration
2704 currentTime !== endTime &&
2705 scheduledLookup[0] <= endTime);
2706
2707 // ran out of functions to call, but still time left on the clock
2708 if (currentTime !== endTime) {
2709 tickDate(endTime - currentTime);
2710 }
2711 }
2712 }
2713
2714 return DelayedFunctionScheduler;
2715};
2716
2717getJasmineRequireObj().errors = function() {
2718 function ExpectationFailed() {}
2719
2720 ExpectationFailed.prototype = new Error();
2721 ExpectationFailed.prototype.constructor = ExpectationFailed;
2722
2723 return {
2724 ExpectationFailed: ExpectationFailed
2725 };
2726};
2727getJasmineRequireObj().ExceptionFormatter = function(j$) {
2728
2729 function ExceptionFormatter(options) {
2730 var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
2731 this.message = function(error) {
2732 var message = '';
2733
2734 if (error.name && error.message) {
2735 message += error.name + ': ' + error.message;
2736 } else {
2737 message += error.toString() + ' thrown';
2738 }
2739
2740 if (error.fileName || error.sourceURL) {
2741 message += ' in ' + (error.fileName || error.sourceURL);
2742 }
2743
2744 if (error.line || error.lineNumber) {
2745 message += ' (line ' + (error.line || error.lineNumber) + ')';
2746 }
2747
2748 return message;
2749 };
2750
2751 this.stack = function(error) {
2752 if (!error || !error.stack) {
2753 return null;
2754 }
2755
2756 var stackTrace = new j$.StackTrace(error);
2757 var lines = filterJasmine(stackTrace);
2758 var result = '';
2759
2760 if (stackTrace.message) {
2761 lines.unshift(stackTrace.message);
2762 }
2763
2764 result += formatProperties(error);
2765 result += lines.join('\n');
2766
2767 return result;
2768 };
2769
2770 function filterJasmine(stackTrace) {
2771 var result = [],
2772 jasmineMarker = stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
2773
2774 stackTrace.frames.forEach(function(frame) {
2775 if (frame.file && frame.file !== jasmineFile) {
2776 result.push(frame.raw);
2777 } else if (result[result.length - 1] !== jasmineMarker) {
2778 result.push(jasmineMarker);
2779 }
2780 });
2781
2782 return result;
2783 }
2784
2785 function formatProperties(error) {
2786 if (!(error instanceof Object)) {
2787 return;
2788 }
2789
2790 var ignored = ['name', 'message', 'stack', 'fileName', 'sourceURL', 'line', 'lineNumber', 'column', 'description'];
2791 var result = {};
2792 var empty = true;
2793
2794 for (var prop in error) {
2795 if (j$.util.arrayContains(ignored, prop)) {
2796 continue;
2797 }
2798 result[prop] = error[prop];
2799 empty = false;
2800 }
2801
2802 if (!empty) {
2803 return 'error properties: ' + j$.pp(result) + '\n';
2804 }
2805
2806 return '';
2807 }
2808 }
2809
2810 return ExceptionFormatter;
2811};
2812
2813getJasmineRequireObj().Expectation = function() {
2814
2815 /**
2816 * Matchers that come with Jasmine out of the box.
2817 * @namespace matchers
2818 */
2819 function Expectation(options) {
2820 this.util = options.util || { buildFailureMessage: function() {} };
2821 this.customEqualityTesters = options.customEqualityTesters || [];
2822 this.actual = options.actual;
2823 this.addExpectationResult = options.addExpectationResult || function(){};
2824 this.isNot = options.isNot;
2825
2826 var customMatchers = options.customMatchers || {};
2827 for (var matcherName in customMatchers) {
2828 this[matcherName] = Expectation.prototype.wrapCompare(matcherName, customMatchers[matcherName]);
2829 }
2830 }
2831
2832 Expectation.prototype.wrapCompare = function(name, matcherFactory) {
2833 return function() {
2834 var args = Array.prototype.slice.call(arguments, 0),
2835 expected = args.slice(0),
2836 message;
2837
2838 args.unshift(this.actual);
2839
2840 var matcher = matcherFactory(this.util, this.customEqualityTesters),
2841 matcherCompare = matcher.compare;
2842
2843 function defaultNegativeCompare() {
2844 var result = matcher.compare.apply(null, args);
2845 result.pass = !result.pass;
2846 return result;
2847 }
2848
2849 if (this.isNot) {
2850 matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
2851 }
2852
2853 var result = matcherCompare.apply(null, args);
2854 message = Expectation.finalizeMessage(this.util, name, this.isNot, args, result);
2855
2856 if (expected.length == 1) {
2857 expected = expected[0];
2858 }
2859
2860 // TODO: how many of these params are needed?
2861 this.addExpectationResult(
2862 result.pass,
2863 {
2864 matcherName: name,
2865 passed: result.pass,
2866 message: message,
2867 error: result.error,
2868 actual: this.actual,
2869 expected: expected // TODO: this may need to be arrayified/sliced
2870 }
2871 );
2872 };
2873 };
2874
2875 Expectation.finalizeMessage = function(util, name, isNot, args, result) {
2876 if (result.pass) {
2877 return '';
2878 } else if (result.message) {
2879 if (Object.prototype.toString.apply(result.message) === '[object Function]') {
2880 return result.message();
2881 } else {
2882 return result.message;
2883 }
2884 } else {
2885 args = args.slice();
2886 args.unshift(isNot);
2887 args.unshift(name);
2888 return util.buildFailureMessage.apply(null, args);
2889 }
2890 };
2891
2892 Expectation.addCoreMatchers = function(matchers) {
2893 var prototype = Expectation.prototype;
2894 for (var matcherName in matchers) {
2895 var matcher = matchers[matcherName];
2896 prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
2897 }
2898 };
2899
2900 Expectation.Factory = function(options) {
2901 options = options || {};
2902
2903 var expect = new Expectation(options);
2904
2905 // TODO: this would be nice as its own Object - NegativeExpectation
2906 // TODO: copy instead of mutate options
2907 options.isNot = true;
2908 expect.not = new Expectation(options);
2909
2910 return expect;
2911 };
2912
2913 return Expectation;
2914};
2915
2916//TODO: expectation result may make more sense as a presentation of an expectation.
2917getJasmineRequireObj().buildExpectationResult = function() {
2918 function buildExpectationResult(options) {
2919 var messageFormatter = options.messageFormatter || function() {},
2920 stackFormatter = options.stackFormatter || function() {};
2921
2922 /**
2923 * @typedef Expectation
2924 * @property {String} matcherName - The name of the matcher that was executed for this expectation.
2925 * @property {String} message - The failure message for the expectation.
2926 * @property {String} stack - The stack trace for the failure if available.
2927 * @property {Boolean} passed - Whether the expectation passed or failed.
2928 * @property {Object} expected - If the expectation failed, what was the expected value.
2929 * @property {Object} actual - If the expectation failed, what actual value was produced.
2930 */
2931 var result = {
2932 matcherName: options.matcherName,
2933 message: message(),
2934 stack: stack(),
2935 passed: options.passed
2936 };
2937
2938 if(!result.passed) {
2939 result.expected = options.expected;
2940 result.actual = options.actual;
2941 }
2942
2943 return result;
2944
2945 function message() {
2946 if (options.passed) {
2947 return 'Passed.';
2948 } else if (options.message) {
2949 return options.message;
2950 } else if (options.error) {
2951 return messageFormatter(options.error);
2952 }
2953 return '';
2954 }
2955
2956 function stack() {
2957 if (options.passed) {
2958 return '';
2959 }
2960
2961 var error = options.error;
2962 if (!error) {
2963 if (options.errorForStack) {
2964 error = options.errorForStack;
2965 } else if (options.stack) {
2966 error = options;
2967 } else {
2968 try {
2969 throw new Error(message());
2970 } catch (e) {
2971 error = e;
2972 }
2973 }
2974 }
2975 return stackFormatter(error);
2976 }
2977 }
2978
2979 return buildExpectationResult;
2980};
2981
2982getJasmineRequireObj().formatErrorMsg = function() {
2983 function generateErrorMsg(domain, usage) {
2984 var usageDefinition = usage ? '\nUsage: ' + usage : '';
2985
2986 return function errorMsg(msg) {
2987 return domain + ' : ' + msg + usageDefinition;
2988 };
2989 }
2990
2991 return generateErrorMsg;
2992};
2993
2994getJasmineRequireObj().GlobalErrors = function(j$) {
2995 function GlobalErrors(global) {
2996 var handlers = [];
2997 global = global || j$.getGlobal();
2998
2999 var onerror = function onerror() {
3000 var handler = handlers[handlers.length - 1];
3001
3002 if (handler) {
3003 handler.apply(null, Array.prototype.slice.call(arguments, 0));
3004 } else {
3005 throw arguments[0];
3006 }
3007 };
3008
3009 this.originalHandlers = {};
3010 this.installOne_ = function installOne_(errorType) {
3011 this.originalHandlers[errorType] = global.process.listeners(errorType);
3012 global.process.removeAllListeners(errorType);
3013 global.process.on(errorType, onerror);
3014
3015 this.uninstall = function uninstall() {
3016 var errorTypes = Object.keys(this.originalHandlers);
3017 for (var iType = 0; iType < errorTypes.length; iType++) {
3018 var errorType = errorTypes[iType];
3019 global.process.removeListener(errorType, onerror);
3020 for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
3021 global.process.on(errorType, this.originalHandlers[errorType][i]);
3022 }
3023 delete this.originalHandlers[errorType];
3024 }
3025 };
3026 };
3027
3028 this.install = function install() {
3029 if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
3030 this.installOne_('uncaughtException');
3031 this.installOne_('unhandledRejection');
3032 } else {
3033 var originalHandler = global.onerror;
3034 global.onerror = onerror;
3035
3036 this.uninstall = function uninstall() {
3037 global.onerror = originalHandler;
3038 };
3039 }
3040 };
3041
3042 this.pushListener = function pushListener(listener) {
3043 handlers.push(listener);
3044 };
3045
3046 this.popListener = function popListener() {
3047 handlers.pop();
3048 };
3049 }
3050
3051 return GlobalErrors;
3052};
3053
3054getJasmineRequireObj().DiffBuilder = function(j$) {
3055 return function DiffBuilder() {
3056 var path = new j$.ObjectPath(),
3057 mismatches = [];
3058
3059 return {
3060 record: function (actual, expected, formatter) {
3061 formatter = formatter || defaultFormatter;
3062 mismatches.push(formatter(actual, expected, path));
3063 },
3064
3065 getMessage: function () {
3066 return mismatches.join('\n');
3067 },
3068
3069 withPath: function (pathComponent, block) {
3070 var oldPath = path;
3071 path = path.add(pathComponent);
3072 block();
3073 path = oldPath;
3074 }
3075 };
3076
3077 function defaultFormatter (actual, expected, path) {
3078 return 'Expected ' +
3079 path + (path.depth() ? ' = ' : '') +
3080 j$.pp(actual) +
3081 ' to equal ' +
3082 j$.pp(expected) +
3083 '.';
3084 }
3085 };
3086};
3087
3088getJasmineRequireObj().matchersUtil = function(j$) {
3089 // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
3090
3091 return {
3092 equals: equals,
3093
3094 contains: function(haystack, needle, customTesters) {
3095 customTesters = customTesters || [];
3096
3097 if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
3098 return haystack.has(needle);
3099 }
3100
3101 if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
3102 (!!haystack && !haystack.indexOf))
3103 {
3104 for (var i = 0; i < haystack.length; i++) {
3105 if (equals(haystack[i], needle, customTesters)) {
3106 return true;
3107 }
3108 }
3109 return false;
3110 }
3111
3112 return !!haystack && haystack.indexOf(needle) >= 0;
3113 },
3114
3115 buildFailureMessage: function() {
3116 var args = Array.prototype.slice.call(arguments, 0),
3117 matcherName = args[0],
3118 isNot = args[1],
3119 actual = args[2],
3120 expected = args.slice(3),
3121 englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
3122
3123 var message = 'Expected ' +
3124 j$.pp(actual) +
3125 (isNot ? ' not ' : ' ') +
3126 englishyPredicate;
3127
3128 if (expected.length > 0) {
3129 for (var i = 0; i < expected.length; i++) {
3130 if (i > 0) {
3131 message += ',';
3132 }
3133 message += ' ' + j$.pp(expected[i]);
3134 }
3135 }
3136
3137 return message + '.';
3138 }
3139 };
3140
3141 function isAsymmetric(obj) {
3142 return obj && j$.isA_('Function', obj.asymmetricMatch);
3143 }
3144
3145 function asymmetricMatch(a, b, customTesters, diffBuilder) {
3146 var asymmetricA = isAsymmetric(a),
3147 asymmetricB = isAsymmetric(b),
3148 result;
3149
3150 if (asymmetricA && asymmetricB) {
3151 return undefined;
3152 }
3153
3154 if (asymmetricA) {
3155 result = a.asymmetricMatch(b, customTesters);
3156 if (!result) {
3157 diffBuilder.record(a, b);
3158 }
3159 return result;
3160 }
3161
3162 if (asymmetricB) {
3163 result = b.asymmetricMatch(a, customTesters);
3164 if (!result) {
3165 diffBuilder.record(a, b);
3166 }
3167 return result;
3168 }
3169 }
3170
3171 function equals(a, b, customTesters, diffBuilder) {
3172 customTesters = customTesters || [];
3173 diffBuilder = diffBuilder || j$.NullDiffBuilder();
3174
3175 return eq(a, b, [], [], customTesters, diffBuilder);
3176 }
3177
3178 // Equality function lovingly adapted from isEqual in
3179 // [Underscore](http://underscorejs.org)
3180 function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
3181 var result = true, i;
3182
3183 var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
3184 if (!j$.util.isUndefined(asymmetricResult)) {
3185 return asymmetricResult;
3186 }
3187
3188 for (i = 0; i < customTesters.length; i++) {
3189 var customTesterResult = customTesters[i](a, b);
3190 if (!j$.util.isUndefined(customTesterResult)) {
3191 if (!customTesterResult) {
3192 diffBuilder.record(a, b);
3193 }
3194 return customTesterResult;
3195 }
3196 }
3197
3198 if (a instanceof Error && b instanceof Error) {
3199 result = a.message == b.message;
3200 if (!result) {
3201 diffBuilder.record(a, b);
3202 }
3203 return result;
3204 }
3205
3206 // Identical objects are equal. `0 === -0`, but they aren't identical.
3207 // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
3208 if (a === b) {
3209 result = a !== 0 || 1 / a == 1 / b;
3210 if (!result) {
3211 diffBuilder.record(a, b);
3212 }
3213 return result;
3214 }
3215 // A strict comparison is necessary because `null == undefined`.
3216 if (a === null || b === null) {
3217 result = a === b;
3218 if (!result) {
3219 diffBuilder.record(a, b);
3220 }
3221 return result;
3222 }
3223 var className = Object.prototype.toString.call(a);
3224 if (className != Object.prototype.toString.call(b)) {
3225 diffBuilder.record(a, b);
3226 return false;
3227 }
3228 switch (className) {
3229 // Strings, numbers, dates, and booleans are compared by value.
3230 case '[object String]':
3231 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
3232 // equivalent to `new String("5")`.
3233 result = a == String(b);
3234 if (!result) {
3235 diffBuilder.record(a, b);
3236 }
3237 return result;
3238 case '[object Number]':
3239 // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
3240 // other numeric values.
3241 result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
3242 if (!result) {
3243 diffBuilder.record(a, b);
3244 }
3245 return result;
3246 case '[object Date]':
3247 case '[object Boolean]':
3248 // Coerce dates and booleans to numeric primitive values. Dates are compared by their
3249 // millisecond representations. Note that invalid dates with millisecond representations
3250 // of `NaN` are not equivalent.
3251 result = +a == +b;
3252 if (!result) {
3253 diffBuilder.record(a, b);
3254 }
3255 return result;
3256 // RegExps are compared by their source patterns and flags.
3257 case '[object RegExp]':
3258 return a.source == b.source &&
3259 a.global == b.global &&
3260 a.multiline == b.multiline &&
3261 a.ignoreCase == b.ignoreCase;
3262 }
3263 if (typeof a != 'object' || typeof b != 'object') {
3264 diffBuilder.record(a, b);
3265 return false;
3266 }
3267
3268 var aIsDomNode = j$.isDomNode(a);
3269 var bIsDomNode = j$.isDomNode(b);
3270 if (aIsDomNode && bIsDomNode) {
3271 // At first try to use DOM3 method isEqualNode
3272 result = a.isEqualNode(b);
3273 if (!result) {
3274 diffBuilder.record(a, b);
3275 }
3276 return result;
3277 }
3278 if (aIsDomNode || bIsDomNode) {
3279 diffBuilder.record(a, b);
3280 return false;
3281 }
3282
3283 var aIsPromise = j$.isPromise(a);
3284 var bIsPromise = j$.isPromise(b);
3285 if (aIsPromise && bIsPromise) {
3286 return a === b;
3287 }
3288
3289 // Assume equality for cyclic structures. The algorithm for detecting cyclic
3290 // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
3291 var length = aStack.length;
3292 while (length--) {
3293 // Linear search. Performance is inversely proportional to the number of
3294 // unique nested structures.
3295 if (aStack[length] == a) { return bStack[length] == b; }
3296 }
3297 // Add the first object to the stack of traversed objects.
3298 aStack.push(a);
3299 bStack.push(b);
3300 var size = 0;
3301 // Recursively compare objects and arrays.
3302 // Compare array lengths to determine if a deep comparison is necessary.
3303 if (className == '[object Array]') {
3304 var aLength = a.length;
3305 var bLength = b.length;
3306
3307 diffBuilder.withPath('length', function() {
3308 if (aLength !== bLength) {
3309 diffBuilder.record(aLength, bLength);
3310 result = false;
3311 }
3312 });
3313
3314 for (i = 0; i < aLength || i < bLength; i++) {
3315 var formatter = false;
3316 diffBuilder.withPath(i, function() {
3317 if (i >= bLength) {
3318 diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
3319 result = false;
3320 } else {
3321 result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
3322 }
3323 });
3324 }
3325 if (!result) {
3326 return false;
3327 }
3328 } else if (j$.isMap(a) && j$.isMap(b)) {
3329 if (a.size != b.size) {
3330 diffBuilder.record(a, b);
3331 return false;
3332 }
3333
3334 var keysA = [];
3335 var keysB = [];
3336 a.forEach( function( valueA, keyA ) {
3337 keysA.push( keyA );
3338 });
3339 b.forEach( function( valueB, keyB ) {
3340 keysB.push( keyB );
3341 });
3342
3343 // For both sets of keys, check they map to equal values in both maps.
3344 // Keep track of corresponding keys (in insertion order) in order to handle asymmetric obj keys.
3345 var mapKeys = [keysA, keysB];
3346 var cmpKeys = [keysB, keysA];
3347 var mapIter, mapKey, mapValueA, mapValueB;
3348 var cmpIter, cmpKey;
3349 for (i = 0; result && i < mapKeys.length; i++) {
3350 mapIter = mapKeys[i];
3351 cmpIter = cmpKeys[i];
3352
3353 for (var j = 0; result && j < mapIter.length; j++) {
3354 mapKey = mapIter[j];
3355 cmpKey = cmpIter[j];
3356 mapValueA = a.get(mapKey);
3357
3358 // Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
3359 // otherwise explicitly look up the mapKey in the other Map since we want keys with unique
3360 // obj identity (that are otherwise equal) to not match.
3361 if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
3362 eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
3363 mapValueB = b.get(cmpKey);
3364 } else {
3365 mapValueB = b.get(mapKey);
3366 }
3367 result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
3368 }
3369 }
3370
3371 if (!result) {
3372 diffBuilder.record(a, b);
3373 return false;
3374 }
3375 } else if (j$.isSet(a) && j$.isSet(b)) {
3376 if (a.size != b.size) {
3377 diffBuilder.record(a, b);
3378 return false;
3379 }
3380
3381 var valuesA = [];
3382 a.forEach( function( valueA ) {
3383 valuesA.push( valueA );
3384 });
3385 var valuesB = [];
3386 b.forEach( function( valueB ) {
3387 valuesB.push( valueB );
3388 });
3389
3390 // For both sets, check they are all contained in the other set
3391 var setPairs = [[valuesA, valuesB], [valuesB, valuesA]];
3392 var stackPairs = [[aStack, bStack], [bStack, aStack]];
3393 var baseValues, baseValue, baseStack;
3394 var otherValues, otherValue, otherStack;
3395 var found;
3396 var prevStackSize;
3397 for (i = 0; result && i < setPairs.length; i++) {
3398 baseValues = setPairs[i][0];
3399 otherValues = setPairs[i][1];
3400 baseStack = stackPairs[i][0];
3401 otherStack = stackPairs[i][1];
3402 // For each value in the base set...
3403 for (var k = 0; result && k < baseValues.length; k++) {
3404 baseValue = baseValues[k];
3405 found = false;
3406 // ... test that it is present in the other set
3407 for (var l = 0; !found && l < otherValues.length; l++) {
3408 otherValue = otherValues[l];
3409 prevStackSize = baseStack.length;
3410 // compare by value equality
3411 found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
3412 if (!found && prevStackSize !== baseStack.length) {
3413 baseStack.splice(prevStackSize);
3414 otherStack.splice(prevStackSize);
3415 }
3416 }
3417 result = result && found;
3418 }
3419 }
3420
3421 if (!result) {
3422 diffBuilder.record(a, b);
3423 return false;
3424 }
3425 } else {
3426
3427 // Objects with different constructors are not equivalent, but `Object`s
3428 // or `Array`s from different frames are.
3429 var aCtor = a.constructor, bCtor = b.constructor;
3430 if (aCtor !== bCtor &&
3431 isFunction(aCtor) && isFunction(bCtor) &&
3432 a instanceof aCtor && b instanceof bCtor &&
3433 !(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
3434
3435 diffBuilder.record(a, b, constructorsAreDifferentFormatter);
3436 return false;
3437 }
3438 }
3439
3440 // Deep compare objects.
3441 var aKeys = keys(a, className == '[object Array]'), key;
3442 size = aKeys.length;
3443
3444 // Ensure that both objects contain the same number of properties before comparing deep equality.
3445 if (keys(b, className == '[object Array]').length !== size) {
3446 diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
3447 return false;
3448 }
3449
3450 for (i = 0; i < size; i++) {
3451 key = aKeys[i];
3452 // Deep compare each member
3453 if (!j$.util.has(b, key)) {
3454 diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
3455 result = false;
3456 continue;
3457 }
3458
3459 diffBuilder.withPath(key, function() {
3460 if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
3461 result = false;
3462 }
3463 });
3464 }
3465
3466 if (!result) {
3467 return false;
3468 }
3469
3470 // Remove the first object from the stack of traversed objects.
3471 aStack.pop();
3472 bStack.pop();
3473
3474 return result;
3475 }
3476
3477 function keys(obj, isArray) {
3478 var allKeys = Object.keys ? Object.keys(obj) :
3479 (function(o) {
3480 var keys = [];
3481 for (var key in o) {
3482 if (j$.util.has(o, key)) {
3483 keys.push(key);
3484 }
3485 }
3486 return keys;
3487 })(obj);
3488
3489 if (!isArray) {
3490 return allKeys;
3491 }
3492
3493 if (allKeys.length === 0) {
3494 return allKeys;
3495 }
3496
3497 var extraKeys = [];
3498 for (var i = 0; i < allKeys.length; i++) {
3499 if (!/^[0-9]+$/.test(allKeys[i])) {
3500 extraKeys.push(allKeys[i]);
3501 }
3502 }
3503
3504 return extraKeys;
3505 }
3506
3507 function has(obj, key) {
3508 return Object.prototype.hasOwnProperty.call(obj, key);
3509 }
3510
3511 function isFunction(obj) {
3512 return typeof obj === 'function';
3513 }
3514
3515 function objectKeysAreDifferentFormatter(actual, expected, path) {
3516 var missingProperties = j$.util.objectDifference(expected, actual),
3517 extraProperties = j$.util.objectDifference(actual, expected),
3518 missingPropertiesMessage = formatKeyValuePairs(missingProperties),
3519 extraPropertiesMessage = formatKeyValuePairs(extraProperties),
3520 messages = [];
3521
3522 if (!path.depth()) {
3523 path = 'object';
3524 }
3525
3526 if (missingPropertiesMessage.length) {
3527 messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
3528 }
3529
3530 if (extraPropertiesMessage.length) {
3531 messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
3532 }
3533
3534 return messages.join('\n');
3535 }
3536
3537 function constructorsAreDifferentFormatter(actual, expected, path) {
3538 if (!path.depth()) {
3539 path = 'object';
3540 }
3541
3542 return 'Expected ' +
3543 path + ' to be a kind of ' +
3544 j$.fnNameFor(expected.constructor) +
3545 ', but was ' + j$.pp(actual) + '.';
3546 }
3547
3548 function actualArrayIsLongerFormatter(actual, expected, path) {
3549 return 'Unexpected ' +
3550 path + (path.depth() ? ' = ' : '') +
3551 j$.pp(actual) +
3552 ' in array.';
3553 }
3554
3555 function formatKeyValuePairs(obj) {
3556 var formatted = '';
3557 for (var key in obj) {
3558 formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
3559 }
3560 return formatted;
3561 }
3562};
3563
3564getJasmineRequireObj().nothing = function() {
3565 /**
3566 * {@link expect} nothing explicitly.
3567 * @function
3568 * @name matchers#nothing
3569 * @example
3570 * expect().nothing();
3571 */
3572 function nothing() {
3573 return {
3574 compare: function() {
3575 return {
3576 pass: true
3577 };
3578 }
3579 };
3580 }
3581
3582 return nothing;
3583};
3584
3585getJasmineRequireObj().NullDiffBuilder = function(j$) {
3586 return function() {
3587 return {
3588 withPath: function(_, block) {
3589 block();
3590 },
3591 record: function() {}
3592 };
3593 };
3594};
3595
3596getJasmineRequireObj().ObjectPath = function(j$) {
3597 function ObjectPath(components) {
3598 this.components = components || [];
3599 }
3600
3601 ObjectPath.prototype.toString = function() {
3602 if (this.components.length) {
3603 return '$' + map(this.components, formatPropertyAccess).join('');
3604 } else {
3605 return '';
3606 }
3607 };
3608
3609 ObjectPath.prototype.add = function(component) {
3610 return new ObjectPath(this.components.concat([component]));
3611 };
3612
3613 ObjectPath.prototype.depth = function() {
3614 return this.components.length;
3615 };
3616
3617 function formatPropertyAccess(prop) {
3618 if (typeof prop === 'number') {
3619 return '[' + prop + ']';
3620 }
3621
3622 if (isValidIdentifier(prop)) {
3623 return '.' + prop;
3624 }
3625
3626 return '[\'' + prop + '\']';
3627 }
3628
3629 function map(array, fn) {
3630 var results = [];
3631 for (var i = 0; i < array.length; i++) {
3632 results.push(fn(array[i]));
3633 }
3634 return results;
3635 }
3636
3637 function isValidIdentifier(string) {
3638 return /^[A-Za-z\$_][A-Za-z0-9\$_]*$/.test(string);
3639 }
3640
3641 return ObjectPath;
3642};
3643
3644getJasmineRequireObj().toBe = function() {
3645 /**
3646 * {@link expect} the actual value to be `===` to the expected value.
3647 * @function
3648 * @name matchers#toBe
3649 * @param {Object} expected - The expected value to compare against.
3650 * @example
3651 * expect(thing).toBe(realThing);
3652 */
3653 function toBe() {
3654 return {
3655 compare: function(actual, expected) {
3656 return {
3657 pass: actual === expected
3658 };
3659 }
3660 };
3661 }
3662
3663 return toBe;
3664};
3665
3666getJasmineRequireObj().toBeCloseTo = function() {
3667 /**
3668 * {@link expect} the actual value to be within a specified precision of the expected value.
3669 * @function
3670 * @name matchers#toBeCloseTo
3671 * @param {Object} expected - The expected value to compare against.
3672 * @param {Number} [precision=2] - The number of decimal points to check.
3673 * @example
3674 * expect(number).toBeCloseTo(42.2, 3);
3675 */
3676 function toBeCloseTo() {
3677 return {
3678 compare: function(actual, expected, precision) {
3679 if (precision !== 0) {
3680 precision = precision || 2;
3681 }
3682
3683 if (expected === null || actual === null) {
3684 throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
3685 'expect(' + actual + ').toBeCloseTo(' + expected + ').'
3686 );
3687 }
3688
3689 var pow = Math.pow(10, precision + 1);
3690 var delta = Math.abs(expected - actual);
3691 var maxDelta = Math.pow(10, -precision) / 2;
3692
3693 return {
3694 pass: Math.round(delta * pow) / pow <= maxDelta
3695 };
3696 }
3697 };
3698 }
3699
3700 return toBeCloseTo;
3701};
3702
3703getJasmineRequireObj().toBeDefined = function() {
3704 /**
3705 * {@link expect} the actual value to be defined. (Not `undefined`)
3706 * @function
3707 * @name matchers#toBeDefined
3708 * @example
3709 * expect(result).toBeDefined();
3710 */
3711 function toBeDefined() {
3712 return {
3713 compare: function(actual) {
3714 return {
3715 pass: (void 0 !== actual)
3716 };
3717 }
3718 };
3719 }
3720
3721 return toBeDefined;
3722};
3723
3724getJasmineRequireObj().toBeFalsy = function() {
3725 /**
3726 * {@link expect} the actual value to be falsy
3727 * @function
3728 * @name matchers#toBeFalsy
3729 * @example
3730 * expect(result).toBeFalsy();
3731 */
3732 function toBeFalsy() {
3733 return {
3734 compare: function(actual) {
3735 return {
3736 pass: !!!actual
3737 };
3738 }
3739 };
3740 }
3741
3742 return toBeFalsy;
3743};
3744
3745getJasmineRequireObj().toBeGreaterThan = function() {
3746 /**
3747 * {@link expect} the actual value to be greater than the expected value.
3748 * @function
3749 * @name matchers#toBeGreaterThan
3750 * @param {Number} expected - The value to compare against.
3751 * @example
3752 * expect(result).toBeGreaterThan(3);
3753 */
3754 function toBeGreaterThan() {
3755 return {
3756 compare: function(actual, expected) {
3757 return {
3758 pass: actual > expected
3759 };
3760 }
3761 };
3762 }
3763
3764 return toBeGreaterThan;
3765};
3766
3767
3768getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
3769 /**
3770 * {@link expect} the actual value to be greater than or equal to the expected value.
3771 * @function
3772 * @name matchers#toBeGreaterThanOrEqual
3773 * @param {Number} expected - The expected value to compare against.
3774 * @example
3775 * expect(result).toBeGreaterThanOrEqual(25);
3776 */
3777 function toBeGreaterThanOrEqual() {
3778 return {
3779 compare: function(actual, expected) {
3780 return {
3781 pass: actual >= expected
3782 };
3783 }
3784 };
3785 }
3786
3787 return toBeGreaterThanOrEqual;
3788};
3789
3790getJasmineRequireObj().toBeLessThan = function() {
3791 /**
3792 * {@link expect} the actual value to be less than the expected value.
3793 * @function
3794 * @name matchers#toBeLessThan
3795 * @param {Number} expected - The expected value to compare against.
3796 * @example
3797 * expect(result).toBeLessThan(0);
3798 */
3799 function toBeLessThan() {
3800 return {
3801
3802 compare: function(actual, expected) {
3803 return {
3804 pass: actual < expected
3805 };
3806 }
3807 };
3808 }
3809
3810 return toBeLessThan;
3811};
3812
3813getJasmineRequireObj().toBeLessThanOrEqual = function() {
3814 /**
3815 * {@link expect} the actual value to be less than or equal to the expected value.
3816 * @function
3817 * @name matchers#toBeLessThanOrEqual
3818 * @param {Number} expected - The expected value to compare against.
3819 * @example
3820 * expect(result).toBeLessThanOrEqual(123);
3821 */
3822 function toBeLessThanOrEqual() {
3823 return {
3824
3825 compare: function(actual, expected) {
3826 return {
3827 pass: actual <= expected
3828 };
3829 }
3830 };
3831 }
3832
3833 return toBeLessThanOrEqual;
3834};
3835
3836getJasmineRequireObj().toBeNaN = function(j$) {
3837 /**
3838 * {@link expect} the actual value to be `NaN` (Not a Number).
3839 * @function
3840 * @name matchers#toBeNaN
3841 * @example
3842 * expect(thing).toBeNaN();
3843 */
3844 function toBeNaN() {
3845 return {
3846 compare: function(actual) {
3847 var result = {
3848 pass: (actual !== actual)
3849 };
3850
3851 if (result.pass) {
3852 result.message = 'Expected actual not to be NaN.';
3853 } else {
3854 result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
3855 }
3856
3857 return result;
3858 }
3859 };
3860 }
3861
3862 return toBeNaN;
3863};
3864
3865getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
3866 /**
3867 * {@link expect} the actual value to be `-Infinity` (-infinity).
3868 * @function
3869 * @name matchers#toBeNegativeInfinity
3870 * @example
3871 * expect(thing).toBeNegativeInfinity();
3872 */
3873 function toBeNegativeInfinity() {
3874 return {
3875 compare: function(actual) {
3876 var result = {
3877 pass: (actual === Number.NEGATIVE_INFINITY)
3878 };
3879
3880 if (result.pass) {
3881 result.message = 'Expected actual to be -Infinity.';
3882 } else {
3883 result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be -Infinity.'; };
3884 }
3885
3886 return result;
3887 }
3888 };
3889 }
3890
3891 return toBeNegativeInfinity;
3892};
3893
3894getJasmineRequireObj().toBeNull = function() {
3895 /**
3896 * {@link expect} the actual value to be `null`.
3897 * @function
3898 * @name matchers#toBeNull
3899 * @example
3900 * expect(result).toBeNull();
3901 */
3902 function toBeNull() {
3903 return {
3904 compare: function(actual) {
3905 return {
3906 pass: actual === null
3907 };
3908 }
3909 };
3910 }
3911
3912 return toBeNull;
3913};
3914
3915getJasmineRequireObj().toBePositiveInfinity = function(j$) {
3916 /**
3917 * {@link expect} the actual value to be `Infinity` (infinity).
3918 * @function
3919 * @name matchers#toBePositiveInfinity
3920 * @example
3921 * expect(thing).toBePositiveInfinity();
3922 */
3923 function toBePositiveInfinity() {
3924 return {
3925 compare: function(actual) {
3926 var result = {
3927 pass: (actual === Number.POSITIVE_INFINITY)
3928 };
3929
3930 if (result.pass) {
3931 result.message = 'Expected actual to be Infinity.';
3932 } else {
3933 result.message = function() { return 'Expected ' + j$.pp(actual) + ' not to be Infinity.'; };
3934 }
3935
3936 return result;
3937 }
3938 };
3939 }
3940
3941 return toBePositiveInfinity;
3942};
3943
3944getJasmineRequireObj().toBeTruthy = function() {
3945 /**
3946 * {@link expect} the actual value to be truthy.
3947 * @function
3948 * @name matchers#toBeTruthy
3949 * @example
3950 * expect(thing).toBeTruthy();
3951 */
3952 function toBeTruthy() {
3953 return {
3954 compare: function(actual) {
3955 return {
3956 pass: !!actual
3957 };
3958 }
3959 };
3960 }
3961
3962 return toBeTruthy;
3963};
3964
3965getJasmineRequireObj().toBeUndefined = function() {
3966 /**
3967 * {@link expect} the actual value to be `undefined`.
3968 * @function
3969 * @name matchers#toBeUndefined
3970 * @example
3971 * expect(result).toBeUndefined():
3972 */
3973 function toBeUndefined() {
3974 return {
3975 compare: function(actual) {
3976 return {
3977 pass: void 0 === actual
3978 };
3979 }
3980 };
3981 }
3982
3983 return toBeUndefined;
3984};
3985
3986getJasmineRequireObj().toContain = function() {
3987 /**
3988 * {@link expect} the actual value to contain a specific value.
3989 * @function
3990 * @name matchers#toContain
3991 * @param {Object} expected - The value to look for.
3992 * @example
3993 * expect(array).toContain(anElement);
3994 * expect(string).toContain(substring);
3995 */
3996 function toContain(util, customEqualityTesters) {
3997 customEqualityTesters = customEqualityTesters || [];
3998
3999 return {
4000 compare: function(actual, expected) {
4001
4002 return {
4003 pass: util.contains(actual, expected, customEqualityTesters)
4004 };
4005 }
4006 };
4007 }
4008
4009 return toContain;
4010};
4011
4012getJasmineRequireObj().toEqual = function(j$) {
4013 /**
4014 * {@link expect} the actual value to be equal to the expected, using deep equality comparison.
4015 * @function
4016 * @name matchers#toEqual
4017 * @param {Object} expected - Expected value
4018 * @example
4019 * expect(bigObject).toEqual({"foo": ['bar', 'baz']});
4020 */
4021 function toEqual(util, customEqualityTesters) {
4022 customEqualityTesters = customEqualityTesters || [];
4023
4024 return {
4025 compare: function(actual, expected) {
4026 var result = {
4027 pass: false
4028 },
4029 diffBuilder = j$.DiffBuilder();
4030
4031 result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
4032
4033 // TODO: only set error message if test fails
4034 result.message = diffBuilder.getMessage();
4035
4036 return result;
4037 }
4038 };
4039 }
4040
4041 return toEqual;
4042};
4043
4044getJasmineRequireObj().toHaveBeenCalled = function(j$) {
4045
4046 var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
4047
4048 /**
4049 * {@link expect} the actual (a {@link Spy}) to have been called.
4050 * @function
4051 * @name matchers#toHaveBeenCalled
4052 * @example
4053 * expect(mySpy).toHaveBeenCalled();
4054 * expect(mySpy).not.toHaveBeenCalled();
4055 */
4056 function toHaveBeenCalled() {
4057 return {
4058 compare: function(actual) {
4059 var result = {};
4060
4061 if (!j$.isSpy(actual)) {
4062 throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
4063 }
4064
4065 if (arguments.length > 1) {
4066 throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
4067 }
4068
4069 result.pass = actual.calls.any();
4070
4071 result.message = result.pass ?
4072 'Expected spy ' + actual.and.identity + ' not to have been called.' :
4073 'Expected spy ' + actual.and.identity + ' to have been called.';
4074
4075 return result;
4076 }
4077 };
4078 }
4079
4080 return toHaveBeenCalled;
4081};
4082
4083getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
4084
4085 var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledBefore>', 'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)');
4086
4087 /**
4088 * {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
4089 * @function
4090 * @name matchers#toHaveBeenCalledBefore
4091 * @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
4092 * @example
4093 * expect(mySpy).toHaveBeenCalledBefore(otherSpy);
4094 */
4095 function toHaveBeenCalledBefore() {
4096 return {
4097 compare: function(firstSpy, latterSpy) {
4098 if (!j$.isSpy(firstSpy)) {
4099 throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
4100 }
4101 if (!j$.isSpy(latterSpy)) {
4102 throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
4103 }
4104
4105 var result = { pass: false };
4106
4107 if (!firstSpy.calls.count()) {
4108 result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.';
4109 return result;
4110 }
4111 if (!latterSpy.calls.count()) {
4112 result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.';
4113 return result;
4114 }
4115
4116 var latest1stSpyCall = firstSpy.calls.mostRecent().invocationOrder;
4117 var first2ndSpyCall = latterSpy.calls.first().invocationOrder;
4118
4119 result.pass = latest1stSpyCall < first2ndSpyCall;
4120
4121 if (result.pass) {
4122 result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was';
4123 } else {
4124 var first1stSpyCall = firstSpy.calls.first().invocationOrder;
4125 var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
4126
4127 if(first1stSpyCall < first2ndSpyCall) {
4128 result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)';
4129 } else if (latest2ndSpyCall > latest1stSpyCall) {
4130 result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)';
4131 } else {
4132 result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity;
4133 }
4134 }
4135
4136 return result;
4137 }
4138 };
4139 }
4140
4141 return toHaveBeenCalledBefore;
4142};
4143
4144getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
4145
4146 var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
4147
4148 /**
4149 * {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
4150 * @function
4151 * @name matchers#toHaveBeenCalledTimes
4152 * @param {Number} expected - The number of invocations to look for.
4153 * @example
4154 * expect(mySpy).toHaveBeenCalledTimes(3);
4155 */
4156 function toHaveBeenCalledTimes() {
4157 return {
4158 compare: function(actual, expected) {
4159 if (!j$.isSpy(actual)) {
4160 throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
4161 }
4162
4163 var args = Array.prototype.slice.call(arguments, 0),
4164 result = { pass: false };
4165
4166 if (!j$.isNumber_(expected)){
4167 throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
4168 }
4169
4170 actual = args[0];
4171 var calls = actual.calls.count();
4172 var timesMessage = expected === 1 ? 'once' : expected + ' times';
4173 result.pass = calls === expected;
4174 result.message = result.pass ?
4175 'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
4176 'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
4177 return result;
4178 }
4179 };
4180 }
4181
4182 return toHaveBeenCalledTimes;
4183};
4184
4185getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
4186
4187 var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
4188
4189 /**
4190 * {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
4191 * @function
4192 * @name matchers#toHaveBeenCalledWith
4193 * @param {...Object} - The arguments to look for
4194 * @example
4195 * expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
4196 */
4197 function toHaveBeenCalledWith(util, customEqualityTesters) {
4198 return {
4199 compare: function() {
4200 var args = Array.prototype.slice.call(arguments, 0),
4201 actual = args[0],
4202 expectedArgs = args.slice(1),
4203 result = { pass: false };
4204
4205 if (!j$.isSpy(actual)) {
4206 throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
4207 }
4208
4209 if (!actual.calls.any()) {
4210 result.message = function() { return 'Expected spy ' + actual.and.identity + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
4211 return result;
4212 }
4213
4214 if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
4215 result.pass = true;
4216 result.message = function() { return 'Expected spy ' + actual.and.identity + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
4217 } else {
4218 result.message = function() { return 'Expected spy ' + actual.and.identity + ' to have been called with ' + j$.pp(expectedArgs) + ' but actual calls were ' + j$.pp(actual.calls.allArgs()).replace(/^\[ | \]$/g, '') + '.'; };
4219 }
4220
4221 return result;
4222 }
4223 };
4224 }
4225
4226 return toHaveBeenCalledWith;
4227};
4228
4229getJasmineRequireObj().toHaveClass = function(j$) {
4230 /**
4231 * {@link expect} the actual value to be a DOM element that has the expected class
4232 * @function
4233 * @name matchers#toHaveClass
4234 * @param {Object} expected - The class name to test for
4235 * @example
4236 * var el = document.createElement('div');
4237 * el.className = 'foo bar baz';
4238 * expect(el).toHaveClass('bar');
4239 */
4240 function toHaveClass(util, customEqualityTesters) {
4241 return {
4242 compare: function(actual, expected) {
4243 if (!isElement(actual)) {
4244 throw new Error(j$.pp(actual) + ' is not a DOM element');
4245 }
4246
4247 return {
4248 pass: actual.classList.contains(expected)
4249 };
4250 }
4251 };
4252 }
4253
4254 function isElement(maybeEl) {
4255 return maybeEl &&
4256 maybeEl.classList &&
4257 j$.isFunction_(maybeEl.classList.contains);
4258 }
4259
4260 return toHaveClass;
4261};
4262
4263getJasmineRequireObj().toMatch = function(j$) {
4264
4265 var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
4266
4267 /**
4268 * {@link expect} the actual value to match a regular expression
4269 * @function
4270 * @name matchers#toMatch
4271 * @param {RegExp|String} expected - Value to look for in the string.
4272 * @example
4273 * expect("my string").toMatch(/string$/);
4274 * expect("other string").toMatch("her");
4275 */
4276 function toMatch() {
4277 return {
4278 compare: function(actual, expected) {
4279 if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
4280 throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
4281 }
4282
4283 var regexp = new RegExp(expected);
4284
4285 return {
4286 pass: regexp.test(actual)
4287 };
4288 }
4289 };
4290 }
4291
4292 return toMatch;
4293};
4294
4295getJasmineRequireObj().toThrow = function(j$) {
4296
4297 var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
4298
4299 /**
4300 * {@link expect} a function to `throw` something.
4301 * @function
4302 * @name matchers#toThrow
4303 * @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
4304 * @example
4305 * expect(function() { return 'things'; }).toThrow('foo');
4306 * expect(function() { return 'stuff'; }).toThrow();
4307 */
4308 function toThrow(util) {
4309 return {
4310 compare: function(actual, expected) {
4311 var result = { pass: false },
4312 threw = false,
4313 thrown;
4314
4315 if (typeof actual != 'function') {
4316 throw new Error(getErrorMsg('Actual is not a Function'));
4317 }
4318
4319 try {
4320 actual();
4321 } catch (e) {
4322 threw = true;
4323 thrown = e;
4324 }
4325
4326 if (!threw) {
4327 result.message = 'Expected function to throw an exception.';
4328 return result;
4329 }
4330
4331 if (arguments.length == 1) {
4332 result.pass = true;
4333 result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
4334
4335 return result;
4336 }
4337
4338 if (util.equals(thrown, expected)) {
4339 result.pass = true;
4340 result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
4341 } else {
4342 result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
4343 }
4344
4345 return result;
4346 }
4347 };
4348 }
4349
4350 return toThrow;
4351};
4352
4353getJasmineRequireObj().toThrowError = function(j$) {
4354
4355 var getErrorMsg = j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
4356
4357 /**
4358 * {@link expect} a function to `throw` an `Error`.
4359 * @function
4360 * @name matchers#toThrowError
4361 * @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
4362 * @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
4363 * @example
4364 * expect(function() { return 'things'; }).toThrowError(MyCustomError, 'message');
4365 * expect(function() { return 'things'; }).toThrowError(MyCustomError, /bar/);
4366 * expect(function() { return 'stuff'; }).toThrowError(MyCustomError);
4367 * expect(function() { return 'other'; }).toThrowError(/foo/);
4368 * expect(function() { return 'other'; }).toThrowError();
4369 */
4370 function toThrowError () {
4371 return {
4372 compare: function(actual) {
4373 var errorMatcher = getMatcher.apply(null, arguments),
4374 thrown;
4375
4376 if (typeof actual != 'function') {
4377 throw new Error(getErrorMsg('Actual is not a Function'));
4378 }
4379
4380 try {
4381 actual();
4382 return fail('Expected function to throw an Error.');
4383 } catch (e) {
4384 thrown = e;
4385 }
4386
4387 if (!j$.isError_(thrown)) {
4388 return fail(function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; });
4389 }
4390
4391 return errorMatcher.match(thrown);
4392 }
4393 };
4394
4395 function getMatcher() {
4396 var expected, errorType;
4397
4398 if (arguments[2]) {
4399 errorType = arguments[1];
4400 expected = arguments[2];
4401 if (!isAnErrorType(errorType)) {
4402 throw new Error(getErrorMsg('Expected error type is not an Error.'));
4403 }
4404
4405 return exactMatcher(expected, errorType);
4406 } else if (arguments[1]) {
4407 expected = arguments[1];
4408
4409 if (isAnErrorType(arguments[1])) {
4410 return exactMatcher(null, arguments[1]);
4411 } else {
4412 return exactMatcher(arguments[1], null);
4413 }
4414 } else {
4415 return anyMatcher();
4416 }
4417 }
4418
4419 function anyMatcher() {
4420 return {
4421 match: function(error) {
4422 return pass('Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.');
4423 }
4424 };
4425 }
4426
4427 function exactMatcher(expected, errorType) {
4428 if (expected && !isStringOrRegExp(expected)) {
4429 if (errorType) {
4430 throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
4431 } else {
4432 throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
4433 }
4434 }
4435
4436 function messageMatch(message) {
4437 if (typeof expected == 'string') {
4438 return expected == message;
4439 } else {
4440 return expected.test(message);
4441 }
4442 }
4443
4444 var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception';
4445
4446 function thrownDescription(thrown) {
4447 var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
4448 thrownMessage = '';
4449
4450 if (expected) {
4451 thrownMessage = ' with message ' + j$.pp(thrown.message);
4452 }
4453
4454 return thrownName + thrownMessage;
4455 }
4456
4457 function messageDescription() {
4458 if (expected === null) {
4459 return '';
4460 } else if (expected instanceof RegExp) {
4461 return ' with a message matching ' + j$.pp(expected);
4462 } else {
4463 return ' with message ' + j$.pp(expected);
4464 }
4465 }
4466
4467 function matches(error) {
4468 return (errorType === null || error instanceof errorType) &&
4469 (expected === null || messageMatch(error.message));
4470 }
4471
4472 return {
4473 match: function(thrown) {
4474 if (matches(thrown)) {
4475 return pass(function() {
4476 return 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.';
4477 });
4478 } else {
4479 return fail(function() {
4480 return 'Expected function to throw ' + errorTypeDescription + messageDescription() +
4481 ', but it threw ' + thrownDescription(thrown) + '.';
4482 });
4483 }
4484 }
4485 };
4486 }
4487
4488 function isStringOrRegExp(potential) {
4489 return potential instanceof RegExp || (typeof potential == 'string');
4490 }
4491
4492 function isAnErrorType(type) {
4493 if (typeof type !== 'function') {
4494 return false;
4495 }
4496
4497 var Surrogate = function() {};
4498 Surrogate.prototype = type.prototype;
4499 return j$.isError_(new Surrogate());
4500 }
4501 }
4502
4503 function pass(message) {
4504 return {
4505 pass: true,
4506 message: message
4507 };
4508 }
4509
4510 function fail(message) {
4511 return {
4512 pass: false,
4513 message: message
4514 };
4515 }
4516
4517 return toThrowError;
4518};
4519
4520getJasmineRequireObj().toThrowMatching = function(j$) {
4521 var usageError = j$.formatErrorMsg('<toThrowMatching>', 'expect(function() {<expectation>}).toThrowMatching(<Predicate>)');
4522
4523 /**
4524 * {@link expect} a function to `throw` something matching a predicate.
4525 * @function
4526 * @name matchers#toThrowMatching
4527 * @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches.
4528 * @example
4529 * expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
4530 */
4531 function toThrowMatching() {
4532 return {
4533 compare: function(actual, predicate) {
4534 var thrown;
4535
4536 if (typeof actual !== 'function') {
4537 throw new Error(usageError('Actual is not a Function'));
4538 }
4539
4540 if (typeof predicate !== 'function') {
4541 throw new Error(usageError('Predicate is not a Function'));
4542 }
4543
4544 try {
4545 actual();
4546 return fail('Expected function to throw an exception.');
4547 } catch (e) {
4548 thrown = e;
4549 }
4550
4551 if (predicate(thrown)) {
4552 return pass('Expected function not to throw an exception matching a predicate.');
4553 } else {
4554 return fail(function() {
4555 return 'Expected function to throw an exception matching a predicate, ' +
4556 'but it threw ' + thrownDescription(thrown) + '.';
4557 });
4558 }
4559 }
4560 };
4561 }
4562
4563 function thrownDescription(thrown) {
4564 if (thrown && thrown.constructor) {
4565 return j$.fnNameFor(thrown.constructor) + ' with message ' +
4566 j$.pp(thrown.message);
4567 } else {
4568 return j$.pp(thrown);
4569 }
4570 }
4571
4572 function pass(message) {
4573 return {
4574 pass: true,
4575 message: message
4576 };
4577 }
4578
4579 function fail(message) {
4580 return {
4581 pass: false,
4582 message: message
4583 };
4584 }
4585
4586 return toThrowMatching;
4587};
4588
4589getJasmineRequireObj().MockDate = function() {
4590 function MockDate(global) {
4591 var self = this;
4592 var currentTime = 0;
4593
4594 if (!global || !global.Date) {
4595 self.install = function() {};
4596 self.tick = function() {};
4597 self.uninstall = function() {};
4598 return self;
4599 }
4600
4601 var GlobalDate = global.Date;
4602
4603 self.install = function(mockDate) {
4604 if (mockDate instanceof GlobalDate) {
4605 currentTime = mockDate.getTime();
4606 } else {
4607 currentTime = new GlobalDate().getTime();
4608 }
4609
4610 global.Date = FakeDate;
4611 };
4612
4613 self.tick = function(millis) {
4614 millis = millis || 0;
4615 currentTime = currentTime + millis;
4616 };
4617
4618 self.uninstall = function() {
4619 currentTime = 0;
4620 global.Date = GlobalDate;
4621 };
4622
4623 createDateProperties();
4624
4625 return self;
4626
4627 function FakeDate() {
4628 switch(arguments.length) {
4629 case 0:
4630 return new GlobalDate(currentTime);
4631 case 1:
4632 return new GlobalDate(arguments[0]);
4633 case 2:
4634 return new GlobalDate(arguments[0], arguments[1]);
4635 case 3:
4636 return new GlobalDate(arguments[0], arguments[1], arguments[2]);
4637 case 4:
4638 return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
4639 case 5:
4640 return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
4641 arguments[4]);
4642 case 6:
4643 return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
4644 arguments[4], arguments[5]);
4645 default:
4646 return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
4647 arguments[4], arguments[5], arguments[6]);
4648 }
4649 }
4650
4651 function createDateProperties() {
4652 FakeDate.prototype = GlobalDate.prototype;
4653
4654 FakeDate.now = function() {
4655 if (GlobalDate.now) {
4656 return currentTime;
4657 } else {
4658 throw new Error('Browser does not support Date.now()');
4659 }
4660 };
4661
4662 FakeDate.toSource = GlobalDate.toSource;
4663 FakeDate.toString = GlobalDate.toString;
4664 FakeDate.parse = GlobalDate.parse;
4665 FakeDate.UTC = GlobalDate.UTC;
4666 }
4667 }
4668
4669 return MockDate;
4670};
4671
4672getJasmineRequireObj().pp = function(j$) {
4673
4674 function PrettyPrinter() {
4675 this.ppNestLevel_ = 0;
4676 this.seen = [];
4677 this.length = 0;
4678 this.stringParts = [];
4679 }
4680
4681 function hasCustomToString(value) {
4682 // value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
4683 // iframe, web worker)
4684 return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
4685 }
4686
4687 PrettyPrinter.prototype.format = function(value) {
4688 this.ppNestLevel_++;
4689 try {
4690 if (j$.util.isUndefined(value)) {
4691 this.emitScalar('undefined');
4692 } else if (value === null) {
4693 this.emitScalar('null');
4694 } else if (value === 0 && 1/value === -Infinity) {
4695 this.emitScalar('-0');
4696 } else if (value === j$.getGlobal()) {
4697 this.emitScalar('<global>');
4698 } else if (value.jasmineToString) {
4699 this.emitScalar(value.jasmineToString());
4700 } else if (typeof value === 'string') {
4701 this.emitString(value);
4702 } else if (j$.isSpy(value)) {
4703 this.emitScalar('spy on ' + value.and.identity);
4704 } else if (value instanceof RegExp) {
4705 this.emitScalar(value.toString());
4706 } else if (typeof value === 'function') {
4707 this.emitScalar('Function');
4708 } else if (value.nodeType === 1) {
4709 this.emitDomElement(value);
4710 } else if (typeof value.nodeType === 'number') {
4711 this.emitScalar('HTMLNode');
4712 } else if (value instanceof Date) {
4713 this.emitScalar('Date(' + value + ')');
4714 } else if (j$.isSet(value)) {
4715 this.emitSet(value);
4716 } else if (j$.isMap(value)) {
4717 this.emitMap(value);
4718 } else if (j$.isTypedArray_(value)) {
4719 this.emitTypedArray(value);
4720 } else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
4721 this.emitScalar(value.toString());
4722 } else if (j$.util.arrayContains(this.seen, value)) {
4723 this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
4724 } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
4725 this.seen.push(value);
4726 if (j$.isArray_(value)) {
4727 this.emitArray(value);
4728 } else {
4729 this.emitObject(value);
4730 }
4731 this.seen.pop();
4732 } else {
4733 this.emitScalar(value.toString());
4734 }
4735 } catch (e) {
4736 if (this.ppNestLevel_ > 1 || !(e instanceof MaxCharsReachedError)) {
4737 throw e;
4738 }
4739 } finally {
4740 this.ppNestLevel_--;
4741 }
4742 };
4743
4744 PrettyPrinter.prototype.iterateObject = function(obj, fn) {
4745 var objKeys = keys(obj, j$.isArray_(obj));
4746 var isGetter = function isGetter(prop) {};
4747
4748 if (obj.__lookupGetter__) {
4749 isGetter = function isGetter(prop) {
4750 var getter = obj.__lookupGetter__(prop);
4751 return !j$.util.isUndefined(getter) && getter !== null;
4752 };
4753
4754 }
4755 var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
4756 for (var i = 0; i < length; i++) {
4757 var property = objKeys[i];
4758 fn(property, isGetter(property));
4759 }
4760
4761 return objKeys.length > length;
4762 };
4763
4764 PrettyPrinter.prototype.emitScalar = function(value) {
4765 this.append(value);
4766 };
4767
4768 PrettyPrinter.prototype.emitString = function(value) {
4769 this.append('\'' + value + '\'');
4770 };
4771
4772 PrettyPrinter.prototype.emitArray = function(array) {
4773 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
4774 this.append('Array');
4775 return;
4776 }
4777 var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
4778 this.append('[ ');
4779 for (var i = 0; i < length; i++) {
4780 if (i > 0) {
4781 this.append(', ');
4782 }
4783 this.format(array[i]);
4784 }
4785 if(array.length > length){
4786 this.append(', ...');
4787 }
4788
4789 var self = this;
4790 var first = array.length === 0;
4791 var truncated = this.iterateObject(array, function(property, isGetter) {
4792 if (first) {
4793 first = false;
4794 } else {
4795 self.append(', ');
4796 }
4797
4798 self.formatProperty(array, property, isGetter);
4799 });
4800
4801 if (truncated) { this.append(', ...'); }
4802
4803 this.append(' ]');
4804 };
4805
4806 PrettyPrinter.prototype.emitSet = function(set) {
4807 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
4808 this.append('Set');
4809 return;
4810 }
4811 this.append('Set( ');
4812 var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
4813 var i = 0;
4814 set.forEach( function( value, key ) {
4815 if (i >= size) {
4816 return;
4817 }
4818 if (i > 0) {
4819 this.append(', ');
4820 }
4821 this.format(value);
4822
4823 i++;
4824 }, this );
4825 if (set.size > size){
4826 this.append(', ...');
4827 }
4828 this.append(' )');
4829 };
4830
4831 PrettyPrinter.prototype.emitMap = function(map) {
4832 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
4833 this.append('Map');
4834 return;
4835 }
4836 this.append('Map( ');
4837 var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
4838 var i = 0;
4839 map.forEach( function( value, key ) {
4840 if (i >= size) {
4841 return;
4842 }
4843 if (i > 0) {
4844 this.append(', ');
4845 }
4846 this.format([key,value]);
4847
4848 i++;
4849 }, this );
4850 if (map.size > size){
4851 this.append(', ...');
4852 }
4853 this.append(' )');
4854 };
4855
4856 PrettyPrinter.prototype.emitObject = function(obj) {
4857 var ctor = obj.constructor,
4858 constructorName;
4859
4860 constructorName = typeof ctor === 'function' && obj instanceof ctor ?
4861 j$.fnNameFor(obj.constructor) :
4862 'null';
4863
4864 this.append(constructorName);
4865
4866 if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
4867 return;
4868 }
4869
4870 var self = this;
4871 this.append('({ ');
4872 var first = true;
4873
4874 var truncated = this.iterateObject(obj, function(property, isGetter) {
4875 if (first) {
4876 first = false;
4877 } else {
4878 self.append(', ');
4879 }
4880
4881 self.formatProperty(obj, property, isGetter);
4882 });
4883
4884 if (truncated) { this.append(', ...'); }
4885
4886 this.append(' })');
4887 };
4888
4889 PrettyPrinter.prototype.emitTypedArray = function(arr) {
4890 var constructorName = j$.fnNameFor(arr.constructor),
4891 limitedArray = Array.prototype.slice.call(arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH),
4892 itemsString = Array.prototype.join.call(limitedArray, ', ');
4893
4894 if (limitedArray.length !== arr.length) {
4895 itemsString += ', ...';
4896 }
4897
4898 this.append(constructorName + ' [ ' + itemsString + ' ]');
4899 };
4900
4901 PrettyPrinter.prototype.emitDomElement = function(el) {
4902 var closingTag = '</' + el.tagName.toLowerCase() + '>';
4903
4904 if (el.innerHTML === '') {
4905 this.append(el.outerHTML.replace(closingTag, ''));
4906 } else {
4907 var tagEnd = el.outerHTML.indexOf('>');
4908 this.append(el.outerHTML.substring(0, tagEnd + 1));
4909 this.append('...' + closingTag);
4910 }
4911 };
4912
4913 PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
4914 this.append(property);
4915 this.append(': ');
4916 if (isGetter) {
4917 this.append('<getter>');
4918 } else {
4919 this.format(obj[property]);
4920 }
4921 };
4922
4923 PrettyPrinter.prototype.append = function(value) {
4924 var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
4925 this.length += result.value.length;
4926 this.stringParts.push(result.value);
4927
4928 if (result.truncated) {
4929 throw new MaxCharsReachedError();
4930 }
4931 };
4932
4933
4934 function truncate(s, maxlen) {
4935 if (s.length <= maxlen) {
4936 return { value: s, truncated: false };
4937 }
4938
4939 s = s.substring(0, maxlen - 4) + ' ...';
4940 return { value: s, truncated: true };
4941 }
4942
4943 function MaxCharsReachedError() {
4944 this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS +
4945 ' characters while pretty-printing a value';
4946 }
4947
4948 MaxCharsReachedError.prototype = new Error();
4949
4950 function keys(obj, isArray) {
4951 var allKeys = Object.keys ? Object.keys(obj) :
4952 (function(o) {
4953 var keys = [];
4954 for (var key in o) {
4955 if (j$.util.has(o, key)) {
4956 keys.push(key);
4957 }
4958 }
4959 return keys;
4960 })(obj);
4961
4962 if (!isArray) {
4963 return allKeys;
4964 }
4965
4966 if (allKeys.length === 0) {
4967 return allKeys;
4968 }
4969
4970 var extraKeys = [];
4971 for (var i = 0; i < allKeys.length; i++) {
4972 if (!/^[0-9]+$/.test(allKeys[i])) {
4973 extraKeys.push(allKeys[i]);
4974 }
4975 }
4976
4977 return extraKeys;
4978 }
4979 return function(value) {
4980 var prettyPrinter = new PrettyPrinter();
4981 prettyPrinter.format(value);
4982 return prettyPrinter.stringParts.join('');
4983 };
4984};
4985
4986getJasmineRequireObj().QueueRunner = function(j$) {
4987 function StopExecutionError() {}
4988 StopExecutionError.prototype = new Error();
4989 j$.StopExecutionError = StopExecutionError;
4990
4991 function once(fn) {
4992 var called = false;
4993 return function() {
4994 if (!called) {
4995 called = true;
4996 fn.apply(null, arguments);
4997 }
4998 return null;
4999 };
5000 }
5001
5002 function QueueRunner(attrs) {
5003 var queueableFns = attrs.queueableFns || [];
5004 this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
5005 this.firstCleanupIx = queueableFns.length;
5006 this.onComplete = attrs.onComplete || function() {};
5007 this.clearStack = attrs.clearStack || function(fn) {fn();};
5008 this.onException = attrs.onException || function() {};
5009 this.userContext = attrs.userContext || new j$.UserContext();
5010 this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
5011 this.fail = attrs.fail || function() {};
5012 this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
5013 this.completeOnFirstError = !!attrs.completeOnFirstError;
5014 this.errored = false;
5015
5016 if (typeof(this.onComplete) !== 'function') {
5017 throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
5018 }
5019 this.deprecated = attrs.deprecated;
5020 }
5021
5022 QueueRunner.prototype.execute = function() {
5023 var self = this;
5024 this.handleFinalError = function(error) {
5025 self.onException(error);
5026 };
5027 this.globalErrors.pushListener(this.handleFinalError);
5028 this.run(0);
5029 };
5030
5031 QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
5032 if (lastRanIndex < this.firstCleanupIx) {
5033 this.run(this.firstCleanupIx);
5034 } else {
5035 this.run(lastRanIndex + 1);
5036 }
5037 };
5038
5039 QueueRunner.prototype.clearTimeout = function(timeoutId) {
5040 Function.prototype.apply.apply(this.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
5041 };
5042
5043 QueueRunner.prototype.setTimeout = function(fn, timeout) {
5044 return Function.prototype.apply.apply(this.timeout.setTimeout, [j$.getGlobal(), [fn, timeout]]);
5045 };
5046
5047 QueueRunner.prototype.attempt = function attempt(iterativeIndex) {
5048 var self = this, completedSynchronously = true,
5049 handleError = function handleError(error) {
5050 onException(error);
5051 next(error);
5052 },
5053 cleanup = once(function cleanup() {
5054 self.clearTimeout(timeoutId);
5055 self.globalErrors.popListener(handleError);
5056 }),
5057 next = once(function next(err) {
5058 cleanup();
5059
5060 if (j$.isError_(err)) {
5061 if (!(err instanceof StopExecutionError)) {
5062 self.fail(err);
5063 }
5064 self.errored = errored = true;
5065 }
5066
5067 function runNext() {
5068 if (self.completeOnFirstError && errored) {
5069 self.skipToCleanup(iterativeIndex);
5070 } else {
5071 self.run(iterativeIndex + 1);
5072 }
5073 }
5074
5075 if (completedSynchronously) {
5076 self.setTimeout(runNext);
5077 } else {
5078 runNext();
5079 }
5080 }),
5081 errored = false,
5082 queueableFn = self.queueableFns[iterativeIndex],
5083 timeoutId;
5084
5085 next.fail = function nextFail() {
5086 self.fail.apply(null, arguments);
5087 self.errored = errored = true;
5088 next();
5089 };
5090
5091 self.globalErrors.pushListener(handleError);
5092
5093 if (queueableFn.timeout !== undefined) {
5094 var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
5095 timeoutId = self.setTimeout(function() {
5096 var error = new Error(
5097 'Timeout - Async callback was not invoked within ' + timeoutInterval + 'ms ' +
5098 (queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
5099 );
5100 onException(error);
5101 next();
5102 }, timeoutInterval);
5103 }
5104
5105 try {
5106 if (queueableFn.fn.length === 0) {
5107 var maybeThenable = queueableFn.fn.call(self.userContext);
5108
5109 if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
5110 maybeThenable.then(next, onPromiseRejection);
5111 completedSynchronously = false;
5112 return { completedSynchronously: false };
5113 }
5114 } else {
5115 queueableFn.fn.call(self.userContext, next);
5116 completedSynchronously = false;
5117 return { completedSynchronously: false };
5118 }
5119 } catch (e) {
5120 onException(e);
5121 self.errored = errored = true;
5122 }
5123
5124 cleanup();
5125 return { completedSynchronously: true, errored: errored };
5126
5127 function onException(e) {
5128 self.onException(e);
5129 self.errored = errored = true;
5130 }
5131
5132 function onPromiseRejection(e) {
5133 onException(e);
5134 next();
5135 }
5136 };
5137
5138 QueueRunner.prototype.run = function(recursiveIndex) {
5139 var length = this.queueableFns.length,
5140 self = this,
5141 iterativeIndex;
5142
5143
5144 for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
5145 var result = this.attempt(iterativeIndex);
5146
5147 if (!result.completedSynchronously) {
5148 return;
5149 }
5150
5151 self.errored = self.errored || result.errored;
5152
5153 if (this.completeOnFirstError && result.errored) {
5154 this.skipToCleanup(iterativeIndex);
5155 return;
5156 }
5157 }
5158
5159 this.clearStack(function() {
5160 self.globalErrors.popListener(self.handleFinalError);
5161 self.onComplete(self.errored && new StopExecutionError());
5162 });
5163
5164 };
5165
5166 return QueueRunner;
5167};
5168
5169getJasmineRequireObj().ReportDispatcher = function(j$) {
5170 function ReportDispatcher(methods, queueRunnerFactory) {
5171
5172 var dispatchedMethods = methods || [];
5173
5174 for (var i = 0; i < dispatchedMethods.length; i++) {
5175 var method = dispatchedMethods[i];
5176 this[method] = (function(m) {
5177 return function() {
5178 dispatch(m, arguments);
5179 };
5180 }(method));
5181 }
5182
5183 var reporters = [];
5184 var fallbackReporter = null;
5185
5186 this.addReporter = function(reporter) {
5187 reporters.push(reporter);
5188 };
5189
5190 this.provideFallbackReporter = function(reporter) {
5191 fallbackReporter = reporter;
5192 };
5193
5194 this.clearReporters = function() {
5195 reporters = [];
5196 };
5197
5198 return this;
5199
5200 function dispatch(method, args) {
5201 if (reporters.length === 0 && fallbackReporter !== null) {
5202 reporters.push(fallbackReporter);
5203 }
5204 var onComplete = args[args.length - 1];
5205 args = j$.util.argsToArray(args).splice(0, args.length - 1);
5206 var fns = [];
5207 for (var i = 0; i < reporters.length; i++) {
5208 var reporter = reporters[i];
5209 addFn(fns, reporter, method, args);
5210 }
5211
5212 queueRunnerFactory({
5213 queueableFns: fns,
5214 onComplete: onComplete,
5215 isReporter: true
5216 });
5217 }
5218
5219 function addFn(fns, reporter, method, args) {
5220 var fn = reporter[method];
5221 if (!fn) {
5222 return;
5223 }
5224
5225 var thisArgs = j$.util.cloneArgs(args);
5226 if (fn.length <= 1) {
5227 fns.push({
5228 fn: function () {
5229 return fn.apply(reporter, thisArgs);
5230 }
5231 });
5232 } else {
5233 fns.push({
5234 fn: function (done) {
5235 return fn.apply(reporter, thisArgs.concat([done]));
5236 }
5237 });
5238 }
5239 }
5240 }
5241
5242 return ReportDispatcher;
5243};
5244
5245
5246getJasmineRequireObj().interface = function(jasmine, env) {
5247 var jasmineInterface = {
5248 /**
5249 * Callback passed to parts of the Jasmine base interface.
5250 *
5251 * By default Jasmine assumes this function completes synchronously.
5252 * If you have code that you need to test asynchronously, you can declare that you receive a `done` callback, return a Promise, or use the `async` keyword if it is supported in your environment.
5253 * @callback implementationCallback
5254 * @param {Function} [done] Used to specify to Jasmine that this callback is asynchronous and Jasmine should wait until it has been called before moving on.
5255 * @returns {} Optionally return a Promise instead of using `done` to cause Jasmine to wait for completion.
5256 */
5257
5258 /**
5259 * Create a group of specs (often called a suite).
5260 *
5261 * Calls to `describe` can be nested within other calls to compose your suite as a tree.
5262 * @name describe
5263 * @function
5264 * @global
5265 * @param {String} description Textual description of the group
5266 * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
5267 */
5268 describe: function(description, specDefinitions) {
5269 return env.describe(description, specDefinitions);
5270 },
5271
5272 /**
5273 * A temporarily disabled [`describe`]{@link describe}
5274 *
5275 * Specs within an `xdescribe` will be marked pending and not executed
5276 * @name xdescribe
5277 * @function
5278 * @global
5279 * @param {String} description Textual description of the group
5280 * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
5281 */
5282 xdescribe: function(description, specDefinitions) {
5283 return env.xdescribe(description, specDefinitions);
5284 },
5285
5286 /**
5287 * A focused [`describe`]{@link describe}
5288 *
5289 * If suites or specs are focused, only those that are focused will be executed
5290 * @see fit
5291 * @name fdescribe
5292 * @function
5293 * @global
5294 * @param {String} description Textual description of the group
5295 * @param {Function} specDefinitions Function for Jasmine to invoke that will define inner suites and specs
5296 */
5297 fdescribe: function(description, specDefinitions) {
5298 return env.fdescribe(description, specDefinitions);
5299 },
5300
5301 /**
5302 * Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
5303 *
5304 * A spec whose expectations all succeed will be passing and a spec with any failures will fail.
5305 * @name it
5306 * @function
5307 * @global
5308 * @param {String} description Textual description of what this spec is checking
5309 * @param {implementationCallback} [testFunction] Function that contains the code of your test. If not provided the test will be `pending`.
5310 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
5311 * @see async
5312 */
5313 it: function() {
5314 return env.it.apply(env, arguments);
5315 },
5316
5317 /**
5318 * A temporarily disabled [`it`]{@link it}
5319 *
5320 * The spec will report as `pending` and will not be executed.
5321 * @name xit
5322 * @function
5323 * @global
5324 * @param {String} description Textual description of what this spec is checking.
5325 * @param {implementationCallback} [testFunction] Function that contains the code of your test. Will not be executed.
5326 */
5327 xit: function() {
5328 return env.xit.apply(env, arguments);
5329 },
5330
5331 /**
5332 * A focused [`it`]{@link it}
5333 *
5334 * If suites or specs are focused, only those that are focused will be executed.
5335 * @name fit
5336 * @function
5337 * @global
5338 * @param {String} description Textual description of what this spec is checking.
5339 * @param {implementationCallback} testFunction Function that contains the code of your test.
5340 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async spec.
5341 * @see async
5342 */
5343 fit: function() {
5344 return env.fit.apply(env, arguments);
5345 },
5346
5347 /**
5348 * Run some shared setup before each of the specs in the {@link describe} in which it is called.
5349 * @name beforeEach
5350 * @function
5351 * @global
5352 * @param {implementationCallback} [function] Function that contains the code to setup your specs.
5353 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeEach.
5354 * @see async
5355 */
5356 beforeEach: function() {
5357 return env.beforeEach.apply(env, arguments);
5358 },
5359
5360 /**
5361 * Run some shared teardown after each of the specs in the {@link describe} in which it is called.
5362 * @name afterEach
5363 * @function
5364 * @global
5365 * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
5366 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterEach.
5367 * @see async
5368 */
5369 afterEach: function() {
5370 return env.afterEach.apply(env, arguments);
5371 },
5372
5373 /**
5374 * Run some shared setup once before all of the specs in the {@link describe} are run.
5375 *
5376 * _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
5377 * @name beforeAll
5378 * @function
5379 * @global
5380 * @param {implementationCallback} [function] Function that contains the code to setup your specs.
5381 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async beforeAll.
5382 * @see async
5383 */
5384 beforeAll: function() {
5385 return env.beforeAll.apply(env, arguments);
5386 },
5387
5388 /**
5389 * Run some shared teardown once after all of the specs in the {@link describe} are run.
5390 *
5391 * _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
5392 * @name afterAll
5393 * @function
5394 * @global
5395 * @param {implementationCallback} [function] Function that contains the code to teardown your specs.
5396 * @param {Int} [timeout={@link jasmine.DEFAULT_TIMEOUT_INTERVAL}] Custom timeout for an async afterAll.
5397 * @see async
5398 */
5399 afterAll: function() {
5400 return env.afterAll.apply(env, arguments);
5401 },
5402
5403 /**
5404 * Create an expectation for a spec.
5405 * @name expect
5406 * @function
5407 * @global
5408 * @param {Object} actual - Actual computed value to test expectations against.
5409 * @return {matchers}
5410 */
5411 expect: function(actual) {
5412 return env.expect(actual);
5413 },
5414
5415 /**
5416 * Create an asynchronous expectation for a spec. Note that the matchers
5417 * that are provided by an asynchronous expectation all return promises
5418 * which must be either returned from the spec or waited for using `await`
5419 * in order for Jasmine to associate them with the correct spec.
5420 * @name expectAsync
5421 * @function
5422 * @global
5423 * @param {Object} actual - Actual computed value to test expectations against.
5424 * @return {async-matchers}
5425 * @example
5426 * await expectAsync(somePromise).toBeResolved();
5427 * @example
5428 * return expectAsync(somePromise).toBeResolved();
5429 */
5430 expectAsync: function(actual) {
5431 return env.expectAsync(actual);
5432 },
5433
5434 /**
5435 * Mark a spec as pending, expectation results will be ignored.
5436 * @name pending
5437 * @function
5438 * @global
5439 * @param {String} [message] - Reason the spec is pending.
5440 */
5441 pending: function() {
5442 return env.pending.apply(env, arguments);
5443 },
5444
5445 /**
5446 * Explicitly mark a spec as failed.
5447 * @name fail
5448 * @function
5449 * @global
5450 * @param {String|Error} [error] - Reason for the failure.
5451 */
5452 fail: function() {
5453 return env.fail.apply(env, arguments);
5454 },
5455
5456 /**
5457 * Install a spy onto an existing object.
5458 * @name spyOn
5459 * @function
5460 * @global
5461 * @param {Object} obj - The object upon which to install the {@link Spy}.
5462 * @param {String} methodName - The name of the method to replace with a {@link Spy}.
5463 * @returns {Spy}
5464 */
5465 spyOn: function(obj, methodName) {
5466 return env.spyOn(obj, methodName);
5467 },
5468
5469 /**
5470 * Install a spy on a property installed with `Object.defineProperty` onto an existing object.
5471 * @name spyOnProperty
5472 * @function
5473 * @global
5474 * @param {Object} obj - The object upon which to install the {@link Spy}
5475 * @param {String} propertyName - The name of the property to replace with a {@link Spy}.
5476 * @param {String} [accessType=get] - The access type (get|set) of the property to {@link Spy} on.
5477 * @returns {Spy}
5478 */
5479 spyOnProperty: function(obj, methodName, accessType) {
5480 return env.spyOnProperty(obj, methodName, accessType);
5481 },
5482
5483 /**
5484 * Installs spies on all writable and configurable properties of an object.
5485 * @name spyOnProperty
5486 * @function
5487 * @global
5488 * @param {Object} obj - The object upon which to install the {@link Spy}s
5489 * @returns {Object} the spied object
5490 */
5491 spyOnAllFunctions: function(obj) {
5492 return env.spyOnAllFunctions(obj);
5493 },
5494
5495 jsApiReporter: new jasmine.JsApiReporter({
5496 timer: new jasmine.Timer()
5497 }),
5498
5499 /**
5500 * @namespace jasmine
5501 */
5502 jasmine: jasmine
5503 };
5504
5505 /**
5506 * Add a custom equality tester for the current scope of specs.
5507 *
5508 * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
5509 * @name jasmine.addCustomEqualityTester
5510 * @function
5511 * @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
5512 * @see custom_equality
5513 */
5514 jasmine.addCustomEqualityTester = function(tester) {
5515 env.addCustomEqualityTester(tester);
5516 };
5517
5518 /**
5519 * Add custom matchers for the current scope of specs.
5520 *
5521 * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
5522 * @name jasmine.addMatchers
5523 * @function
5524 * @param {Object} matchers - Keys from this object will be the new matcher names.
5525 * @see custom_matcher
5526 */
5527 jasmine.addMatchers = function(matchers) {
5528 return env.addMatchers(matchers);
5529 };
5530
5531 /**
5532 * Get the currently booted mock {Clock} for this Jasmine environment.
5533 * @name jasmine.clock
5534 * @function
5535 * @returns {Clock}
5536 */
5537 jasmine.clock = function() {
5538 return env.clock;
5539 };
5540
5541 /**
5542 * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
5543 * @name jasmine.createSpy
5544 * @function
5545 * @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
5546 * @param {Function} [originalFn] - Function to act as the real implementation.
5547 * @return {Spy}
5548 */
5549 jasmine.createSpy = function(name, originalFn) {
5550 return env.createSpy(name, originalFn);
5551 };
5552
5553 /**
5554 * Create an object with multiple {@link Spy}s as its members.
5555 * @name jasmine.createSpyObj
5556 * @function
5557 * @param {String} [baseName] - Base name for the spies in the object.
5558 * @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
5559 * @return {Object}
5560 */
5561 jasmine.createSpyObj = function(baseName, methodNames) {
5562 return env.createSpyObj(baseName, methodNames);
5563 };
5564
5565 /**
5566 * Add a custom spy strategy for the current scope of specs.
5567 *
5568 * _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
5569 * @name jasmine.addSpyStrategy
5570 * @function
5571 * @param {String} name - The name of the strategy (i.e. what you call from `and`)
5572 * @param {Function} factory - Factory function that returns the plan to be executed.
5573 */
5574 jasmine.addSpyStrategy = function(name, factory) {
5575 return env.addSpyStrategy(name, factory);
5576 };
5577
5578 return jasmineInterface;
5579};
5580
5581getJasmineRequireObj().Spy = function (j$) {
5582
5583 var nextOrder = (function() {
5584 var order = 0;
5585
5586 return function() {
5587 return order++;
5588 };
5589 })();
5590
5591 /**
5592 * _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
5593 * @constructor
5594 * @name Spy
5595 */
5596 function Spy(name, originalFn, customStrategies) {
5597 var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
5598 wrapper = makeFunc(numArgs, function () {
5599 return spy.apply(this, Array.prototype.slice.call(arguments));
5600 }),
5601 strategyDispatcher = new SpyStrategyDispatcher({
5602 name: name,
5603 fn: originalFn,
5604 getSpy: function () {
5605 return wrapper;
5606 },
5607 customStrategies: customStrategies
5608 }),
5609 callTracker = new j$.CallTracker(),
5610 spy = function () {
5611 /**
5612 * @name Spy.callData
5613 * @property {object} object - `this` context for the invocation.
5614 * @property {number} invocationOrder - Order of the invocation.
5615 * @property {Array} args - The arguments passed for this invocation.
5616 */
5617 var callData = {
5618 object: this,
5619 invocationOrder: nextOrder(),
5620 args: Array.prototype.slice.apply(arguments)
5621 };
5622
5623 callTracker.track(callData);
5624 var returnValue = strategyDispatcher.exec(this, arguments);
5625 callData.returnValue = returnValue;
5626
5627 return returnValue;
5628 };
5629
5630 function makeFunc(length, fn) {
5631 switch (length) {
5632 case 1 : return function (a) { return fn.apply(this, arguments); };
5633 case 2 : return function (a,b) { return fn.apply(this, arguments); };
5634 case 3 : return function (a,b,c) { return fn.apply(this, arguments); };
5635 case 4 : return function (a,b,c,d) { return fn.apply(this, arguments); };
5636 case 5 : return function (a,b,c,d,e) { return fn.apply(this, arguments); };
5637 case 6 : return function (a,b,c,d,e,f) { return fn.apply(this, arguments); };
5638 case 7 : return function (a,b,c,d,e,f,g) { return fn.apply(this, arguments); };
5639 case 8 : return function (a,b,c,d,e,f,g,h) { return fn.apply(this, arguments); };
5640 case 9 : return function (a,b,c,d,e,f,g,h,i) { return fn.apply(this, arguments); };
5641 default : return function () { return fn.apply(this, arguments); };
5642 }
5643 }
5644
5645 for (var prop in originalFn) {
5646 if (prop === 'and' || prop === 'calls') {
5647 throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
5648 }
5649
5650 wrapper[prop] = originalFn[prop];
5651 }
5652
5653 /**
5654 * @member {SpyStrategy} - Accesses the default strategy for the spy. This strategy will be used
5655 * whenever the spy is called with arguments that don't match any strategy
5656 * created with {@link Spy#withArgs}.
5657 * @name Spy#and
5658 * @example
5659 * spyOn(someObj, 'func').and.returnValue(42);
5660 */
5661 wrapper.and = strategyDispatcher.and;
5662 /**
5663 * Specifies a strategy to be used for calls to the spy that have the
5664 * specified arguments.
5665 * @name Spy#withArgs
5666 * @function
5667 * @param {...*} args - The arguments to match
5668 * @type {SpyStrategy}
5669 * @example
5670 * spyOn(someObj, 'func').withArgs(1, 2, 3).and.returnValue(42);
5671 * someObj.func(1, 2, 3); // returns 42
5672 */
5673 wrapper.withArgs = function() {
5674 return strategyDispatcher.withArgs.apply(strategyDispatcher, arguments);
5675 };
5676 wrapper.calls = callTracker;
5677
5678 return wrapper;
5679 }
5680
5681
5682 function SpyStrategyDispatcher(strategyArgs) {
5683 var baseStrategy = new j$.SpyStrategy(strategyArgs);
5684 var argsStrategies = new StrategyDict(function() {
5685 return new j$.SpyStrategy(strategyArgs);
5686 });
5687
5688 this.and = baseStrategy;
5689
5690 this.exec = function(spy, args) {
5691 var strategy = argsStrategies.get(args);
5692
5693 if (!strategy) {
5694 if (argsStrategies.any() && !baseStrategy.isConfigured()) {
5695 throw new Error('Spy \'' + strategyArgs.name + '\' receieved a call with arguments ' + j$.pp(Array.prototype.slice.call(args)) + ' but all configured strategies specify other arguments.');
5696 } else {
5697 strategy = baseStrategy;
5698 }
5699 }
5700
5701 return strategy.exec(spy, args);
5702 };
5703
5704 this.withArgs = function() {
5705 return { and: argsStrategies.getOrCreate(arguments) };
5706 };
5707 }
5708
5709 function StrategyDict(strategyFactory) {
5710 this.strategies = [];
5711 this.strategyFactory = strategyFactory;
5712 }
5713
5714 StrategyDict.prototype.any = function() {
5715 return this.strategies.length > 0;
5716 };
5717
5718 StrategyDict.prototype.getOrCreate = function(args) {
5719 var strategy = this.get(args);
5720
5721 if (!strategy) {
5722 strategy = this.strategyFactory();
5723 this.strategies.push({
5724 args: args,
5725 strategy: strategy
5726 });
5727 }
5728
5729 return strategy;
5730 };
5731
5732 StrategyDict.prototype.get = function(args) {
5733 var i;
5734
5735 for (i = 0; i < this.strategies.length; i++) {
5736 if (j$.matchersUtil.equals(args, this.strategies[i].args)) {
5737 return this.strategies[i].strategy;
5738 }
5739 }
5740 };
5741
5742 return Spy;
5743};
5744
5745getJasmineRequireObj().SpyFactory = function(j$) {
5746
5747 function SpyFactory(getCustomStrategies) {
5748 var self = this;
5749
5750 this.createSpy = function(name, originalFn) {
5751 return j$.Spy(name, originalFn, getCustomStrategies());
5752 };
5753
5754 this.createSpyObj = function(baseName, methodNames) {
5755 var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
5756
5757 if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
5758 methodNames = baseName;
5759 baseName = 'unknown';
5760 }
5761
5762 var obj = {};
5763 var spiesWereSet = false;
5764
5765 if (j$.isArray_(methodNames)) {
5766 for (var i = 0; i < methodNames.length; i++) {
5767 obj[methodNames[i]] = self.createSpy(baseName + '.' + methodNames[i]);
5768 spiesWereSet = true;
5769 }
5770 } else if (j$.isObject_(methodNames)) {
5771 for (var key in methodNames) {
5772 if (methodNames.hasOwnProperty(key)) {
5773 obj[key] = self.createSpy(baseName + '.' + key);
5774 obj[key].and.returnValue(methodNames[key]);
5775 spiesWereSet = true;
5776 }
5777 }
5778 }
5779
5780 if (!spiesWereSet) {
5781 throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
5782 }
5783
5784 return obj;
5785 };
5786 }
5787
5788 return SpyFactory;
5789};
5790
5791getJasmineRequireObj().SpyRegistry = function(j$) {
5792
5793 var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
5794
5795 function SpyRegistry(options) {
5796 options = options || {};
5797 var global = options.global || j$.getGlobal();
5798 var createSpy = options.createSpy;
5799 var currentSpies = options.currentSpies || function() { return []; };
5800
5801 this.allowRespy = function(allow){
5802 this.respy = allow;
5803 };
5804
5805 this.spyOn = function(obj, methodName) {
5806
5807 if (j$.util.isUndefined(obj) || obj === null) {
5808 throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
5809 }
5810
5811 if (j$.util.isUndefined(methodName) || methodName === null) {
5812 throw new Error(getErrorMsg('No method name supplied'));
5813 }
5814
5815 if (j$.util.isUndefined(obj[methodName])) {
5816 throw new Error(getErrorMsg(methodName + '() method does not exist'));
5817 }
5818
5819 if (obj[methodName] && j$.isSpy(obj[methodName]) ) {
5820 if ( !!this.respy ){
5821 return obj[methodName];
5822 }else {
5823 throw new Error(getErrorMsg(methodName + ' has already been spied upon'));
5824 }
5825 }
5826
5827 var descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
5828
5829 if (descriptor && !(descriptor.writable || descriptor.set)) {
5830 throw new Error(getErrorMsg(methodName + ' is not declared writable or has no setter'));
5831 }
5832
5833 var originalMethod = obj[methodName],
5834 spiedMethod = createSpy(methodName, originalMethod),
5835 restoreStrategy;
5836
5837 if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
5838 restoreStrategy = function() {
5839 obj[methodName] = originalMethod;
5840 };
5841 } else {
5842 restoreStrategy = function() {
5843 if (!delete obj[methodName]) {
5844 obj[methodName] = originalMethod;
5845 }
5846 };
5847 }
5848
5849 currentSpies().push({
5850 restoreObjectToOriginalState: restoreStrategy
5851 });
5852
5853 obj[methodName] = spiedMethod;
5854
5855 return spiedMethod;
5856 };
5857
5858 this.spyOnProperty = function (obj, propertyName, accessType) {
5859 accessType = accessType || 'get';
5860
5861 if (j$.util.isUndefined(obj)) {
5862 throw new Error('spyOn could not find an object to spy upon for ' + propertyName + '');
5863 }
5864
5865 if (j$.util.isUndefined(propertyName)) {
5866 throw new Error('No property name supplied');
5867 }
5868
5869 var descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
5870
5871 if (!descriptor) {
5872 throw new Error(propertyName + ' property does not exist');
5873 }
5874
5875 if (!descriptor.configurable) {
5876 throw new Error(propertyName + ' is not declared configurable');
5877 }
5878
5879 if(!descriptor[accessType]) {
5880 throw new Error('Property ' + propertyName + ' does not have access type ' + accessType);
5881 }
5882
5883 if (j$.isSpy(descriptor[accessType])) {
5884 //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
5885 throw new Error(propertyName + ' has already been spied upon');
5886 }
5887
5888 var originalDescriptor = j$.util.clone(descriptor),
5889 spy = createSpy(propertyName, descriptor[accessType]),
5890 restoreStrategy;
5891
5892 if (Object.prototype.hasOwnProperty.call(obj, propertyName)) {
5893 restoreStrategy = function() {
5894 Object.defineProperty(obj, propertyName, originalDescriptor);
5895 };
5896 } else {
5897 restoreStrategy = function() {
5898 delete obj[propertyName];
5899 };
5900 }
5901
5902 currentSpies().push({
5903 restoreObjectToOriginalState: restoreStrategy
5904 });
5905
5906 descriptor[accessType] = spy;
5907
5908 Object.defineProperty(obj, propertyName, descriptor);
5909
5910 return spy;
5911 };
5912
5913 this.spyOnAllFunctions = function(obj) {
5914 if (j$.util.isUndefined(obj)) {
5915 throw new Error('spyOnAllFunctions could not find an object to spy upon');
5916 }
5917
5918 for (var prop in obj) {
5919 if (Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] instanceof Function) {
5920 var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
5921 if ((descriptor.writable || descriptor.set) && descriptor.configurable) {
5922 this.spyOn(obj, prop);
5923 }
5924 }
5925 }
5926
5927 return obj;
5928 };
5929
5930 this.clearSpies = function() {
5931 var spies = currentSpies();
5932 for (var i = spies.length - 1; i >= 0; i--) {
5933 var spyEntry = spies[i];
5934 spyEntry.restoreObjectToOriginalState();
5935 }
5936 };
5937 }
5938
5939 return SpyRegistry;
5940};
5941
5942getJasmineRequireObj().SpyStrategy = function(j$) {
5943
5944 /**
5945 * @interface SpyStrategy
5946 */
5947 function SpyStrategy(options) {
5948 options = options || {};
5949
5950 /**
5951 * Get the identifying information for the spy.
5952 * @name SpyStrategy#identity
5953 * @member
5954 * @type {String}
5955 */
5956 this.identity = options.name || 'unknown';
5957 this.originalFn = options.fn || function() {};
5958 this.getSpy = options.getSpy || function() {};
5959 this.plan = this._defaultPlan = function() {};
5960
5961 var k, cs = options.customStrategies || {};
5962 for (k in cs) {
5963 if (j$.util.has(cs, k) && !this[k]) {
5964 this[k] = createCustomPlan(cs[k]);
5965 }
5966 }
5967 }
5968
5969 function createCustomPlan(factory) {
5970 return function() {
5971 var plan = factory.apply(null, arguments);
5972
5973 if (!j$.isFunction_(plan)) {
5974 throw new Error('Spy strategy must return a function');
5975 }
5976
5977 this.plan = plan;
5978 return this.getSpy();
5979 };
5980 }
5981
5982 /**
5983 * Execute the current spy strategy.
5984 * @name SpyStrategy#exec
5985 * @function
5986 */
5987 SpyStrategy.prototype.exec = function(context, args) {
5988 return this.plan.apply(context, args);
5989 };
5990
5991 /**
5992 * Tell the spy to call through to the real implementation when invoked.
5993 * @name SpyStrategy#callThrough
5994 * @function
5995 */
5996 SpyStrategy.prototype.callThrough = function() {
5997 this.plan = this.originalFn;
5998 return this.getSpy();
5999 };
6000
6001 /**
6002 * Tell the spy to return the value when invoked.
6003 * @name SpyStrategy#returnValue
6004 * @function
6005 * @param {*} value The value to return.
6006 */
6007 SpyStrategy.prototype.returnValue = function(value) {
6008 this.plan = function() {
6009 return value;
6010 };
6011 return this.getSpy();
6012 };
6013
6014 /**
6015 * Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
6016 * @name SpyStrategy#returnValues
6017 * @function
6018 * @param {...*} values - Values to be returned on subsequent calls to the spy.
6019 */
6020 SpyStrategy.prototype.returnValues = function() {
6021 var values = Array.prototype.slice.call(arguments);
6022 this.plan = function () {
6023 return values.shift();
6024 };
6025 return this.getSpy();
6026 };
6027
6028 /**
6029 * Tell the spy to throw an error when invoked.
6030 * @name SpyStrategy#throwError
6031 * @function
6032 * @param {Error|String} something Thing to throw
6033 */
6034 SpyStrategy.prototype.throwError = function(something) {
6035 var error = (something instanceof Error) ? something : new Error(something);
6036 this.plan = function() {
6037 throw error;
6038 };
6039 return this.getSpy();
6040 };
6041
6042 /**
6043 * Tell the spy to call a fake implementation when invoked.
6044 * @name SpyStrategy#callFake
6045 * @function
6046 * @param {Function} fn The function to invoke with the passed parameters.
6047 */
6048 SpyStrategy.prototype.callFake = function(fn) {
6049 if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
6050 throw new Error('Argument passed to callFake should be a function, got ' + fn);
6051 }
6052 this.plan = fn;
6053 return this.getSpy();
6054 };
6055
6056 /**
6057 * Tell the spy to do nothing when invoked. This is the default.
6058 * @name SpyStrategy#stub
6059 * @function
6060 */
6061 SpyStrategy.prototype.stub = function(fn) {
6062 this.plan = function() {};
6063 return this.getSpy();
6064 };
6065
6066 SpyStrategy.prototype.isConfigured = function() {
6067 return this.plan !== this._defaultPlan;
6068 };
6069
6070 return SpyStrategy;
6071};
6072
6073getJasmineRequireObj().StackTrace = function(j$) {
6074 function StackTrace(error) {
6075 var lines = error.stack
6076 .split('\n')
6077 .filter(function(line) { return line !== ''; });
6078
6079 var extractResult = extractMessage(error.message, lines);
6080
6081 if (extractResult) {
6082 this.message = extractResult.message;
6083 lines = extractResult.remainder;
6084 }
6085
6086 var parseResult = tryParseFrames(lines);
6087 this.frames = parseResult.frames;
6088 this.style = parseResult.style;
6089 }
6090
6091 var framePatterns = [
6092 // PhantomJS on Linux, Node, Chrome, IE, Edge
6093 // e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)"
6094 // Note that the "function name" can include a surprisingly large set of
6095 // characters, including angle brackets and square brackets.
6096 { re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, fnIx: 1, fileLineColIx: 2, style: 'v8' },
6097
6098 // NodeJS alternate form, often mixed in with the Chrome style
6099 // e.g. " at /some/path:4320:20
6100 { re: /\s*at (.+)$/, fileLineColIx: 1, style: 'v8' },
6101
6102 // PhantomJS on OS X, Safari, Firefox
6103 // e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
6104 // or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
6105 { re: /^(([^@\s]+)@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' }
6106 ];
6107
6108 // regexes should capture the function name (if any) as group 1
6109 // and the file, line, and column as group 2.
6110 function tryParseFrames(lines) {
6111 var style = null;
6112 var frames = lines.map(function(line) {
6113 var convertedLine = first(framePatterns, function(pattern) {
6114 var overallMatch = line.match(pattern.re),
6115 fileLineColMatch;
6116 if (!overallMatch) { return null; }
6117
6118 fileLineColMatch = overallMatch[pattern.fileLineColIx].match(
6119 /^(.*):(\d+):\d+$/);
6120 if (!fileLineColMatch) { return null; }
6121
6122 style = style || pattern.style;
6123 return {
6124 raw: line,
6125 file: fileLineColMatch[1],
6126 line: parseInt(fileLineColMatch[2], 10),
6127 func: overallMatch[pattern.fnIx]
6128 };
6129 });
6130
6131 return convertedLine || { raw: line };
6132 });
6133
6134 return {
6135 style: style,
6136 frames: frames
6137 };
6138 }
6139
6140 function first(items, fn) {
6141 var i, result;
6142
6143 for (i = 0; i < items.length; i++) {
6144 result = fn(items[i]);
6145
6146 if (result) {
6147 return result;
6148 }
6149 }
6150 }
6151
6152 function extractMessage(message, stackLines) {
6153 var len = messagePrefixLength(message, stackLines);
6154
6155 if (len > 0) {
6156 return {
6157 message: stackLines.slice(0, len).join('\n'),
6158 remainder: stackLines.slice(len)
6159 };
6160 }
6161 }
6162
6163 function messagePrefixLength(message, stackLines) {
6164 if (!stackLines[0].match(/^Error/)) {
6165 return 0;
6166 }
6167
6168 var messageLines = message.split('\n');
6169 var i;
6170
6171 for (i = 1; i < messageLines.length; i++) {
6172 if (messageLines[i] !== stackLines[i]) {
6173 return 0;
6174 }
6175 }
6176
6177 return messageLines.length;
6178 }
6179
6180 return StackTrace;
6181};
6182
6183getJasmineRequireObj().Suite = function(j$) {
6184 function Suite(attrs) {
6185 this.env = attrs.env;
6186 this.id = attrs.id;
6187 this.parentSuite = attrs.parentSuite;
6188 this.description = attrs.description;
6189 this.expectationFactory = attrs.expectationFactory;
6190 this.asyncExpectationFactory = attrs.asyncExpectationFactory;
6191 this.expectationResultFactory = attrs.expectationResultFactory;
6192 this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
6193
6194 this.beforeFns = [];
6195 this.afterFns = [];
6196 this.beforeAllFns = [];
6197 this.afterAllFns = [];
6198
6199 this.children = [];
6200
6201 /**
6202 * @typedef SuiteResult
6203 * @property {Int} id - The unique id of this suite.
6204 * @property {String} description - The description text passed to the {@link describe} that made this suite.
6205 * @property {String} fullName - The full description including all ancestors of this suite.
6206 * @property {Expectation[]} failedExpectations - The list of expectations that failed in an {@link afterAll} for this suite.
6207 * @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
6208 * @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
6209 */
6210 this.result = {
6211 id: this.id,
6212 description: this.description,
6213 fullName: this.getFullName(),
6214 failedExpectations: [],
6215 deprecationWarnings: []
6216 };
6217 }
6218
6219 Suite.prototype.expect = function(actual) {
6220 return this.expectationFactory(actual, this);
6221 };
6222
6223 Suite.prototype.expectAsync = function(actual) {
6224 return this.asyncExpectationFactory(actual, this);
6225 };
6226
6227 Suite.prototype.getFullName = function() {
6228 var fullName = [];
6229 for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
6230 if (parentSuite.parentSuite) {
6231 fullName.unshift(parentSuite.description);
6232 }
6233 }
6234 return fullName.join(' ');
6235 };
6236
6237 Suite.prototype.pend = function() {
6238 this.markedPending = true;
6239 };
6240
6241 Suite.prototype.beforeEach = function(fn) {
6242 this.beforeFns.unshift(fn);
6243 };
6244
6245 Suite.prototype.beforeAll = function(fn) {
6246 this.beforeAllFns.push(fn);
6247 };
6248
6249 Suite.prototype.afterEach = function(fn) {
6250 this.afterFns.unshift(fn);
6251 };
6252
6253 Suite.prototype.afterAll = function(fn) {
6254 this.afterAllFns.unshift(fn);
6255 };
6256
6257 function removeFns(queueableFns) {
6258 for(var i = 0; i < queueableFns.length; i++) {
6259 queueableFns[i].fn = null;
6260 }
6261 }
6262
6263 Suite.prototype.cleanupBeforeAfter = function() {
6264 removeFns(this.beforeAllFns);
6265 removeFns(this.afterAllFns);
6266 removeFns(this.beforeFns);
6267 removeFns(this.afterFns);
6268 };
6269
6270 Suite.prototype.addChild = function(child) {
6271 this.children.push(child);
6272 };
6273
6274 Suite.prototype.status = function() {
6275 if (this.markedPending) {
6276 return 'pending';
6277 }
6278
6279 if (this.result.failedExpectations.length > 0) {
6280 return 'failed';
6281 } else {
6282 return 'passed';
6283 }
6284 };
6285
6286 Suite.prototype.canBeReentered = function() {
6287 return this.beforeAllFns.length === 0 && this.afterAllFns.length === 0;
6288 };
6289
6290 Suite.prototype.getResult = function() {
6291 this.result.status = this.status();
6292 return this.result;
6293 };
6294
6295 Suite.prototype.sharedUserContext = function() {
6296 if (!this.sharedContext) {
6297 this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
6298 }
6299
6300 return this.sharedContext;
6301 };
6302
6303 Suite.prototype.clonedSharedUserContext = function() {
6304 return j$.UserContext.fromExisting(this.sharedUserContext());
6305 };
6306
6307 Suite.prototype.onException = function() {
6308 if (arguments[0] instanceof j$.errors.ExpectationFailed) {
6309 return;
6310 }
6311
6312 var data = {
6313 matcherName: '',
6314 passed: false,
6315 expected: '',
6316 actual: '',
6317 error: arguments[0]
6318 };
6319 var failedExpectation = this.expectationResultFactory(data);
6320
6321 if (!this.parentSuite) {
6322 failedExpectation.globalErrorType = 'afterAll';
6323 }
6324
6325 this.result.failedExpectations.push(failedExpectation);
6326 };
6327
6328 Suite.prototype.addExpectationResult = function () {
6329 if(isFailure(arguments)) {
6330 var data = arguments[1];
6331 this.result.failedExpectations.push(this.expectationResultFactory(data));
6332 if(this.throwOnExpectationFailure) {
6333 throw new j$.errors.ExpectationFailed();
6334 }
6335 }
6336 };
6337
6338 Suite.prototype.addDeprecationWarning = function(deprecation) {
6339 if (typeof deprecation === 'string') {
6340 deprecation = { message: deprecation };
6341 }
6342 this.result.deprecationWarnings.push(this.expectationResultFactory(deprecation));
6343 };
6344
6345 function isFailure(args) {
6346 return !args[0];
6347 }
6348
6349 return Suite;
6350};
6351
6352if (typeof window == void 0 && typeof exports == 'object') {
6353 /* globals exports */
6354 exports.Suite = jasmineRequire.Suite;
6355}
6356
6357getJasmineRequireObj().Timer = function() {
6358 var defaultNow = (function(Date) {
6359 return function() { return new Date().getTime(); };
6360 })(Date);
6361
6362 function Timer(options) {
6363 options = options || {};
6364
6365 var now = options.now || defaultNow,
6366 startTime;
6367
6368 this.start = function() {
6369 startTime = now();
6370 };
6371
6372 this.elapsed = function() {
6373 return now() - startTime;
6374 };
6375 }
6376
6377 return Timer;
6378};
6379
6380getJasmineRequireObj().TreeProcessor = function() {
6381 function TreeProcessor(attrs) {
6382 var tree = attrs.tree,
6383 runnableIds = attrs.runnableIds,
6384 queueRunnerFactory = attrs.queueRunnerFactory,
6385 nodeStart = attrs.nodeStart || function() {},
6386 nodeComplete = attrs.nodeComplete || function() {},
6387 orderChildren = attrs.orderChildren || function(node) { return node.children; },
6388 excludeNode = attrs.excludeNode || function(node) { return false; },
6389 stats = { valid: true },
6390 processed = false,
6391 defaultMin = Infinity,
6392 defaultMax = 1 - Infinity;
6393
6394 this.processTree = function() {
6395 processNode(tree, true);
6396 processed = true;
6397 return stats;
6398 };
6399
6400 this.execute = function(done) {
6401 if (!processed) {
6402 this.processTree();
6403 }
6404
6405 if (!stats.valid) {
6406 throw 'invalid order';
6407 }
6408
6409 var childFns = wrapChildren(tree, 0);
6410
6411 queueRunnerFactory({
6412 queueableFns: childFns,
6413 userContext: tree.sharedUserContext(),
6414 onException: function() {
6415 tree.onException.apply(tree, arguments);
6416 },
6417 onComplete: done
6418 });
6419 };
6420
6421 function runnableIndex(id) {
6422 for (var i = 0; i < runnableIds.length; i++) {
6423 if (runnableIds[i] === id) {
6424 return i;
6425 }
6426 }
6427 }
6428
6429 function processNode(node, parentExcluded) {
6430 var executableIndex = runnableIndex(node.id);
6431
6432 if (executableIndex !== undefined) {
6433 parentExcluded = false;
6434 }
6435
6436 if (!node.children) {
6437 var excluded = parentExcluded || excludeNode(node);
6438 stats[node.id] = {
6439 excluded: excluded,
6440 willExecute: !excluded && !node.markedPending,
6441 segments: [{
6442 index: 0,
6443 owner: node,
6444 nodes: [node],
6445 min: startingMin(executableIndex),
6446 max: startingMax(executableIndex)
6447 }]
6448 };
6449 } else {
6450 var hasExecutableChild = false;
6451
6452 var orderedChildren = orderChildren(node);
6453
6454 for (var i = 0; i < orderedChildren.length; i++) {
6455 var child = orderedChildren[i];
6456
6457 processNode(child, parentExcluded);
6458
6459 if (!stats.valid) {
6460 return;
6461 }
6462
6463 var childStats = stats[child.id];
6464
6465 hasExecutableChild = hasExecutableChild || childStats.willExecute;
6466 }
6467
6468 stats[node.id] = {
6469 excluded: parentExcluded,
6470 willExecute: hasExecutableChild
6471 };
6472
6473 segmentChildren(node, orderedChildren, stats[node.id], executableIndex);
6474
6475 if (!node.canBeReentered() && stats[node.id].segments.length > 1) {
6476 stats = { valid: false };
6477 }
6478 }
6479 }
6480
6481 function startingMin(executableIndex) {
6482 return executableIndex === undefined ? defaultMin : executableIndex;
6483 }
6484
6485 function startingMax(executableIndex) {
6486 return executableIndex === undefined ? defaultMax : executableIndex;
6487 }
6488
6489 function segmentChildren(node, orderedChildren, nodeStats, executableIndex) {
6490 var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
6491 result = [currentSegment],
6492 lastMax = defaultMax,
6493 orderedChildSegments = orderChildSegments(orderedChildren);
6494
6495 function isSegmentBoundary(minIndex) {
6496 return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
6497 }
6498
6499 for (var i = 0; i < orderedChildSegments.length; i++) {
6500 var childSegment = orderedChildSegments[i],
6501 maxIndex = childSegment.max,
6502 minIndex = childSegment.min;
6503
6504 if (isSegmentBoundary(minIndex)) {
6505 currentSegment = {index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax};
6506 result.push(currentSegment);
6507 }
6508
6509 currentSegment.nodes.push(childSegment);
6510 currentSegment.min = Math.min(currentSegment.min, minIndex);
6511 currentSegment.max = Math.max(currentSegment.max, maxIndex);
6512 lastMax = maxIndex;
6513 }
6514
6515 nodeStats.segments = result;
6516 }
6517
6518 function orderChildSegments(children) {
6519 var specifiedOrder = [],
6520 unspecifiedOrder = [];
6521
6522 for (var i = 0; i < children.length; i++) {
6523 var child = children[i],
6524 segments = stats[child.id].segments;
6525
6526 for (var j = 0; j < segments.length; j++) {
6527 var seg = segments[j];
6528
6529 if (seg.min === defaultMin) {
6530 unspecifiedOrder.push(seg);
6531 } else {
6532 specifiedOrder.push(seg);
6533 }
6534 }
6535 }
6536
6537 specifiedOrder.sort(function(a, b) {
6538 return a.min - b.min;
6539 });
6540
6541 return specifiedOrder.concat(unspecifiedOrder);
6542 }
6543
6544 function executeNode(node, segmentNumber) {
6545 if (node.children) {
6546 return {
6547 fn: function(done) {
6548 var onStart = {
6549 fn: function(next) {
6550 nodeStart(node, next);
6551 }
6552 };
6553
6554 queueRunnerFactory({
6555 onComplete: function () {
6556 var args = Array.prototype.slice.call(arguments, [0]);
6557 node.cleanupBeforeAfter();
6558 nodeComplete(node, node.getResult(), function() {
6559 done.apply(undefined, args);
6560 });
6561 },
6562 queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
6563 userContext: node.sharedUserContext(),
6564 onException: function () {
6565 node.onException.apply(node, arguments);
6566 }
6567 });
6568 }
6569 };
6570 } else {
6571 return {
6572 fn: function(done) { node.execute(done, stats[node.id].excluded); }
6573 };
6574 }
6575 }
6576
6577 function wrapChildren(node, segmentNumber) {
6578 var result = [],
6579 segmentChildren = stats[node.id].segments[segmentNumber].nodes;
6580
6581 for (var i = 0; i < segmentChildren.length; i++) {
6582 result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
6583 }
6584
6585 if (!stats[node.id].willExecute) {
6586 return result;
6587 }
6588
6589 return node.beforeAllFns.concat(result).concat(node.afterAllFns);
6590 }
6591 }
6592
6593 return TreeProcessor;
6594};
6595
6596getJasmineRequireObj().UserContext = function(j$) {
6597 function UserContext() {
6598 }
6599
6600 UserContext.fromExisting = function(oldContext) {
6601 var context = new UserContext();
6602
6603 for (var prop in oldContext) {
6604 if (oldContext.hasOwnProperty(prop)) {
6605 context[prop] = oldContext[prop];
6606 }
6607 }
6608
6609 return context;
6610 };
6611
6612 return UserContext;
6613};
6614
6615getJasmineRequireObj().version = function() {
6616 return '3.2.0';
6617};