source: pyenvjasmine/pyenvjasmine/envjasmine/lib/jasmine-3.1.0/jasmine.js@ 49:ce9136f79ee6

Last change on this file since 49:ce9136f79ee6 was 36:4c964b691922, checked in by Mauro Molino <mauro@…>, 7 years ago

Selectable engine (phantom with jasmine3, rhino with jasmine1)

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