UNPKG

jasminejsx

Version:

A port of Jasmine.js that is compatible with Adobe ExtendScript

1,550 lines (1,288 loc) 164 kB
/* Copyright (c) 2008-2017 Pivotal Labs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ var getJasmineRequireObj = (function (jasmineGlobal) { var jasmineRequire; if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') { if (typeof global !== 'undefined') { jasmineGlobal = global; } else { jasmineGlobal = {}; } jasmineRequire = exports; } else { if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') { jasmineGlobal = window; } jasmineRequire = jasmineGlobal.jasmineRequire = jasmineGlobal.jasmineRequire || {}; } function getJasmineRequire() { return jasmineRequire; } getJasmineRequire().core = function (jRequire) { var j$ = {}; jRequire.base(j$, jasmineGlobal); j$.util = jRequire.util(); j$.errors = jRequire.errors(); j$.formatErrorMsg = jRequire.formatErrorMsg(); j$.Any = jRequire.Any(j$); j$.Anything = jRequire.Anything(j$); j$.CallTracker = jRequire.CallTracker(j$); j$.MockDate = jRequire.MockDate(); j$.getClearStack = jRequire.clearStack(j$); j$.Clock = jRequire.Clock(); j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler(); j$.Env = jRequire.Env(j$); j$.ExceptionFormatter = jRequire.ExceptionFormatter(); j$.Expectation = jRequire.Expectation(); j$.buildExpectationResult = jRequire.buildExpectationResult(); j$.JsApiReporter = jRequire.JsApiReporter(); j$.matchersUtil = jRequire.matchersUtil(j$); j$.ObjectContaining = jRequire.ObjectContaining(j$); j$.ArrayContaining = jRequire.ArrayContaining(j$); j$.pp = jRequire.pp(j$); j$.QueueRunner = jRequire.QueueRunner(j$); j$.ReportDispatcher = jRequire.ReportDispatcher(); j$.Spec = jRequire.Spec(j$); j$.Spy = jRequire.Spy(j$); j$.SpyRegistry = jRequire.SpyRegistry(j$); j$.SpyStrategy = jRequire.SpyStrategy(j$); j$.StringMatching = jRequire.StringMatching(j$); j$.Suite = jRequire.Suite(j$); j$.Timer = jRequire.Timer(); j$.TreeProcessor = jRequire.TreeProcessor(); j$.version = jRequire.version(); j$.Order = jRequire.Order(); j$.DiffBuilder = jRequire.DiffBuilder(j$); j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$); j$.ObjectPath = jRequire.ObjectPath(j$); j$.GlobalErrors = jRequire.GlobalErrors(j$); j$.matchers = jRequire.requireMatchers(jRequire, j$); return j$; }; return getJasmineRequire; })(this); getJasmineRequireObj().requireMatchers = function (jRequire, j$) { var availableMatchers = [ 'toBe', 'toBeCloseTo', 'toBeDefined', 'toBeFalsy', 'toBeGreaterThan', 'toBeGreaterThanOrEqual', 'toBeLessThan', 'toBeLessThanOrEqual', 'toBeNaN', 'toBeNegativeInfinity', 'toBeNull', 'toBePositiveInfinity', 'toBeTruthy', 'toBeUndefined', 'toContain', 'toEqual', 'toHaveBeenCalled', 'toHaveBeenCalledBefore', 'toHaveBeenCalledTimes', 'toHaveBeenCalledWith', 'toMatch', 'toThrow', 'toThrowError' ], matchers = {}; for (var i = 0; i < availableMatchers.length; i++) { var name = availableMatchers[i]; matchers[name] = jRequire[name](j$); } return matchers; }; getJasmineRequireObj().base = function (j$, jasmineGlobal) { j$.unimplementedMethod_ = function () { throw new Error('unimplemented method'); }; /** * Maximum object depth the pretty printer will print to. * Set this to a lower value to speed up pretty printing if you have large objects. * @name jasmine.MAX_PRETTY_PRINT_DEPTH */ j$.MAX_PRETTY_PRINT_DEPTH = 40; /** * Maximum number of array elements to display when pretty printing objects. * Elements past this number will be ellipised. * @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH */ j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100; /** * Default number of milliseconds Jasmine will wait for an asynchronous spec to complete. * @name jasmine.DEFAULT_TIMEOUT_INTERVAL */ j$.DEFAULT_TIMEOUT_INTERVAL = 5000; j$.getGlobal = function () { return jasmineGlobal; }; /** * Get the currently booted Jasmine Environment. * * @name jasmine.getEnv * @function * @return {Env} */ j$.getEnv = function (options) { var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options); //jasmine. singletons in here (setTimeout blah blah). return env; }; j$.isArray_ = function (value) { return j$.isA_('Array', value); }; j$.isObject_ = function (value) { return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value); }; j$.isString_ = function (value) { return j$.isA_('String', value); }; j$.isNumber_ = function (value) { return j$.isA_('Number', value); }; j$.isFunction_ = function (value) { return j$.isA_('Function', value); }; j$.isA_ = function (typeName, value) { return j$.getType_(value) === '[object ' + typeName + ']'; }; j$.getType_ = function (value) { return Object.prototype.toString.apply(value); }; j$.isDomNode = function (obj) { return obj.nodeType > 0; }; j$.fnNameFor = function (func) { if (func.name) { return func.name; } var matches = func.toString().match(/^\s*function\s*(\w*)\s*\(/); return matches ? matches[1] : '<anonymous>'; }; /** * 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}), * that will succeed if the actual value being compared is an instance of the specified class/constructor. * @name jasmine.any * @function * @param {Constructor} clazz - The constructor to check against. */ j$.any = function (clazz) { return new j$.Any(clazz); }; /** * 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}), * that will succeed if the actual value being compared is not `null` and not `undefined`. * @name jasmine.anything * @function */ j$.anything = function () { return new j$.Anything(); }; /** * 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}), * that will succeed if the actual value being compared contains at least the keys and values. * @name jasmine.objectContaining * @function * @param {Object} sample - The subset of properties that _must_ be in the actual. */ j$.objectContaining = function (sample) { return new j$.ObjectContaining(sample); }; /** * 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}), * that will succeed if the actual value is a `String` that matches the `RegExp` or `String`. * @name jasmine.stringMatching * @function * @param {RegExp|String} expected */ j$.stringMatching = function (expected) { return new j$.StringMatching(expected); }; /** * 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}), * that will succeed if the actual value is an `Array` that contains at least the elements in the sample. * @name jasmine.arrayContaining * @function * @param {Array} sample */ j$.arrayContaining = function (sample) { return new j$.ArrayContaining(sample); }; /** * Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it. * @name jasmine.createSpy * @function * @param {String} [name] - Name to give the spy. This will be displayed in failure messages. * @param {Function} [originalFn] - Function to act as the real implementation. * @return {Spy} */ j$.createSpy = function (name, originalFn) { return j$.Spy(name, originalFn); }; j$.isSpy = function (putativeSpy) { if (!putativeSpy) { return false; } return putativeSpy.and instanceof j$.SpyStrategy && putativeSpy.calls instanceof j$.CallTracker; }; /** * Create an object with multiple {@link Spy}s as its members. * @name jasmine.createSpyObj * @function * @param {String} [baseName] - Base name for the spies in the object. * @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}. * @return {Object} */ j$.createSpyObj = function (baseName, methodNames) { var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName); if (baseNameIsCollection && j$.util.isUndefined(methodNames)) { methodNames = baseName; baseName = 'unknown'; } var obj = {}; var spiesWereSet = false; if (j$.isArray_(methodNames)) { for (var i = 0; i < methodNames.length; i++) { obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]); spiesWereSet = true; } } else if (j$.isObject_(methodNames)) { for (var key in methodNames) { if (methodNames.hasOwnProperty(key)) { obj[key] = j$.createSpy(baseName + '.' + key); obj[key].and.returnValue(methodNames[key]); spiesWereSet = true; } } } if (!spiesWereSet) { throw 'createSpyObj requires a non-empty array or object of method names to create spies for'; } return obj; }; }; getJasmineRequireObj().util = function () { var util = {}; util.inherit = function (childClass, parentClass) { var Subclass = function () { }; Subclass.prototype = parentClass.prototype; childClass.prototype = new Subclass(); }; util.htmlEscape = function (str) { if (!str) { return str; } return str.replace(/&/g, '&amp;') .replace(/</g, '&lt;') .replace(/>/g, '&gt;'); }; util.argsToArray = function (args) { var arrayOfArgs = []; for (var i = 0; i < args.length; i++) { arrayOfArgs.push(args[i]); } return arrayOfArgs; }; util.isUndefined = function (obj) { return obj === void 0; }; util.arrayContains = function (array, search) { var i = array.length; while (i--) { if (array[i] === search) { return true; } } return false; }; util.clone = function (obj) { if (Object.prototype.toString.apply(obj) === '[object Array]') { return obj.slice(); } var cloned = {}; for (var prop in obj) { if (obj.hasOwnProperty(prop)) { cloned[prop] = obj[prop]; } } return cloned; }; util.getPropertyDescriptor = function (obj, methodName) { var descriptor, proto = obj; do { descriptor = Object.getOwnPropertyDescriptor(proto, methodName); proto = Object.getPrototypeOf(proto); } while (!descriptor && proto); return descriptor; }; util.objectDifference = function (obj, toRemove) { var diff = {}; for (var key in obj) { if (util.has(obj, key) && !util.has(toRemove, key)) { diff[key] = obj[key]; } } return diff; }; util.has = function (obj, key) { return Object.prototype.hasOwnProperty.call(obj, key); }; return util; }; getJasmineRequireObj().Spec = function (j$) { function Spec(attrs) { this.expectationFactory = attrs.expectationFactory; this.resultCallback = attrs.resultCallback || function () { }; this.id = attrs.id; this.description = attrs.description || ''; this.queueableFn = attrs.queueableFn; this.beforeAndAfterFns = attrs.beforeAndAfterFns || function () { return { befores: [], afters: [] }; }; this.userContext = attrs.userContext || function () { return {}; }; this.onStart = attrs.onStart || function () { }; this.getSpecName = attrs.getSpecName || function () { return ''; }; this.expectationResultFactory = attrs.expectationResultFactory || function () { }; this.queueRunnerFactory = attrs.queueRunnerFactory || function () { }; this.catchingExceptions = attrs.catchingExceptions || function () { return true; }; this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure; if (!this.queueableFn.fn) { this.pend(); } this.result = { id: this.id, description: this.description, fullName: this.getFullName(), failedExpectations: [], passedExpectations: [], pendingReason: '' }; } Spec.prototype.addExpectationResult = function (passed, data, isError) { var expectationResult = this.expectationResultFactory(data); if (passed) { this.result.passedExpectations.push(expectationResult); } else { this.result.failedExpectations.push(expectationResult); if (this.throwOnExpectationFailure && !isError) { throw new j$.errors.ExpectationFailed(); } } }; Spec.prototype.expect = function (actual) { return this.expectationFactory(actual, this); }; Spec.prototype.execute = function (onComplete, enabled) { var self = this; this.onStart(this); if (!this.isExecutable() || this.markedPending || enabled === false) { complete(enabled); return; } var fns = this.beforeAndAfterFns(); var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters); this.queueRunnerFactory({ queueableFns: allFns, onException: function () { self.onException.apply(self, arguments); }, onComplete: complete, userContext: this.userContext() }); function complete(enabledAgain) { self.result.status = self.status(enabledAgain); self.resultCallback(self.result); if (onComplete) { onComplete(); } } }; Spec.prototype.onException = function onException(e) { if (Spec.isPendingSpecException(e)) { this.pend(extractCustomPendingMessage(e)); return; } if (e instanceof j$.errors.ExpectationFailed) { return; } this.addExpectationResult(false, { matcherName: '', passed: false, expected: '', actual: '', error: e }, true); }; Spec.prototype.disable = function () { this.disabled = true; }; Spec.prototype.pend = function (message) { this.markedPending = true; if (message) { this.result.pendingReason = message; } }; Spec.prototype.getResult = function () { this.result.status = this.status(); return this.result; }; Spec.prototype.status = function (enabled) { if (this.disabled || enabled === false) { return 'disabled'; } if (this.markedPending) { return 'pending'; } if (this.result.failedExpectations.length > 0) { return 'failed'; } else { return 'passed'; } }; Spec.prototype.isExecutable = function () { return !this.disabled; }; Spec.prototype.getFullName = function () { return this.getSpecName(this); }; var extractCustomPendingMessage = function (e) { var fullMessage = e.toString(), boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage), boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length; return fullMessage.substr(boilerplateEnd); }; Spec.pendingSpecExceptionMessage = '=> marked Pending'; Spec.isPendingSpecException = function (e) { return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1); }; return Spec; }; if (typeof window == void 0 && typeof exports == 'object') { exports.Spec = jasmineRequire.Spec; } /*jshint bitwise: false*/ getJasmineRequireObj().Order = function () { function Order(options) { this.random = 'random' in options ? options.random : true; var seed = this.seed = options.seed || generateSeed(); this.sort = this.random ? randomOrder : naturalOrder; function naturalOrder(items) { return items; } function randomOrder(items) { var copy = items.slice(); copy.sort(function (a, b) { return jenkinsHash(seed + a.id) - jenkinsHash(seed + b.id); }); return copy; } function generateSeed() { return String(Math.random()).slice(-5); } // Bob Jenkins One-at-a-Time Hash algorithm is a non-cryptographic hash function // used to get a different output when the key changes slighly. // We use your return to sort the children randomly in a consistent way when // used in conjunction with a seed function jenkinsHash(key) { var hash, i; for (hash = i = 0; i < key.length; ++i) { hash += key.charCodeAt(i); hash += (hash << 10); hash ^= (hash >> 6); } hash += (hash << 3); hash ^= (hash >> 11); hash += (hash << 15); return hash; } } return Order; }; getJasmineRequireObj().Env = function (j$) { /** * _Note:_ Do not construct this directly, Jasmine will make one during booting. * @name Env * @classdesc The Jasmine environment * @constructor */ function Env(options) { options = options || {}; var self = this; var global = options.global || j$.getGlobal(); var totalSpecsDefined = 0; var catchExceptions = true; var realSetTimeout = j$.getGlobal().setTimeout; var realClearTimeout = j$.getGlobal().clearTimeout; var clearStack = j$.getClearStack(j$.getGlobal()); this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global)); var runnableResources = {}; var currentSpec = null; var currentlyExecutingSuites = []; var currentDeclarationSuite = null; var throwOnExpectationFailure = false; var random = false; var seed = null; var currentSuite = function () { return currentlyExecutingSuites[currentlyExecutingSuites.length - 1]; }; var currentRunnable = function () { return currentSpec || currentSuite(); }; var reporter = new j$.ReportDispatcher([ 'jasmineStarted', 'jasmineDone', 'suiteStarted', 'suiteDone', 'specStarted', 'specDone' ]); var globalErrors = new j$.GlobalErrors(); this.specFilter = function () { return true; }; this.addCustomEqualityTester = function (tester) { if (!currentRunnable()) { throw new Error('Custom Equalities must be added in a before function or a spec'); } runnableResources[currentRunnable().id].customEqualityTesters.push(tester); }; this.addMatchers = function (matchersToAdd) { if (!currentRunnable()) { throw new Error('Matchers must be added in a before function or a spec'); } var customMatchers = runnableResources[currentRunnable().id].customMatchers; for (var matcherName in matchersToAdd) { customMatchers[matcherName] = matchersToAdd[matcherName]; } }; j$.Expectation.addCoreMatchers(j$.matchers); var nextSpecId = 0; var getNextSpecId = function () { return 'spec' + nextSpecId++; }; var nextSuiteId = 0; var getNextSuiteId = function () { return 'suite' + nextSuiteId++; }; var expectationFactory = function (actual, spec) { return j$.Expectation.Factory({ util: j$.matchersUtil, customEqualityTesters: runnableResources[spec.id].customEqualityTesters, customMatchers: runnableResources[spec.id].customMatchers, actual: actual, addExpectationResult: addExpectationResult }); function addExpectationResult(passed, result) { return spec.addExpectationResult(passed, result); } }; var defaultResourcesForRunnable = function (id, parentRunnableId) { var resources = { spies: [], customEqualityTesters: [], customMatchers: {} }; if (runnableResources[parentRunnableId]) { resources.customEqualityTesters = j$.util.clone(runnableResources[parentRunnableId].customEqualityTesters); resources.customMatchers = j$.util.clone(runnableResources[parentRunnableId].customMatchers); } runnableResources[id] = resources; }; var clearResourcesForRunnable = function (id) { spyRegistry.clearSpies(); delete runnableResources[id]; }; var beforeAndAfterFns = function (suite) { return function () { var befores = [], afters = []; while (suite) { befores = befores.concat(suite.beforeFns); afters = afters.concat(suite.afterFns); suite = suite.parentSuite; } return { befores: befores.reverse(), afters: afters }; }; }; var getSpecName = function (spec, suite) { var fullName = [spec.description], suiteFullName = suite.getFullName(); if (suiteFullName !== '') { fullName.unshift(suiteFullName); } return fullName.join(' '); }; // TODO: we may just be able to pass in the fn instead of wrapping here var buildExpectationResult = j$.buildExpectationResult, exceptionFormatter = new j$.ExceptionFormatter(), expectationResultFactory = function (attrs) { attrs.messageFormatter = exceptionFormatter.message; attrs.stackFormatter = exceptionFormatter.stack; return buildExpectationResult(attrs); }; // TODO: fix this naming, and here's where the value comes in this.catchExceptions = function (value) { catchExceptions = !!value; return catchExceptions; }; this.catchingExceptions = function () { return catchExceptions; }; var maximumSpecCallbackDepth = 20; var currentSpecCallbackDepth = 0; var catchException = function (e) { return j$.Spec.isPendingSpecException(e) || catchExceptions; }; this.throwOnExpectationFailure = function (value) { throwOnExpectationFailure = !!value; }; this.throwingExpectationFailures = function () { return throwOnExpectationFailure; }; this.randomizeTests = function (value) { random = !!value; }; this.randomTests = function () { return random; }; this.seed = function (value) { if (value) { seed = value; } return seed; }; var queueRunnerFactory = function (options) { options.catchException = catchException; options.clearStack = options.clearStack || clearStack; options.timeout = { setTimeout: realSetTimeout, clearTimeout: realClearTimeout }; options.fail = self.fail; options.globalErrors = globalErrors; new j$.QueueRunner(options).execute(); }; var topSuite = new j$.Suite({ env: this, id: getNextSuiteId(), description: 'Jasmine__TopLevel__Suite', expectationFactory: expectationFactory, expectationResultFactory: expectationResultFactory }); defaultResourcesForRunnable(topSuite.id); currentDeclarationSuite = topSuite; this.topSuite = function () { return topSuite; }; this.execute = function (runnablesToRun) { if (!runnablesToRun) { if (focusedRunnables.length) { runnablesToRun = focusedRunnables; } else { runnablesToRun = [topSuite.id]; } } var order = new j$.Order({ random: random, seed: seed }); var processor = new j$.TreeProcessor({ tree: topSuite, runnableIds: runnablesToRun, queueRunnerFactory: queueRunnerFactory, nodeStart: function (suite) { currentlyExecutingSuites.push(suite); defaultResourcesForRunnable(suite.id, suite.parentSuite.id); reporter.suiteStarted(suite.result); }, nodeComplete: function (suite, result) { if (suite !== currentSuite()) { throw new Error('Tried to complete the wrong suite'); } if (!suite.markedPending) { clearResourcesForRunnable(suite.id); } currentlyExecutingSuites.pop(); reporter.suiteDone(result); }, orderChildren: function (node) { return order.sort(node.children); } }); if (!processor.processTree().valid) { throw new Error('Invalid order: would cause a beforeAll or afterAll to be run multiple times'); } reporter.jasmineStarted({ totalSpecsDefined: totalSpecsDefined }); currentlyExecutingSuites.push(topSuite); globalErrors.install(); processor.execute(function () { clearResourcesForRunnable(topSuite.id); currentlyExecutingSuites.pop(); globalErrors.uninstall(); reporter.jasmineDone({ order: order, failedExpectations: topSuite.result.failedExpectations }); }); }; /** * Add a custom reporter to the Jasmine environment. * @name Env#addReporter * @function * @see custom_reporter */ this.addReporter = function (reporterToAdd) { reporter.addReporter(reporterToAdd); }; this.provideFallbackReporter = function (reporterToAdd) { reporter.provideFallbackReporter(reporterToAdd); }; this.clearReporters = function () { reporter.clearReporters(); }; var spyRegistry = new j$.SpyRegistry({ currentSpies: function () { if (!currentRunnable()) { throw new Error('Spies must be created in a before function or a spec'); } return runnableResources[currentRunnable().id].spies; } }); this.allowRespy = function (allow) { spyRegistry.allowRespy(allow); }; this.spyOn = function () { return spyRegistry.spyOn.apply(spyRegistry, arguments); }; this.spyOnProperty = function () { return spyRegistry.spyOnProperty.apply(spyRegistry, arguments); }; var ensureIsFunction = function (fn, caller) { if (!j$.isFunction_(fn)) { throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn)); } }; var suiteFactory = function (description) { var suite = new j$.Suite({ env: self, id: getNextSuiteId(), description: description, parentSuite: currentDeclarationSuite, expectationFactory: expectationFactory, expectationResultFactory: expectationResultFactory, throwOnExpectationFailure: throwOnExpectationFailure }); return suite; }; this.describe = function (description, specDefinitions) { ensureIsFunction(specDefinitions, 'describe'); var suite = suiteFactory(description); if (specDefinitions.length > 0) { throw new Error('describe does not expect any arguments'); } if (currentDeclarationSuite.markedPending) { suite.pend(); } addSpecsToSuite(suite, specDefinitions); return suite; }; this.xdescribe = function (description, specDefinitions) { ensureIsFunction(specDefinitions, 'xdescribe'); var suite = suiteFactory(description); suite.pend(); addSpecsToSuite(suite, specDefinitions); return suite; }; var focusedRunnables = []; this.fdescribe = function (description, specDefinitions) { ensureIsFunction(specDefinitions, 'fdescribe'); var suite = suiteFactory(description); suite.isFocused = true; focusedRunnables.push(suite.id); unfocusAncestor(); addSpecsToSuite(suite, specDefinitions); return suite; }; function addSpecsToSuite(suite, specDefinitions) { var parentSuite = currentDeclarationSuite; parentSuite.addChild(suite); currentDeclarationSuite = suite; var declarationError = null; try { specDefinitions.call(suite); } catch (e) { declarationError = e; } if (declarationError) { self.it('encountered a declaration exception', function () { throw declarationError; }); } currentDeclarationSuite = parentSuite; } function findFocusedAncestor(suite) { while (suite) { if (suite.isFocused) { return suite.id; } suite = suite.parentSuite; } return null; } function unfocusAncestor() { var focusedAncestor = findFocusedAncestor(currentDeclarationSuite); if (focusedAncestor) { for (var i = 0; i < focusedRunnables.length; i++) { if (focusedRunnables[i] === focusedAncestor) { focusedRunnables.splice(i, 1); break; } } } } var specFactory = function (description, fn, suite, timeout) { totalSpecsDefined++; var spec = new j$.Spec({ id: getNextSpecId(), beforeAndAfterFns: beforeAndAfterFns(suite), expectationFactory: expectationFactory, resultCallback: specResultCallback, getSpecName: function (spec) { return getSpecName(spec, suite); }, onStart: specStarted, description: description, expectationResultFactory: expectationResultFactory, queueRunnerFactory: queueRunnerFactory, userContext: function () { return suite.clonedSharedUserContext(); }, queueableFn: { fn: fn, timeout: function () { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } }, throwOnExpectationFailure: throwOnExpectationFailure }); if (!self.specFilter(spec)) { spec.disable(); } return spec; function specResultCallback(result) { clearResourcesForRunnable(spec.id); currentSpec = null; reporter.specDone(result); } function specStarted(spec) { currentSpec = spec; defaultResourcesForRunnable(spec.id, suite.id); reporter.specStarted(spec.result); } }; this.it = function (description, fn, timeout) { // it() sometimes doesn't have a fn argument, so only check the type if // it's given. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunction(fn, 'it'); } var spec = specFactory(description, fn, currentDeclarationSuite, timeout); if (currentDeclarationSuite.markedPending) { spec.pend(); } currentDeclarationSuite.addChild(spec); return spec; }; this.xit = function (description, fn, timeout) { // xit(), like it(), doesn't always have a fn argument, so only check the // type when needed. if (arguments.length > 1 && typeof fn !== 'undefined') { ensureIsFunction(fn, 'xit'); } var spec = this.it.apply(this, arguments); spec.pend('Temporarily disabled with xit'); return spec; }; this.fit = function (description, fn, timeout) { ensureIsFunction(fn, 'fit'); var spec = specFactory(description, fn, currentDeclarationSuite, timeout); currentDeclarationSuite.addChild(spec); focusedRunnables.push(spec.id); unfocusAncestor(); return spec; }; this.expect = function (actual) { if (!currentRunnable()) { throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out'); } return currentRunnable().expect(actual); }; this.beforeEach = function (beforeEachFunction, timeout) { ensureIsFunction(beforeEachFunction, 'beforeEach'); currentDeclarationSuite.beforeEach({ fn: beforeEachFunction, timeout: function () { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } }); }; this.beforeAll = function (beforeAllFunction, timeout) { ensureIsFunction(beforeAllFunction, 'beforeAll'); currentDeclarationSuite.beforeAll({ fn: beforeAllFunction, timeout: function () { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } }); }; this.afterEach = function (afterEachFunction, timeout) { ensureIsFunction(afterEachFunction, 'afterEach'); currentDeclarationSuite.afterEach({ fn: afterEachFunction, timeout: function () { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } }); }; this.afterAll = function (afterAllFunction, timeout) { ensureIsFunction(afterAllFunction, 'afterAll'); currentDeclarationSuite.afterAll({ fn: afterAllFunction, timeout: function () { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; } }); }; this.pending = function (message) { var fullMessage = j$.Spec.pendingSpecExceptionMessage; fullMessage += 'Pending' if (message) { fullMessage += ': '+message; } throw fullMessage; }; this.fail = function (error) { if (!currentRunnable()) { throw new Error('\'fail\' was used when there was no current spec, this could be because an asynchronous test timed out'); } var message = 'Failed'; if (error) { message += ': '; if (error.message) { message += error.message; } else if (jasmine.isString_(error)) { message += error; } else { // pretty print all kind of objects. This includes arrays. message += jasmine.pp(error); } } currentRunnable().addExpectationResult(false, { matcherName: '', passed: false, expected: '', actual: '', message: message, error: error && error.message ? error : null }); }; } return Env; }; getJasmineRequireObj().JsApiReporter = function () { var noopTimer = { start: function () { }, elapsed: function () { return 0; } }; /** * _Note:_ Do not construct this directly, use the global `jsApiReporter` to retrieve the instantiated object. * * @name jsApiReporter * @classdesc Reporter added by default in `boot.js` to record results for retrieval in javascript code. * @class */ function JsApiReporter(options) { var timer = options.timer || noopTimer, status = 'loaded'; this.started = false; this.finished = false; this.runDetails = {}; this.jasmineStarted = function () { this.started = true; status = 'started'; timer.start(); }; var executionTime; this.jasmineDone = function (runDetails) { this.finished = true; this.runDetails = runDetails; executionTime = timer.elapsed(); status = 'done'; }; /** * Get the current status for the Jasmine environment. * @name jsApiReporter#status * @function * @return {String} - One of `loaded`, `started`, or `done` */ this.status = function () { return status; }; var suites = [], suites_hash = {}; this.suiteStarted = function (result) { suites_hash[result.id] = result; }; this.suiteDone = function (result) { storeSuite(result); }; /** * Get the results for a set of suites. * * Retrievable in slices for easier serialization. * @name jsApiReporter#suiteResults * @function * @param {Number} index - The position in the suites list to start from. * @param {Number} length - Maximum number of suite results to return. * @return {Object[]} */ this.suiteResults = function (index, length) { return suites.slice(index, index + length); }; function storeSuite(result) { suites.push(result); suites_hash[result.id] = result; } /** * Get all of the suites in a single object, with their `id` as the key. * @name jsApiReporter#suites * @function * @return {Object} */ this.suites = function () { return suites_hash; }; var specs = []; this.specDone = function (result) { specs.push(result); }; /** * Get the results for a set of specs. * * Retrievable in slices for easier serialization. * @name jsApiReporter#specResults * @function * @param {Number} index - The position in the specs list to start from. * @param {Number} length - Maximum number of specs results to return. * @return {Object[]} */ this.specResults = function (index, length) { return specs.slice(index, index + length); }; /** * Get all spec results. * @name jsApiReporter#specs * @function * @return {Object[]} */ this.specs = function () { return specs; }; /** * Get the number of milliseconds it took for the full Jasmine suite to run. * @name jsApiReporter#executionTime * @function * @return {Number} */ this.executionTime = function () { return executionTime; }; } return JsApiReporter; }; getJasmineRequireObj().Any = function (j$) { function Any(expectedObject) { if (typeof expectedObject === 'undefined') { throw new TypeError( 'jasmine.any() expects to be passed a constructor function. ' + 'Please pass one or use jasmine.anything() to match any object.' ); } this.expectedObject = expectedObject; } Any.prototype.asymmetricMatch = function (other) { if (this.expectedObject == String) { return typeof other == 'string' || other instanceof String; } if (this.expectedObject == Number) { return typeof other == 'number' || other instanceof Number; } if (this.expectedObject == Function) { return typeof other == 'function' || other instanceof Function; } if (this.expectedObject == Object) { return typeof other == 'object'; } if (this.expectedObject == Boolean) { return typeof other == 'boolean'; } return other instanceof this.expectedObject; }; Any.prototype.jasmineToString = function () { return '<jasmine.any(' + j$.fnNameFor(this.expectedObject) + ')>'; }; return Any; }; getJasmineRequireObj().Anything = function (j$) { function Anything() { } Anything.prototype.asymmetricMatch = function (other) { return !j$.util.isUndefined(other) && other !== null; }; Anything.prototype.jasmineToString = function () { return '<jasmine.anything>'; }; return Anything; }; getJasmineRequireObj().ArrayContaining = function (j$) { function ArrayContaining(sample) { this.sample = sample; } ArrayContaining.prototype.asymmetricMatch = function (other, customTesters) { var className = Object.prototype.toString.call(this.sample); if (className !== '[object Array]') { throw new Error('You must provide an array to arrayContaining, not \'' + this.sample + '\'.'); } for (var i = 0; i < this.sample.length; i++) { var item = this.sample[i]; if (!j$.matchersUtil.contains(other, item, customTesters)) { return false; } } return true; }; ArrayContaining.prototype.jasmineToString = function () { return '<jasmine.arrayContaining(' + jasmine.pp(this.sample) + ')>'; }; return ArrayContaining; }; getJasmineRequireObj().ObjectContaining = function (j$) { function ObjectContaining(sample) { this.sample = sample; } function getPrototype(obj) { if (Object.getPrototypeOf) { return Object.getPrototypeOf(obj); } if (obj.constructor.prototype == obj) { return null; } return obj.constructor.prototype; } function hasProperty(obj, property) { if (!obj) { return false; } if (Object.prototype.hasOwnProperty.call(obj, property)) { return true; } return hasProperty(getPrototype(obj), property); } ObjectContaining.prototype.asymmetricMatch = function (other, customTesters) { if (typeof (this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \'' + this.sample + '\'.'); } for (var property in this.sample) { if (!hasProperty(other, property) || !j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) { return false; } } return true; }; ObjectContaining.prototype.jasmineToString = function () { return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>'; }; return ObjectContaining; }; getJasmineRequireObj().StringMatching = function (j$) { function StringMatching(expected) { if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) { throw new Error('Expected is not a String or a RegExp'); } this.regexp = new RegExp(expected); } StringMatching.prototype.asymmetricMatch = function (other) { return this.regexp.test(other); }; StringMatching.prototype.jasmineToString = function () { return '<jasmine.stringMatching(' + this.regexp + ')>'; }; return StringMatching; }; getJasmineRequireObj().CallTracker = function (j$) { /** * @namespace Spy#calls */ function CallTracker() { var calls = []; var opts = {}; function argCloner(context) { var clonedArgs = []; var argsAsArray = j$.util.argsToArray(context.args); for (var i = 0; i < argsAsArray.length; i++) { if (Object.prototype.toString.apply(argsAsArray[i]).match(/^\[object/)) { clonedArgs.push(j$.util.clone(argsAsArray[i])); } else { clonedArgs.push(argsAsArray[i]); } } context.args = clonedArgs; } this.track = function (context) { if (opts.cloneArgs) { argCloner(context); } calls.push(context); }; /** * Check whether this spy has been invoked. * @name Spy#calls#any * @function * @return {Boolean} */ this.any = function () { return !!calls.length; }; /** * Get the number of invocations of this spy. * @name Spy#calls#count * @function * @return {Integer} */ this.count = function () { return calls.length; }; /** * Get the arguments that were passed to a specific invocation of this spy. * @name Spy#calls#argsFor * @function * @param {Integer} index The 0-based invocation index. * @return {Array} */ this.argsFor = function (index) { var call = calls[index]; return call ? call.args : []; }; /** * Get the raw calls array for this spy. * @name Spy#calls#all * @function * @return {Spy.callData[]} */ this.all = function () { return calls; }; /** * Get all of the arguments for each invocation of this spy in the order they were received. * @name Spy#calls#allArgs *