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