diff --git a/README.md b/README.md
index e4170a6f6..395fedc3d 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,7 @@ Note: You might need to run the Android Studio from the command line in order to
## How to Run Tests
+* Run `npm install` in the repository root. The test app's Jasmine (`jasmine-core`) comes from there and is copied into the APK at build time.
* Go to subfolder test-app after you built the runtime.
* Start an emulator or connect a device.
diff --git a/package.json b/package.json
index 826505027..4a292a289 100644
--- a/package.json
+++ b/package.json
@@ -35,6 +35,7 @@
"dayjs": "^1.11.7",
"eslint": "^9.15.0",
"globals": "^15.12.0",
+ "jasmine-core": "7.0.2",
"semver": "^7.5.0"
}
}
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/boot.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/boot.js
new file mode 100644
index 000000000..f6bc7915d
--- /dev/null
+++ b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/boot.js
@@ -0,0 +1,57 @@
+// Boots jasmine-core for the test app. The test-runner-deps plugin
+// (test-app/test-runner-deps) stages jasmine-core from the repo's node_modules
+// into ./vendor at build time.
+var jasmineCore = require("./vendor/jasmine-core/jasmine");
+var JUnitXmlReporter = require("./jasmine-reporters/junit_reporter").JUnitXmlReporter;
+var TerminalReporter = require("./jasmine-reporters/terminal_reporter").TerminalReporter;
+
+jasmineCore.installGlobals(global);
+
+var env = jasmine.getEnv();
+
+env.configure({
+ // Suites carry state from one spec to the next (the shared Workers suite
+ // counts live runtimes across its specs), so they run in declaration order.
+ random: false
+});
+
+// jasmine-core's pretty-printer falls back to value.toString() for tagged objects
+// it does not recognize, which throws for null-prototype ones such as module
+// namespaces. toBe() builds its message even when it passes, so without this an
+// expect(namespace).toBe(sameNamespace) throws.
+beforeEach(function () {
+ jasmine.addCustomObjectFormatter(function (value) {
+ if (value !== null && typeof value === "object" && typeof value.toString !== "function") {
+ var tag = Object.prototype.toString.call(value);
+ if (tag !== "[object Object]") {
+ return tag;
+ }
+ }
+ return undefined;
+ });
+});
+
+env.addReporter(new TerminalReporter({
+ verbosity: 2
+}));
+env.addReporter(new JUnitXmlReporter());
+
+// Without a results file the runtests harness only gives up after its full
+// timeout, so a run that cannot start still writes one failing testcase.
+function saveRunFailure(message) {
+ var xml = '\n' +
+ '\n ' +
+ '\n ' +
+ '\n ' +
+ '/g, ']]]]>') + ']]>' +
+ '\n \n \n \n';
+ global.__JUnitSaveResults(xml);
+}
+
+exports.execute = function () {
+ env.execute().catch(function (e) {
+ var message = String((e && e.stack) || e);
+ console.log("Jasmine could not run the suite: " + message);
+ saveRunFailure(message);
+ });
+};
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/globalErrorSpy.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/globalErrorSpy.js
new file mode 100644
index 000000000..a802c5d4c
--- /dev/null
+++ b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/globalErrorSpy.js
@@ -0,0 +1,29 @@
+// Wraps a done-style spec body that raises global `error` events or unhandled
+// rejections on purpose. Jasmine fails the running spec on those unless its
+// global error spy is installed, which it is for as long as the body runs; the
+// spy is passed as the body's second argument. Jasmine's spy never cancels the
+// event, so listeners, preventDefault() and the __onUncaughtError fallback behave
+// as they do in production.
+//
+// The body must call done() only after every error it expects was dispatched:
+// one that arrives later is charged to whatever spec is running then.
+exports.raisesGlobalErrors = function (body) {
+ return function () {
+ var context = this;
+ return jasmine.spyOnGlobalErrorsAsync(function (globalErrorSpy) {
+ return new Promise(function (resolve, reject) {
+ function done(reason) {
+ if (reason === undefined) {
+ resolve();
+ } else {
+ reject(reason instanceof Error ? reason : new Error(String(reason)));
+ }
+ }
+ done.fail = function (reason) {
+ done(reason === undefined ? new Error("Failed") : reason);
+ };
+ body.call(context, done, globalErrorSpy);
+ });
+ });
+ };
+};
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/boot.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/boot.js
deleted file mode 100644
index 01ed0dcbc..000000000
--- a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/boot.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/**
- Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project.
-
- If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms.
-
- The location of `boot.js` can be specified and/or overridden in `jasmine.yml`.
-
- [jasmine-gem]: http://github.com/pivotal/jasmine-gem
- */
-
-var jasmineRequire = require('./jasmine');
-var JUnitXmlReporter = require('../jasmine-reporters/junit_reporter').JUnitXmlReporter;
-var TerminalReporter = require('../jasmine-reporters/terminal_reporter').TerminalReporter;
-
-(function() {
- /**
- * ## Require & Instantiate
- *
- * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference.
- */
- var jasmine = jasmineRequire.core(jasmineRequire);
-
- /**
- * Create the Jasmine environment. This is used to run all specs in a project.
- */
- var env = jasmine.getEnv();
-
- /**
- * ## The Global Interface
- *
- * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged.
- */
- var jasmineInterface = {
- describe: function(description, specDefinitions) {
- return env.describe(description, specDefinitions);
- },
-
- xdescribe: function(description, specDefinitions) {
- return env.xdescribe(description, specDefinitions);
- },
-
- it: function(desc, func) {
- return env.it(desc, func);
- },
-
- xit: function(desc, func) {
- return env.xit(desc, func);
- },
-
- beforeEach: function(beforeEachFunction) {
- return env.beforeEach(beforeEachFunction);
- },
-
- afterEach: function(afterEachFunction) {
- return env.afterEach(afterEachFunction);
- },
-
- expect: function(actual) {
- return env.expect(actual);
- },
-
- pending: function() {
- return env.pending();
- },
-
- spyOn: function(obj, methodName) {
- return env.spyOn(obj, methodName);
- },
-
- jsApiReporter: new jasmine.JsApiReporter({
- timer: new jasmine.Timer()
- }),
-
- execute: function() {
- return env.execute();
- },
-
- jasmine: jasmine
- };
-
- /**
- * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
- */
- if (typeof window == "undefined" && typeof global == "object") {
- extend(global, jasmineInterface);
- } else {
- extend(window, jasmineInterface);
- }
-
- /**
- * Expose the interface for adding custom equality testers.
- */
- jasmine.addCustomEqualityTester = function(tester) {
- env.addCustomEqualityTester(tester);
- };
-
- /**
- * Expose the interface for adding custom expectation matchers
- */
- jasmine.addMatchers = function(matchers) {
- return env.addMatchers(matchers);
- };
-
- /**
- * Expose the mock interface for the JavaScript timeout functions
- */
- jasmine.clock = function() {
- return env.clock;
- };
-
- /**
- * ## Runner Parameters
- */
-
- env.catchExceptions(true);
-
- /**
- * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript.
- */
- env.addReporter(jasmineInterface.jsApiReporter);
-//
- env.addReporter(new TerminalReporter({
- verbosity: 2 // Show failures and summary, but not individual passes
- }));
-
- env.addReporter(new JUnitXmlReporter());
-
- env.specFilter = function(spec) {
- return true;
- };
-
- /**
- * Helper function for readability above.
- */
- function extend(destination, source) {
- for (var property in source) destination[property] = source[property];
- return destination;
- }
-}());
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/jasmine.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/jasmine.js
deleted file mode 100644
index 63614709d..000000000
--- a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-2.0.1/jasmine.js
+++ /dev/null
@@ -1,2521 +0,0 @@
-/*
-Copyright (c) 2008-2014 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.
-*/
-function getJasmineRequireObj() {
- if (typeof module !== 'undefined' && module.exports) {
- return exports;
- } else {
- window.jasmineRequire = window.jasmineRequire || {};
- return window.jasmineRequire;
- }
-}
-
-getJasmineRequireObj().core = function(jRequire) {
- var j$ = {};
-
- jRequire.base(j$);
- j$.util = jRequire.util();
- j$.Any = jRequire.Any();
- j$.CallTracker = jRequire.CallTracker();
- j$.MockDate = jRequire.MockDate();
- 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$.pp = jRequire.pp(j$);
- j$.QueueRunner = jRequire.QueueRunner(j$);
- j$.ReportDispatcher = jRequire.ReportDispatcher();
- j$.Spec = jRequire.Spec(j$);
- j$.SpyStrategy = jRequire.SpyStrategy();
- j$.Suite = jRequire.Suite();
- j$.Timer = jRequire.Timer();
- j$.version = jRequire.version();
-
- j$.matchers = jRequire.requireMatchers(jRequire, j$);
-
- return j$;
-};
-
-getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
- var availableMatchers = [
- 'toBe',
- 'toBeCloseTo',
- 'toBeDefined',
- 'toBeFalsy',
- 'toBeGreaterThan',
- 'toBeLessThan',
- 'toBeNaN',
- 'toBeNull',
- 'toBeTruthy',
- 'toBeUndefined',
- 'toContain',
- 'toEqual',
- 'toHaveBeenCalled',
- '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 (jasmineGlobal) {
- if (typeof module !== 'undefined' && module.exports) {
- jasmineGlobal = global;
- }
-
- return function(j$) {
- j$.unimplementedMethod_ = function() {
- throw new Error('unimplemented method');
- };
-
- j$.MAX_PRETTY_PRINT_DEPTH = 40;
- j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 100;
- j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
-
- j$.getGlobal = function() {
- return jasmineGlobal;
- };
-
- 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$.isString_ = function(value) {
- return j$.isA_('String', value);
- };
-
- j$.isNumber_ = function(value) {
- return j$.isA_('Number', value);
- };
-
- j$.isA_ = function(typeName, value) {
- return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
- };
-
- j$.isDomNode = function(obj) {
- return obj.nodeType > 0;
- };
-
- j$.any = function(clazz) {
- return new j$.Any(clazz);
- };
-
- j$.objectContaining = function(sample) {
- return new j$.ObjectContaining(sample);
- };
-
- j$.createSpy = function(name, originalFn) {
-
- var spyStrategy = new j$.SpyStrategy({
- name: name,
- fn: originalFn,
- getSpy: function() { return spy; }
- }),
- callTracker = new j$.CallTracker(),
- spy = function() {
- callTracker.track({
- object: this,
- args: Array.prototype.slice.apply(arguments)
- });
- return spyStrategy.exec.apply(this, arguments);
- };
-
- for (var prop in originalFn) {
- if (prop === 'and' || prop === 'calls') {
- throw new Error('Jasmine spies would overwrite the \'and\' and \'calls\' properties on the object being spied upon');
- }
-
- spy[prop] = originalFn[prop];
- }
-
- spy.and = spyStrategy;
- spy.calls = callTracker;
-
- return spy;
- };
-
- j$.isSpy = function(putativeSpy) {
- if (!putativeSpy) {
- return false;
- }
- return putativeSpy.and instanceof j$.SpyStrategy &&
- putativeSpy.calls instanceof j$.CallTracker;
- };
-
- j$.createSpyObj = function(baseName, methodNames) {
- if (!j$.isArray_(methodNames) || methodNames.length === 0) {
- throw 'createSpyObj requires a non-empty array of method names to create spies for';
- }
- var obj = {};
- for (var i = 0; i < methodNames.length; i++) {
- obj[methodNames[i]] = j$.createSpy(baseName + '.' + methodNames[i]);
- }
- return obj;
- };
- };
-})(this);
-
-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, '&')
- .replace(//g, '>');
- };
-
- 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;
- };
-
- 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.fn = attrs.fn;
- this.beforeFns = attrs.beforeFns || function() { return []; };
- this.afterFns = attrs.afterFns || function() { return []; };
- this.onStart = attrs.onStart || function() {};
- this.exceptionFormatter = attrs.exceptionFormatter || function() {};
- this.getSpecName = attrs.getSpecName || function() { return ''; };
- this.expectationResultFactory = attrs.expectationResultFactory || function() { };
- this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
- this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
-
- if (!this.fn) {
- this.pend();
- }
-
- this.result = {
- id: this.id,
- description: this.description,
- fullName: this.getFullName(),
- failedExpectations: [],
- passedExpectations: []
- };
- }
-
- Spec.prototype.addExpectationResult = function(passed, data) {
- var expectationResult = this.expectationResultFactory(data);
- if (passed) {
- this.result.passedExpectations.push(expectationResult);
- } else {
- this.result.failedExpectations.push(expectationResult);
- }
- };
-
- Spec.prototype.expect = function(actual) {
- return this.expectationFactory(actual, this);
- };
-
- Spec.prototype.execute = function(onComplete) {
- var self = this;
-
- this.onStart(this);
-
- if (this.markedPending || this.disabled) {
- complete();
- return;
- }
-
- var allFns = this.beforeFns().concat(this.fn).concat(this.afterFns());
-
- this.queueRunnerFactory({
- fns: allFns,
- onException: onException,
- onComplete: complete,
- enforceTimeout: function() { return true; }
- });
-
- function onException(e) {
- if (Spec.isPendingSpecException(e)) {
- self.pend();
- return;
- }
-
- self.addExpectationResult(false, {
- matcherName: '',
- passed: false,
- expected: '',
- actual: '',
- error: e
- });
- }
-
- function complete() {
- self.result.status = self.status();
- self.resultCallback(self.result);
-
- if (onComplete) {
- onComplete();
- }
- }
- };
-
- Spec.prototype.disable = function() {
- this.disabled = true;
- };
-
- Spec.prototype.pend = function() {
- this.markedPending = true;
- };
-
- Spec.prototype.status = function() {
- if (this.disabled) {
- return 'disabled';
- }
-
- if (this.markedPending) {
- return 'pending';
- }
-
- if (this.result.failedExpectations.length > 0) {
- return 'failed';
- } else {
- return 'passed';
- }
- };
-
- Spec.prototype.getFullName = function() {
- return this.getSpecName(this);
- };
-
- 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;
-}
-
-getJasmineRequireObj().Env = function(j$) {
- 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;
-
- this.clock = new j$.Clock(global, new j$.DelayedFunctionScheduler(), new j$.MockDate(global));
-
- var runnableLookupTable = {};
-
- var spies = [];
-
- var currentSpec = null;
- var currentSuite = null;
-
- var reporter = new j$.ReportDispatcher([
- 'jasmineStarted',
- 'jasmineDone',
- 'suiteStarted',
- 'suiteDone',
- 'specStarted',
- 'specDone'
- ]);
-
- this.specFilter = function() {
- return true;
- };
-
- var equalityTesters = [];
-
- var customEqualityTesters = [];
- this.addCustomEqualityTester = function(tester) {
- customEqualityTesters.push(tester);
- };
-
- 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: customEqualityTesters,
- actual: actual,
- addExpectationResult: addExpectationResult
- });
-
- function addExpectationResult(passed, result) {
- return spec.addExpectationResult(passed, result);
- }
- };
-
- var specStarted = function(spec) {
- currentSpec = spec;
- reporter.specStarted(spec.result);
- };
-
- var beforeFns = function(suite) {
- return function() {
- var befores = [];
- while(suite) {
- befores = befores.concat(suite.beforeFns);
- suite = suite.parentSuite;
- }
- return befores.reverse();
- };
- };
-
- var afterFns = function(suite) {
- return function() {
- var afters = [];
- while(suite) {
- afters = afters.concat(suite.afterFns);
- suite = suite.parentSuite;
- }
- return afters;
- };
- };
-
- var getSpecName = function(spec, suite) {
- return suite.getFullName() + ' ' + spec.description;
- };
-
- // 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;
- };
-
- /*
- set maximumSpecCallbackDepth to a large number in order to execute tests in very large batches,
- e.g. it looks like tests are executed synchronously; this guarantees that test order is preserved.
- */
- var maximumSpecCallbackDepth = 20000;
- var currentSpecCallbackDepth = 0;
-
- function clearStack(fn) {
- currentSpecCallbackDepth++;
- if (currentSpecCallbackDepth >= maximumSpecCallbackDepth) {
- currentSpecCallbackDepth = 0;
- realSetTimeout(fn, 0);
- } else {
- fn();
- }
- }
-
- var catchException = function(e) {
- return j$.Spec.isPendingSpecException(e) || catchExceptions;
- };
-
- var queueRunnerFactory = function(options) {
- options.catchException = catchException;
- options.clearStack = options.clearStack || clearStack;
- options.timer = {setTimeout: setTimeout, clearTimeout: clearTimeout};
-
- new j$.QueueRunner(options).execute();
- };
-
- var topSuite = new j$.Suite({
- env: this,
- id: getNextSuiteId(),
- description: 'Jasmine__TopLevel__Suite',
- queueRunner: queueRunnerFactory,
- resultCallback: function() {} // TODO - hook this up
- });
- runnableLookupTable[topSuite.id] = topSuite;
- currentSuite = topSuite;
-
- this.topSuite = function() {
- return topSuite;
- };
-
- this.execute = function(runnablesToRun) {
- runnablesToRun = runnablesToRun || [topSuite.id];
-
- var allFns = [];
- for(var i = 0; i < runnablesToRun.length; i++) {
- var runnable = runnableLookupTable[runnablesToRun[i]];
- allFns.push((function(runnable) { return function(done) { runnable.execute(done); }; })(runnable));
- }
-
- reporter.jasmineStarted({
- totalSpecsDefined: totalSpecsDefined
- });
-
- queueRunnerFactory({fns: allFns, onComplete: reporter.jasmineDone});
- };
-
- this.addReporter = function(reporterToAdd) {
- reporter.addReporter(reporterToAdd);
- };
-
- this.addMatchers = function(matchersToAdd) {
- j$.Expectation.addMatchers(matchersToAdd);
- };
-
- this.spyOn = function(obj, methodName) {
- if (j$.util.isUndefined(obj)) {
- throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
- }
-
- if (j$.util.isUndefined(obj[methodName])) {
- throw new Error(methodName + '() method does not exist');
- }
-
- if (obj[methodName] && j$.isSpy(obj[methodName])) {
- //TODO?: should this return the current spy? Downside: may cause user confusion about spy state
- throw new Error(methodName + ' has already been spied upon');
- }
-
- var spy = j$.createSpy(methodName, obj[methodName]);
-
- spies.push({
- spy: spy,
- baseObj: obj,
- methodName: methodName,
- originalValue: obj[methodName]
- });
-
- obj[methodName] = spy;
-
- return spy;
- };
-
- var suiteFactory = function(description) {
- var suite = new j$.Suite({
- env: self,
- id: getNextSuiteId(),
- description: description,
- parentSuite: currentSuite,
- queueRunner: queueRunnerFactory,
- onStart: suiteStarted,
- resultCallback: function(attrs) {
- reporter.suiteDone(attrs);
- }
- });
-
- runnableLookupTable[suite.id] = suite;
- return suite;
- };
-
- this.describe = function(description, specDefinitions) {
- var suite = suiteFactory(description);
-
- var parentSuite = currentSuite;
- parentSuite.addChild(suite);
- currentSuite = suite;
-
- var declarationError = null;
- try {
- specDefinitions.call(suite);
- } catch (e) {
- declarationError = e;
- }
-
- if (declarationError) {
- this.it('encountered a declaration exception', function() {
- throw declarationError;
- });
- }
-
- currentSuite = parentSuite;
-
- return suite;
- };
-
- this.xdescribe = function(description, specDefinitions) {
- var suite = this.describe(description, specDefinitions);
- suite.disable();
- return suite;
- };
-
- var specFactory = function(description, fn, suite) {
- totalSpecsDefined++;
-
- var spec = new j$.Spec({
- id: getNextSpecId(),
- beforeFns: beforeFns(suite),
- afterFns: afterFns(suite),
- expectationFactory: expectationFactory,
- exceptionFormatter: exceptionFormatter,
- resultCallback: specResultCallback,
- getSpecName: function(spec) {
- return getSpecName(spec, suite);
- },
- onStart: specStarted,
- description: description,
- expectationResultFactory: expectationResultFactory,
- queueRunnerFactory: queueRunnerFactory,
- fn: fn
- });
-
- runnableLookupTable[spec.id] = spec;
-
- if (!self.specFilter(spec)) {
- spec.disable();
- }
-
- return spec;
-
- function removeAllSpies() {
- for (var i = 0; i < spies.length; i++) {
- var spyEntry = spies[i];
- spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
- }
- spies = [];
- }
-
- function specResultCallback(result) {
- removeAllSpies();
- j$.Expectation.resetMatchers();
- customEqualityTesters = [];
- currentSpec = null;
- reporter.specDone(result);
- }
- };
-
- var suiteStarted = function(suite) {
- reporter.suiteStarted(suite.result);
- };
-
- this.it = function(description, fn) {
- var spec = specFactory(description, fn, currentSuite);
- currentSuite.addChild(spec);
- return spec;
- };
-
- this.xit = function(description, fn) {
- var spec = this.it(description, fn);
- spec.pend();
- return spec;
- };
-
- this.expect = function(actual) {
- if (!currentSpec) {
- throw new Error('\'expect\' was used when there was no current spec, this could be because an asynchronous test timed out');
- }
-
- return currentSpec.expect(actual);
- };
-
- this.beforeEach = function(beforeEachFunction) {
- currentSuite.beforeEach(beforeEachFunction);
- };
-
- this.afterEach = function(afterEachFunction) {
- currentSuite.afterEach(afterEachFunction);
- };
-
- this.pending = function() {
- throw j$.Spec.pendingSpecExceptionMessage;
- };
- }
-
- return Env;
-};
-
-getJasmineRequireObj().JsApiReporter = function() {
-
- var noopTimer = {
- start: function(){},
- elapsed: function(){ return 0; }
- };
-
- function JsApiReporter(options) {
- var timer = options.timer || noopTimer,
- status = 'loaded';
-
- this.started = false;
- this.finished = false;
-
- this.jasmineStarted = function() {
- this.started = true;
- status = 'started';
- timer.start();
- };
-
- var executionTime;
-
- this.jasmineDone = function() {
- this.finished = true;
- executionTime = timer.elapsed();
- status = 'done';
- };
-
- this.status = function() {
- return status;
- };
-
- var suites = {};
-
- this.suiteStarted = function(result) {
- storeSuite(result);
- };
-
- this.suiteDone = function(result) {
- storeSuite(result);
- };
-
- function storeSuite(result) {
- suites[result.id] = result;
- }
-
- this.suites = function() {
- return suites;
- };
-
- var specs = [];
- this.specStarted = function(result) { };
-
- this.specDone = function(result) {
- specs.push(result);
- };
-
- this.specResults = function(index, length) {
- return specs.slice(index, index + length);
- };
-
- this.specs = function() {
- return specs;
- };
-
- this.executionTime = function() {
- return executionTime;
- };
-
- }
-
- return JsApiReporter;
-};
-
-getJasmineRequireObj().Any = function() {
-
- function Any(expectedObject) {
- this.expectedObject = expectedObject;
- }
-
- Any.prototype.jasmineMatches = 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 '';
- };
-
- return Any;
-};
-
-getJasmineRequireObj().CallTracker = function() {
-
- function CallTracker() {
- var calls = [];
-
- this.track = function(context) {
- calls.push(context);
- };
-
- this.any = function() {
- return !!calls.length;
- };
-
- this.count = function() {
- return calls.length;
- };
-
- this.argsFor = function(index) {
- var call = calls[index];
- return call ? call.args : [];
- };
-
- this.all = function() {
- return calls;
- };
-
- this.allArgs = function() {
- var callArgs = [];
- for(var i = 0; i < calls.length; i++){
- callArgs.push(calls[i].args);
- }
-
- return callArgs;
- };
-
- this.first = function() {
- return calls[0];
- };
-
- this.mostRecent = function() {
- return calls[calls.length - 1];
- };
-
- this.reset = function() {
- calls = [];
- };
- }
-
- return CallTracker;
-};
-
-getJasmineRequireObj().Clock = function() {
- function Clock(global, delayedFunctionScheduler, mockDate) {
- var self = this,
- realTimingFunctions = {
- setTimeout: global.setTimeout,
- clearTimeout: global.clearTimeout,
- setInterval: global.setInterval,
- clearInterval: global.clearInterval
- },
- fakeTimingFunctions = {
- setTimeout: setTimeout,
- clearTimeout: clearTimeout,
- setInterval: setInterval,
- clearInterval: clearInterval
- },
- installed = false,
- timer;
-
-
- self.install = function() {
- replace(global, fakeTimingFunctions);
- timer = fakeTimingFunctions;
- installed = true;
-
- return self;
- };
-
- self.uninstall = function() {
- delayedFunctionScheduler.reset();
- mockDate.uninstall();
- replace(global, realTimingFunctions);
-
- timer = realTimingFunctions;
- installed = false;
- };
-
- self.mockDate = function(initialDate) {
- mockDate.install(initialDate);
- };
-
- self.setTimeout = function(fn, delay, params) {
- if (legacyIE()) {
- if (arguments.length > 2) {
- throw new Error('IE < 9 cannot support extra params to setTimeout without a polyfill');
- }
- return timer.setTimeout(fn, delay);
- }
- return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
- };
-
- self.setInterval = function(fn, delay, params) {
- if (legacyIE()) {
- if (arguments.length > 2) {
- throw new Error('IE < 9 cannot support extra params to setInterval without a polyfill');
- }
- return timer.setInterval(fn, delay);
- }
- return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
- };
-
- self.clearTimeout = function(id) {
- return Function.prototype.call.apply(timer.clearTimeout, [global, id]);
- };
-
- self.clearInterval = function(id) {
- return Function.prototype.call.apply(timer.clearInterval, [global, id]);
- };
-
- self.tick = function(millis) {
- if (installed) {
- mockDate.tick(millis);
- delayedFunctionScheduler.tick(millis);
- } else {
- throw new Error('Mock clock is not installed, use jasmine.clock().install()');
- }
- };
-
- return self;
-
- function legacyIE() {
- //if these methods are polyfilled, apply will be present
- return !(realTimingFunctions.setTimeout || realTimingFunctions.setInterval).apply;
- }
-
- function replace(dest, source) {
- for (var prop in source) {
- dest[prop] = source[prop];
- }
- }
-
- function setTimeout(fn, delay) {
- return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
- }
-
- function clearTimeout(id) {
- return delayedFunctionScheduler.removeFunctionWithId(id);
- }
-
- function setInterval(fn, interval) {
- return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
- }
-
- function clearInterval(id) {
- return delayedFunctionScheduler.removeFunctionWithId(id);
- }
-
- function argSlice(argsObj, n) {
- return Array.prototype.slice.call(argsObj, n);
- }
- }
-
- return Clock;
-};
-
-getJasmineRequireObj().DelayedFunctionScheduler = function() {
- function DelayedFunctionScheduler() {
- var self = this;
- var scheduledLookup = [];
- var scheduledFunctions = {};
- var currentTime = 0;
- var delayedFnCount = 0;
-
- self.tick = function(millis) {
- millis = millis || 0;
- var endTime = currentTime + millis;
-
- runScheduledFunctions(endTime);
- currentTime = endTime;
- };
-
- self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
- var f;
- if (typeof(funcToCall) === 'string') {
- /* jshint evil: true */
- f = function() { return eval(funcToCall); };
- /* jshint evil: false */
- } else {
- f = funcToCall;
- }
-
- millis = millis || 0;
- timeoutKey = timeoutKey || ++delayedFnCount;
- runAtMillis = runAtMillis || (currentTime + millis);
-
- var funcToSchedule = {
- runAtMillis: runAtMillis,
- funcToCall: f,
- recurring: recurring,
- params: params,
- timeoutKey: timeoutKey,
- millis: millis
- };
-
- if (runAtMillis in scheduledFunctions) {
- scheduledFunctions[runAtMillis].push(funcToSchedule);
- } else {
- scheduledFunctions[runAtMillis] = [funcToSchedule];
- scheduledLookup.push(runAtMillis);
- scheduledLookup.sort(function (a, b) {
- return a - b;
- });
- }
-
- return timeoutKey;
- };
-
- self.removeFunctionWithId = function(timeoutKey) {
- for (var runAtMillis in scheduledFunctions) {
- var funcs = scheduledFunctions[runAtMillis];
- var i = indexOfFirstToPass(funcs, function (func) {
- return func.timeoutKey === timeoutKey;
- });
-
- if (i > -1) {
- if (funcs.length === 1) {
- delete scheduledFunctions[runAtMillis];
- deleteFromLookup(runAtMillis);
- } else {
- funcs.splice(i, 1);
- }
-
- // intervals get rescheduled when executed, so there's never more
- // than a single scheduled function with a given timeoutKey
- break;
- }
- }
- };
-
- self.reset = function() {
- currentTime = 0;
- scheduledLookup = [];
- scheduledFunctions = {};
- delayedFnCount = 0;
- };
-
- return self;
-
- function indexOfFirstToPass(array, testFn) {
- var index = -1;
-
- for (var i = 0; i < array.length; ++i) {
- if (testFn(array[i])) {
- index = i;
- break;
- }
- }
-
- return index;
- }
-
- function deleteFromLookup(key) {
- var value = Number(key);
- var i = indexOfFirstToPass(scheduledLookup, function (millis) {
- return millis === value;
- });
-
- if (i > -1) {
- scheduledLookup.splice(i, 1);
- }
- }
-
- function reschedule(scheduledFn) {
- self.scheduleFunction(scheduledFn.funcToCall,
- scheduledFn.millis,
- scheduledFn.params,
- true,
- scheduledFn.timeoutKey,
- scheduledFn.runAtMillis + scheduledFn.millis);
- }
-
- function runScheduledFunctions(endTime) {
- if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
- return;
- }
-
- do {
- currentTime = scheduledLookup.shift();
-
- var funcsToRun = scheduledFunctions[currentTime];
- delete scheduledFunctions[currentTime];
-
- for (var i = 0; i < funcsToRun.length; ++i) {
- var funcToRun = funcsToRun[i];
- funcToRun.funcToCall.apply(null, funcToRun.params || []);
-
- if (funcToRun.recurring) {
- reschedule(funcToRun);
- }
- }
- } while (scheduledLookup.length > 0 &&
- // checking first if we're out of time prevents setTimeout(0)
- // scheduled in a funcToRun from forcing an extra iteration
- currentTime !== endTime &&
- scheduledLookup[0] <= endTime);
- }
- }
-
- return DelayedFunctionScheduler;
-};
-
-getJasmineRequireObj().ExceptionFormatter = function() {
- function ExceptionFormatter() {
- this.message = function(error) {
- var message = '';
-
- if (error.name && error.message) {
- message += error.name + ': ' + error.message;
- } else {
- message += error.toString() + ' thrown';
- }
-
- if (error.fileName || error.sourceURL) {
- message += ' in ' + (error.fileName || error.sourceURL);
- }
-
- if (error.line || error.lineNumber) {
- message += ' (line ' + (error.line || error.lineNumber) + ')';
- }
-
- return message;
- };
-
- this.stack = function(error) {
- return error ? error.stack : null;
- };
- }
-
- return ExceptionFormatter;
-};
-
-getJasmineRequireObj().Expectation = function() {
-
- var matchers = {};
-
- function Expectation(options) {
- this.util = options.util || { buildFailureMessage: function() {} };
- this.customEqualityTesters = options.customEqualityTesters || [];
- this.actual = options.actual;
- this.addExpectationResult = options.addExpectationResult || function(){};
- this.isNot = options.isNot;
-
- for (var matcherName in matchers) {
- this[matcherName] = matchers[matcherName];
- }
- }
-
- Expectation.prototype.wrapCompare = function(name, matcherFactory) {
- return function() {
- var args = Array.prototype.slice.call(arguments, 0),
- expected = args.slice(0),
- message = '';
-
- args.unshift(this.actual);
-
- var matcher = matcherFactory(this.util, this.customEqualityTesters),
- matcherCompare = matcher.compare;
-
- function defaultNegativeCompare() {
- var result = matcher.compare.apply(null, args);
- result.pass = !result.pass;
- return result;
- }
-
- if (this.isNot) {
- matcherCompare = matcher.negativeCompare || defaultNegativeCompare;
- }
-
- var result = matcherCompare.apply(null, args);
-
- if (!result.pass) {
- if (!result.message) {
- args.unshift(this.isNot);
- args.unshift(name);
- message = this.util.buildFailureMessage.apply(null, args);
- } else {
- if (Object.prototype.toString.apply(result.message) === '[object Function]') {
- message = result.message();
- } else {
- message = result.message;
- }
- }
- }
-
- if (expected.length == 1) {
- expected = expected[0];
- }
-
- // TODO: how many of these params are needed?
- this.addExpectationResult(
- result.pass,
- {
- matcherName: name,
- passed: result.pass,
- message: message,
- actual: this.actual,
- expected: expected // TODO: this may need to be arrayified/sliced
- }
- );
- };
- };
-
- Expectation.addCoreMatchers = function(matchers) {
- var prototype = Expectation.prototype;
- for (var matcherName in matchers) {
- var matcher = matchers[matcherName];
- prototype[matcherName] = prototype.wrapCompare(matcherName, matcher);
- }
- };
-
- Expectation.addMatchers = function(matchersToAdd) {
- for (var name in matchersToAdd) {
- var matcher = matchersToAdd[name];
- matchers[name] = Expectation.prototype.wrapCompare(name, matcher);
- }
- };
-
- Expectation.resetMatchers = function() {
- for (var name in matchers) {
- delete matchers[name];
- }
- };
-
- Expectation.Factory = function(options) {
- options = options || {};
-
- var expect = new Expectation(options);
-
- // TODO: this would be nice as its own Object - NegativeExpectation
- // TODO: copy instead of mutate options
- options.isNot = true;
- expect.not = new Expectation(options);
-
- return expect;
- };
-
- return Expectation;
-};
-
-//TODO: expectation result may make more sense as a presentation of an expectation.
-getJasmineRequireObj().buildExpectationResult = function() {
- function buildExpectationResult(options) {
- var messageFormatter = options.messageFormatter || function() {},
- stackFormatter = options.stackFormatter || function() {};
-
- return {
- matcherName: options.matcherName,
- expected: options.expected,
- actual: options.actual,
- message: message(),
- stack: stack(),
- passed: options.passed
- };
-
- function message() {
- if (options.passed) {
- return 'Passed.';
- } else if (options.message) {
- return options.message;
- } else if (options.error) {
- return messageFormatter(options.error);
- }
- return '';
- }
-
- function stack() {
- if (options.passed) {
- return '';
- }
-
- var error = options.error;
- if (!error) {
- try {
- throw new Error(message());
- } catch (e) {
- error = e;
- }
- }
- return stackFormatter(error);
- }
- }
-
- return buildExpectationResult;
-};
-
-getJasmineRequireObj().MockDate = function() {
- function MockDate(global) {
- var self = this;
- var currentTime = 0;
-
- if (!global || !global.Date) {
- self.install = function() {};
- self.tick = function() {};
- self.uninstall = function() {};
- return self;
- }
-
- var GlobalDate = global.Date;
-
- self.install = function(mockDate) {
- if (mockDate instanceof GlobalDate) {
- currentTime = mockDate.getTime();
- } else {
- currentTime = new GlobalDate().getTime();
- }
-
- global.Date = FakeDate;
- };
-
- self.tick = function(millis) {
- millis = millis || 0;
- currentTime = currentTime + millis;
- };
-
- self.uninstall = function() {
- currentTime = 0;
- global.Date = GlobalDate;
- };
-
- createDateProperties();
-
- return self;
-
- function FakeDate() {
- if (arguments.length === 0) {
- return new GlobalDate(currentTime);
- } else {
- return new GlobalDate(arguments[0], arguments[1], arguments[2],
- arguments[3], arguments[4], arguments[5], arguments[6]);
- }
- }
-
- function createDateProperties() {
-
- FakeDate.now = function() {
- if (GlobalDate.now) {
- return currentTime;
- } else {
- throw new Error('Browser does not support Date.now()');
- }
- };
-
- FakeDate.toSource = GlobalDate.toSource;
- FakeDate.toString = GlobalDate.toString;
- FakeDate.parse = GlobalDate.parse;
- FakeDate.UTC = GlobalDate.UTC;
- }
- }
-
- return MockDate;
-};
-
-getJasmineRequireObj().ObjectContaining = function(j$) {
-
- function ObjectContaining(sample) {
- this.sample = sample;
- }
-
- ObjectContaining.prototype.jasmineMatches = function(other, mismatchKeys, mismatchValues) {
- if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
-
- mismatchKeys = mismatchKeys || [];
- mismatchValues = mismatchValues || [];
-
- var hasKey = function(obj, keyName) {
- return obj !== null && !j$.util.isUndefined(obj[keyName]);
- };
-
- for (var property in this.sample) {
- if (!hasKey(other, property) && hasKey(this.sample, property)) {
- mismatchKeys.push('expected has key \'' + property + '\', but missing from actual.');
- }
- else if (!j$.matchersUtil.equals(other[property], this.sample[property])) {
- mismatchValues.push('\'' + property + '\' was \'' + (other[property] ? j$.util.htmlEscape(other[property].toString()) : other[property]) + '\' in actual, but was \'' + (this.sample[property] ? j$.util.htmlEscape(this.sample[property].toString()) : this.sample[property]) + '\' in expected.');
- }
- }
-
- return (mismatchKeys.length === 0 && mismatchValues.length === 0);
- };
-
- ObjectContaining.prototype.jasmineToString = function() {
- return '';
- };
-
- return ObjectContaining;
-};
-
-getJasmineRequireObj().pp = function(j$) {
-
- function PrettyPrinter() {
- this.ppNestLevel_ = 0;
- this.seen = [];
- }
-
- PrettyPrinter.prototype.format = function(value) {
- this.ppNestLevel_++;
- try {
- if (j$.util.isUndefined(value)) {
- this.emitScalar('undefined');
- } else if (value === null) {
- this.emitScalar('null');
- } else if (value === 0 && 1/value === -Infinity) {
- this.emitScalar('-0');
- } else if (value === j$.getGlobal()) {
- this.emitScalar('');
- } else if (value.jasmineToString) {
- this.emitScalar(value.jasmineToString());
- } else if (typeof value === 'string') {
- this.emitString(value);
- } else if (j$.isSpy(value)) {
- this.emitScalar('spy on ' + value.and.identity());
- } else if (value instanceof RegExp) {
- this.emitScalar(value.toString());
- } else if (typeof value === 'function') {
- this.emitScalar('Function');
- } else if (typeof value.nodeType === 'number') {
- this.emitScalar('HTMLNode');
- } else if (value instanceof Date) {
- this.emitScalar('Date(' + value + ')');
- } else if (j$.util.arrayContains(this.seen, value)) {
- this.emitScalar('');
- } else if (j$.isArray_(value) || j$.isA_('Object', value)) {
- this.seen.push(value);
- if (j$.isArray_(value)) {
- this.emitArray(value);
- } else {
- this.emitObject(value);
- }
- this.seen.pop();
- } else {
- this.emitScalar(value.toString());
- }
- } finally {
- this.ppNestLevel_--;
- }
- };
-
- PrettyPrinter.prototype.iterateObject = function(obj, fn) {
- for (var property in obj) {
- if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
- fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
- obj.__lookupGetter__(property) !== null) : false);
- }
- };
-
- PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
- PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
- PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
- PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
-
- function StringPrettyPrinter() {
- PrettyPrinter.call(this);
-
- this.string = '';
- }
-
- j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
-
- StringPrettyPrinter.prototype.emitScalar = function(value) {
- this.append(value);
- };
-
- StringPrettyPrinter.prototype.emitString = function(value) {
- this.append('\'' + value + '\'');
- };
-
- StringPrettyPrinter.prototype.emitArray = function(array) {
- if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
- this.append('Array');
- return;
- }
- var length = Math.min(array.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
- this.append('[ ');
- for (var i = 0; i < length; i++) {
- if (i > 0) {
- this.append(', ');
- }
- this.format(array[i]);
- }
- if(array.length > length){
- this.append(', ...');
- }
- this.append(' ]');
- };
-
- StringPrettyPrinter.prototype.emitObject = function(obj) {
- if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
- this.append('Object');
- return;
- }
-
- var self = this;
- this.append('{ ');
- var first = true;
-
- this.iterateObject(obj, function(property, isGetter) {
- if (first) {
- first = false;
- } else {
- self.append(', ');
- }
-
- self.append(property);
- self.append(': ');
- if (isGetter) {
- self.append('');
- } else {
- self.format(obj[property]);
- }
- });
-
- this.append(' }');
- };
-
- StringPrettyPrinter.prototype.append = function(value) {
- this.string += value;
- };
-
- return function(value) {
- var stringPrettyPrinter = new StringPrettyPrinter();
- stringPrettyPrinter.format(value);
- return stringPrettyPrinter.string;
- };
-};
-
-getJasmineRequireObj().QueueRunner = function(j$) {
-
- function once(fn) {
- var called = false;
- return function() {
- if (!called) {
- called = true;
- fn();
- }
- };
- }
-
- function QueueRunner(attrs) {
- this.fns = attrs.fns || [];
- this.onComplete = attrs.onComplete || function() {};
- this.clearStack = attrs.clearStack || function(fn) {fn();};
- this.onException = attrs.onException || function() {};
- this.catchException = attrs.catchException || function() { return true; };
- this.enforceTimeout = attrs.enforceTimeout || function() { return false; };
- this.userContext = {};
- this.timer = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
- }
-
- QueueRunner.prototype.execute = function() {
- this.run(this.fns, 0);
- };
-
- QueueRunner.prototype.run = function(fns, recursiveIndex) {
- var length = fns.length,
- self = this,
- iterativeIndex;
-
- for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
- var fn = fns[iterativeIndex];
- if (fn.length > 0) {
- return attemptAsync(fn);
- } else {
- attemptSync(fn);
- }
- }
-
- var runnerDone = iterativeIndex >= length;
-
- if (runnerDone) {
- this.clearStack(this.onComplete);
- }
-
- function attemptSync(fn) {
- try {
- fn.call(self.userContext);
- } catch (e) {
- handleException(e);
- }
- }
-
- function attemptAsync(fn) {
- var clearTimeout = function () {
- Function.prototype.apply.apply(self.timer.clearTimeout, [j$.getGlobal(), [timeoutId]]);
- },
- next = once(function () {
- clearTimeout(timeoutId);
- self.run(fns, iterativeIndex + 1);
- }),
- timeoutId;
-
- if (self.enforceTimeout()) {
- timeoutId = Function.prototype.apply.apply(self.timer.setTimeout, [j$.getGlobal(), [function() {
- self.onException(new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.'));
- next();
- }, j$.DEFAULT_TIMEOUT_INTERVAL]]);
- }
-
- try {
- fn.call(self.userContext, next);
- } catch (e) {
- handleException(e);
- next();
- }
- }
-
- function handleException(e) {
- self.onException(e);
- if (!self.catchException(e)) {
- //TODO: set a var when we catch an exception and
- //use a finally block to close the loop in a nice way..
- throw e;
- }
- }
- };
-
- return QueueRunner;
-};
-
-getJasmineRequireObj().ReportDispatcher = function() {
- function ReportDispatcher(methods) {
-
- var dispatchedMethods = methods || [];
-
- for (var i = 0; i < dispatchedMethods.length; i++) {
- var method = dispatchedMethods[i];
- this[method] = (function(m) {
- return function() {
- dispatch(m, arguments);
- };
- }(method));
- }
-
- var reporters = [];
-
- this.addReporter = function(reporter) {
- reporters.push(reporter);
- };
-
- return this;
-
- function dispatch(method, args) {
- for (var i = 0; i < reporters.length; i++) {
- var reporter = reporters[i];
- if (reporter[method]) {
- reporter[method].apply(reporter, args);
- }
- }
- }
- }
-
- return ReportDispatcher;
-};
-
-
-getJasmineRequireObj().SpyStrategy = function() {
-
- function SpyStrategy(options) {
- options = options || {};
-
- var identity = options.name || 'unknown',
- originalFn = options.fn || function() {},
- getSpy = options.getSpy || function() {},
- plan = function() {};
-
- this.identity = function() {
- return identity;
- };
-
- this.exec = function() {
- return plan.apply(this, arguments);
- };
-
- this.callThrough = function() {
- plan = originalFn;
- return getSpy();
- };
-
- this.returnValue = function(value) {
- plan = function() {
- return value;
- };
- return getSpy();
- };
-
- this.throwError = function(something) {
- var error = (something instanceof Error) ? something : new Error(something);
- plan = function() {
- throw error;
- };
- return getSpy();
- };
-
- this.callFake = function(fn) {
- plan = fn;
- return getSpy();
- };
-
- this.stub = function(fn) {
- plan = function() {};
- return getSpy();
- };
- }
-
- return SpyStrategy;
-};
-
-getJasmineRequireObj().Suite = function() {
- function Suite(attrs) {
- this.env = attrs.env;
- this.id = attrs.id;
- this.parentSuite = attrs.parentSuite;
- this.description = attrs.description;
- this.onStart = attrs.onStart || function() {};
- this.resultCallback = attrs.resultCallback || function() {};
- this.clearStack = attrs.clearStack || function(fn) {fn();};
-
- this.beforeFns = [];
- this.afterFns = [];
- this.queueRunner = attrs.queueRunner || function() {};
- this.disabled = false;
-
- this.children = [];
-
- this.result = {
- id: this.id,
- status: this.disabled ? 'disabled' : '',
- description: this.description,
- fullName: this.getFullName()
- };
- }
-
- Suite.prototype.getFullName = function() {
- var fullName = this.description;
- for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
- if (parentSuite.parentSuite) {
- fullName = parentSuite.description + ' ' + fullName;
- }
- }
- return fullName;
- };
-
- Suite.prototype.disable = function() {
- this.disabled = true;
- };
-
- Suite.prototype.beforeEach = function(fn) {
- this.beforeFns.unshift(fn);
- };
-
- Suite.prototype.afterEach = function(fn) {
- this.afterFns.unshift(fn);
- };
-
- Suite.prototype.addChild = function(child) {
- this.children.push(child);
- };
-
- Suite.prototype.execute = function(onComplete) {
- var self = this;
- if (this.disabled) {
- complete();
- return;
- }
-
- var allFns = [];
-
- for (var i = 0; i < this.children.length; i++) {
- allFns.push(wrapChildAsAsync(this.children[i]));
- }
-
- this.onStart(this);
-
- this.queueRunner({
- fns: allFns,
- onComplete: complete
- });
-
- function complete() {
- self.resultCallback(self.result);
-
- if (onComplete) {
- onComplete();
- }
- }
-
- function wrapChildAsAsync(child) {
- return function(done) { child.execute(done); };
- }
- };
-
- return Suite;
-};
-
-if (typeof window == void 0 && typeof exports == 'object') {
- exports.Suite = jasmineRequire.Suite;
-}
-
-getJasmineRequireObj().Timer = function() {
- var defaultNow = (function(Date) {
- return function() { return new Date().getTime(); };
- })(Date);
-
- function Timer(options) {
- options = options || {};
-
- var now = options.now || defaultNow,
- startTime;
-
- this.start = function() {
- startTime = now();
- };
-
- this.elapsed = function() {
- return now() - startTime;
- };
- }
-
- return Timer;
-};
-
-getJasmineRequireObj().matchersUtil = function(j$) {
- // TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
-
- return {
- equals: function(a, b, customTesters) {
- customTesters = customTesters || [];
-
- return eq(a, b, [], [], customTesters);
- },
-
- contains: function(haystack, needle, customTesters) {
- customTesters = customTesters || [];
-
- if (Object.prototype.toString.apply(haystack) === '[object Array]') {
- for (var i = 0; i < haystack.length; i++) {
- if (eq(haystack[i], needle, [], [], customTesters)) {
- return true;
- }
- }
- return false;
- }
- return !!haystack && haystack.indexOf(needle) >= 0;
- },
-
- buildFailureMessage: function() {
- var args = Array.prototype.slice.call(arguments, 0),
- matcherName = args[0],
- isNot = args[1],
- actual = args[2],
- expected = args.slice(3),
- englishyPredicate = matcherName.replace(/[A-Z]/g, function(s) { return ' ' + s.toLowerCase(); });
-
- var message = 'Expected ' +
- j$.pp(actual) +
- (isNot ? ' not ' : ' ') +
- englishyPredicate;
-
- if (expected.length > 0) {
- for (var i = 0; i < expected.length; i++) {
- if (i > 0) {
- message += ',';
- }
- message += ' ' + j$.pp(expected[i]);
- }
- }
-
- return message + '.';
- }
- };
-
- // Equality function lovingly adapted from isEqual in
- // [Underscore](http://underscorejs.org)
- function eq(a, b, aStack, bStack, customTesters) {
- var result = true;
-
- for (var i = 0; i < customTesters.length; i++) {
- var customTesterResult = customTesters[i](a, b);
- if (!j$.util.isUndefined(customTesterResult)) {
- return customTesterResult;
- }
- }
-
- if (a instanceof j$.Any) {
- result = a.jasmineMatches(b);
- if (result) {
- return true;
- }
- }
-
- if (b instanceof j$.Any) {
- result = b.jasmineMatches(a);
- if (result) {
- return true;
- }
- }
-
- if (b instanceof j$.ObjectContaining) {
- result = b.jasmineMatches(a);
- if (result) {
- return true;
- }
- }
-
- if (a instanceof Error && b instanceof Error) {
- return a.message == b.message;
- }
-
- // Identical objects are equal. `0 === -0`, but they aren't identical.
- // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
- if (a === b) { return a !== 0 || 1 / a == 1 / b; }
- // A strict comparison is necessary because `null == undefined`.
- if (a === null || b === null) { return a === b; }
- var className = Object.prototype.toString.call(a);
- if (className != Object.prototype.toString.call(b)) { return false; }
- switch (className) {
- // Strings, numbers, dates, and booleans are compared by value.
- case '[object String]':
- // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
- // equivalent to `new String("5")`.
- return a == String(b);
- case '[object Number]':
- // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
- // other numeric values.
- return a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
- case '[object Date]':
- case '[object Boolean]':
- // Coerce dates and booleans to numeric primitive values. Dates are compared by their
- // millisecond representations. Note that invalid dates with millisecond representations
- // of `NaN` are not equivalent.
- return +a == +b;
- // RegExps are compared by their source patterns and flags.
- case '[object RegExp]':
- return a.source == b.source &&
- a.global == b.global &&
- a.multiline == b.multiline &&
- a.ignoreCase == b.ignoreCase;
- }
- if (typeof a != 'object' || typeof b != 'object') { return false; }
- // Assume equality for cyclic structures. The algorithm for detecting cyclic
- // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
- var length = aStack.length;
- while (length--) {
- // Linear search. Performance is inversely proportional to the number of
- // unique nested structures.
- if (aStack[length] == a) { return bStack[length] == b; }
- }
- // Add the first object to the stack of traversed objects.
- aStack.push(a);
- bStack.push(b);
- var size = 0;
- // Recursively compare objects and arrays.
- if (className == '[object Array]') {
- // Compare array lengths to determine if a deep comparison is necessary.
- size = a.length;
- result = size == b.length;
- if (result) {
- // Deep compare the contents, ignoring non-numeric properties.
- while (size--) {
- if (!(result = eq(a[size], b[size], aStack, bStack, customTesters))) { break; }
- }
- }
- } else {
- // Objects with different constructors are not equivalent, but `Object`s
- // from different frames are.
- var aCtor = a.constructor, bCtor = b.constructor;
- if (aCtor !== bCtor && !(isFunction(aCtor) && (aCtor instanceof aCtor) &&
- isFunction(bCtor) && (bCtor instanceof bCtor))) {
- return false;
- }
- // Deep compare objects.
- for (var key in a) {
- if (has(a, key)) {
- // Count the expected number of properties.
- size++;
- // Deep compare each member.
- if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
- }
- }
- // Ensure that both objects contain the same number of properties.
- if (result) {
- for (key in b) {
- if (has(b, key) && !(size--)) { break; }
- }
- result = !size;
- }
- }
- // Remove the first object from the stack of traversed objects.
- aStack.pop();
- bStack.pop();
-
- return result;
-
- function has(obj, key) {
- return obj.hasOwnProperty(key);
- }
-
- function isFunction(obj) {
- return typeof obj === 'function';
- }
- }
-};
-
-getJasmineRequireObj().toBe = function() {
- function toBe() {
- return {
- compare: function(actual, expected) {
- return {
- pass: actual === expected
- };
- }
- };
- }
-
- return toBe;
-};
-
-getJasmineRequireObj().toBeCloseTo = function() {
-
- function toBeCloseTo() {
- return {
- compare: function(actual, expected, precision) {
- if (precision !== 0) {
- precision = precision || 2;
- }
-
- return {
- pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
- };
- }
- };
- }
-
- return toBeCloseTo;
-};
-
-getJasmineRequireObj().toBeDefined = function() {
- function toBeDefined() {
- return {
- compare: function(actual) {
- return {
- pass: (void 0 !== actual)
- };
- }
- };
- }
-
- return toBeDefined;
-};
-
-getJasmineRequireObj().toBeFalsy = function() {
- function toBeFalsy() {
- return {
- compare: function(actual) {
- return {
- pass: !!!actual
- };
- }
- };
- }
-
- return toBeFalsy;
-};
-
-getJasmineRequireObj().toBeGreaterThan = function() {
-
- function toBeGreaterThan() {
- return {
- compare: function(actual, expected) {
- return {
- pass: actual > expected
- };
- }
- };
- }
-
- return toBeGreaterThan;
-};
-
-
-getJasmineRequireObj().toBeLessThan = function() {
- function toBeLessThan() {
- return {
-
- compare: function(actual, expected) {
- return {
- pass: actual < expected
- };
- }
- };
- }
-
- return toBeLessThan;
-};
-getJasmineRequireObj().toBeNaN = function(j$) {
-
- function toBeNaN() {
- return {
- compare: function(actual) {
- var result = {
- pass: (actual !== actual)
- };
-
- if (result.pass) {
- result.message = 'Expected actual not to be NaN.';
- } else {
- result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be NaN.'; };
- }
-
- return result;
- }
- };
- }
-
- return toBeNaN;
-};
-
-getJasmineRequireObj().toBeNull = function() {
-
- function toBeNull() {
- return {
- compare: function(actual) {
- return {
- pass: actual === null
- };
- }
- };
- }
-
- return toBeNull;
-};
-
-getJasmineRequireObj().toBeTruthy = function() {
-
- function toBeTruthy() {
- return {
- compare: function(actual) {
- return {
- pass: !!actual
- };
- }
- };
- }
-
- return toBeTruthy;
-};
-
-getJasmineRequireObj().toBeUndefined = function() {
-
- function toBeUndefined() {
- return {
- compare: function(actual) {
- return {
- pass: void 0 === actual
- };
- }
- };
- }
-
- return toBeUndefined;
-};
-
-getJasmineRequireObj().toContain = function() {
- function toContain(util, customEqualityTesters) {
- customEqualityTesters = customEqualityTesters || [];
-
- return {
- compare: function(actual, expected) {
-
- return {
- pass: util.contains(actual, expected, customEqualityTesters)
- };
- }
- };
- }
-
- return toContain;
-};
-
-getJasmineRequireObj().toEqual = function() {
-
- function toEqual(util, customEqualityTesters) {
- customEqualityTesters = customEqualityTesters || [];
-
- return {
- compare: function(actual, expected) {
- var result = {
- pass: false
- };
-
- result.pass = util.equals(actual, expected, customEqualityTesters);
-
- return result;
- }
- };
- }
-
- return toEqual;
-};
-
-getJasmineRequireObj().toHaveBeenCalled = function(j$) {
-
- function toHaveBeenCalled() {
- return {
- compare: function(actual) {
- var result = {};
-
- if (!j$.isSpy(actual)) {
- throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
- }
-
- if (arguments.length > 1) {
- throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
- }
-
- result.pass = actual.calls.any();
-
- result.message = result.pass ?
- 'Expected spy ' + actual.and.identity() + ' not to have been called.' :
- 'Expected spy ' + actual.and.identity() + ' to have been called.';
-
- return result;
- }
- };
- }
-
- return toHaveBeenCalled;
-};
-
-getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
-
- function toHaveBeenCalledWith(util, customEqualityTesters) {
- return {
- compare: function() {
- var args = Array.prototype.slice.call(arguments, 0),
- actual = args[0],
- expectedArgs = args.slice(1),
- result = { pass: false };
-
- if (!j$.isSpy(actual)) {
- throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
- }
-
- if (!actual.calls.any()) {
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' to have been called with ' + j$.pp(expectedArgs) + ' but it was never called.'; };
- return result;
- }
-
- if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
- result.pass = true;
- result.message = function() { return 'Expected spy ' + actual.and.identity() + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
- } else {
- 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, '') + '.'; };
- }
-
- return result;
- }
- };
- }
-
- return toHaveBeenCalledWith;
-};
-
-getJasmineRequireObj().toMatch = function() {
-
- function toMatch() {
- return {
- compare: function(actual, expected) {
- var regexp = new RegExp(expected);
-
- return {
- pass: regexp.test(actual)
- };
- }
- };
- }
-
- return toMatch;
-};
-
-getJasmineRequireObj().toThrow = function(j$) {
-
- function toThrow(util) {
- return {
- compare: function(actual, expected) {
- var result = { pass: false },
- threw = false,
- thrown;
-
- if (typeof actual != 'function') {
- throw new Error('Actual is not a Function');
- }
-
- try {
- actual();
- } catch (e) {
- threw = true;
- thrown = e;
- }
-
- if (!threw) {
- result.message = 'Expected function to throw an exception.';
- return result;
- }
-
- if (arguments.length == 1) {
- result.pass = true;
- result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
-
- return result;
- }
-
- if (util.equals(thrown, expected)) {
- result.pass = true;
- result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
- } else {
- result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
- }
-
- return result;
- }
- };
- }
-
- return toThrow;
-};
-
-getJasmineRequireObj().toThrowError = function(j$) {
- function toThrowError (util) {
- return {
- compare: function(actual) {
- var threw = false,
- pass = {pass: true},
- fail = {pass: false},
- thrown,
- errorType,
- message,
- regexp,
- name,
- constructorName;
-
- if (typeof actual != 'function') {
- throw new Error('Actual is not a Function');
- }
-
- extractExpectedParams.apply(null, arguments);
-
- try {
- actual();
- } catch (e) {
- threw = true;
- thrown = e;
- }
-
- if (!threw) {
- fail.message = 'Expected function to throw an Error.';
- return fail;
- }
-
- if (!(thrown instanceof Error)) {
- fail.message = function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; };
- return fail;
- }
-
- if (arguments.length == 1) {
- pass.message = 'Expected function not to throw an Error, but it threw ' + fnNameFor(thrown) + '.';
- return pass;
- }
-
- if (errorType) {
- name = fnNameFor(errorType);
- constructorName = fnNameFor(thrown.constructor);
- }
-
- if (errorType && message) {
- if (thrown.constructor == errorType && util.equals(thrown.message, message)) {
- pass.message = function() { return 'Expected function not to throw ' + name + ' with message ' + j$.pp(message) + '.'; };
- return pass;
- } else {
- fail.message = function() { return 'Expected function to throw ' + name + ' with message ' + j$.pp(message) +
- ', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; };
- return fail;
- }
- }
-
- if (errorType && regexp) {
- if (thrown.constructor == errorType && regexp.test(thrown.message)) {
- pass.message = function() { return 'Expected function not to throw ' + name + ' with message matching ' + j$.pp(regexp) + '.'; };
- return pass;
- } else {
- fail.message = function() { return 'Expected function to throw ' + name + ' with message matching ' + j$.pp(regexp) +
- ', but it threw ' + constructorName + ' with message ' + j$.pp(thrown.message) + '.'; };
- return fail;
- }
- }
-
- if (errorType) {
- if (thrown.constructor == errorType) {
- pass.message = 'Expected function not to throw ' + name + '.';
- return pass;
- } else {
- fail.message = 'Expected function to throw ' + name + ', but it threw ' + constructorName + '.';
- return fail;
- }
- }
-
- if (message) {
- if (thrown.message == message) {
- pass.message = function() { return 'Expected function not to throw an exception with message ' + j$.pp(message) + '.'; };
- return pass;
- } else {
- fail.message = function() { return 'Expected function to throw an exception with message ' + j$.pp(message) +
- ', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; };
- return fail;
- }
- }
-
- if (regexp) {
- if (regexp.test(thrown.message)) {
- pass.message = function() { return 'Expected function not to throw an exception with a message matching ' + j$.pp(regexp) + '.'; };
- return pass;
- } else {
- fail.message = function() { return 'Expected function to throw an exception with a message matching ' + j$.pp(regexp) +
- ', but it threw an exception with message ' + j$.pp(thrown.message) + '.'; };
- return fail;
- }
- }
-
- function fnNameFor(func) {
- return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
- }
-
- function extractExpectedParams() {
- if (arguments.length == 1) {
- return;
- }
-
- if (arguments.length == 2) {
- var expected = arguments[1];
-
- if (expected instanceof RegExp) {
- regexp = expected;
- } else if (typeof expected == 'string') {
- message = expected;
- } else if (checkForAnErrorType(expected)) {
- errorType = expected;
- }
-
- if (!(errorType || message || regexp)) {
- throw new Error('Expected is not an Error, string, or RegExp.');
- }
- } else {
- if (checkForAnErrorType(arguments[1])) {
- errorType = arguments[1];
- } else {
- throw new Error('Expected error type is not an Error.');
- }
-
- if (arguments[2] instanceof RegExp) {
- regexp = arguments[2];
- } else if (typeof arguments[2] == 'string') {
- message = arguments[2];
- } else {
- throw new Error('Expected error message is not a string or RegExp.');
- }
- }
- }
-
- function checkForAnErrorType(type) {
- if (typeof type !== 'function') {
- return false;
- }
-
- var Surrogate = function() {};
- Surrogate.prototype = type.prototype;
- return (new Surrogate()) instanceof Error;
- }
- }
- };
- }
-
- return toThrowError;
-};
-
-getJasmineRequireObj().version = function() {
- return '2.0.1';
-};
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/junit_reporter.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/junit_reporter.js
index ccddaaf84..eafcd8bed 100644
--- a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/junit_reporter.js
+++ b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/junit_reporter.js
@@ -12,7 +12,9 @@
function trim(str) { return str.replace(/^\s+/, "" ).replace(/\s+$/, "" ); }
function elapsed(start, end) { return (end - start)/1000; }
function isFailed(obj) { return obj.status === "failed"; }
- function isSkipped(obj) { return obj.status === "pending"; }
+ function isSkipped(obj) {
+ return obj.status === "pending" || obj.status === "excluded" || obj.status === "notApplicable";
+ }
function pad(n) { return n < 10 ? '0'+n : n; }
function extend(dupe, obj) { // performs a shallow copy of all props of `obj` onto `dupe`
for (var prop in obj) {
@@ -30,12 +32,23 @@
pad(d.getMinutes()) + ':' +
pad(d.getSeconds());
}
+ // XML 1.0 has no way to represent these, escaped or not, and a single one
+ // makes the whole report unparseable; they are written out as \uXXXX text.
+ var XML_FORBIDDEN = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\uFFFE\uFFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?/g, ">")
.replace(/\"/g, """)
- .replace(/\'/g, "'")
- .replace(/\&/g, "&");
+ .replace(/\'/g, "'");
+ }
+ function cdata(str) {
+ return '/g, ']]]]>') + ']]>';
}
function getQualifiedFilename(path, filename, separator) {
if (path && path.substr(-1) !== separator && filename.substr(0) !== separator) {
@@ -143,6 +156,9 @@
};
self.suiteDone = function(suite) {
suite = getSuite(suite);
+ // Errors that belong to the suite itself (an afterAll, or an error
+ // reported while no spec was running), not to any one spec.
+ suite._ownFailures = suite.failedExpectations || [];
// disabled suite (xdescribe) -- suiteStarted was never called
if (suite._parent === UNDEFINED) {
self.suiteStarted(suite);
@@ -151,11 +167,12 @@
suite._endTime = new Date();
currentSuite = suite._parent;
};
- self.jasmineDone = function() {
+ self.jasmineDone = function(result) {
var output = '';
for (var i = 0; i < suites.length; i++) {
output += self.getOrWriteNestedOutput(suites[i]);
}
+ output += runFailuresAsXml(result || {});
// if we have anything to write here, write out the consolidated file
if (output) {
wrapOutputAndWriteFile(self.filePrefix, output);
@@ -265,26 +282,67 @@
}
function suiteAsXml(suite) {
-
- var fullyQualifiedSuiteName = getFullyQualifiedSuiteName(suite);
+ var ownFailures = suite._ownFailures || [];
+ var extraCase = ownFailures.length ? 1 : 0;
var xml = '\n ';
for (var i = 0; i < suite._specs.length; i++) {
xml += specAsXml(suite._specs[i]);
}
-
+ if (extraCase) {
+ xml += failedCaseAsXml(getFullyQualifiedSuiteName(suite), "(suite-level errors)",
+ elapsed(suite._startTime, suite._endTime), ownFailures);
+ }
xml += '\n ';
return xml;
}
+ // Run-level failures (errors outside any suite, or a run that never
+ // completed) as their own suite, so JUnit consumers count them.
+ function runFailuresAsXml(result) {
+ var failures = (result.failedExpectations || []).slice();
+ if (result.overallStatus === "incomplete") {
+ failures.push({ message: "Run incomplete: " + result.incompleteReason });
+ }
+ if (!failures.length) {
+ return '';
+ }
+ var xml = '\n ';
+ xml += failedCaseAsXml("Jasmine run", "(run-level errors)", 0, failures);
+ xml += '\n ';
+ return xml;
+ }
+ function failedCaseAsXml(classname, name, time, failures) {
+ var xml = '\n ';
+ xml += failuresAsXml(failures);
+ xml += '\n ';
+ return xml;
+ }
+ function failuresAsXml(failures) {
+ var xml = '';
+ for (var i = 0, failure; i < failures.length; i++) {
+ failure = failures[i];
+ xml += '\n ';
+ xml += cdata(trim(failure.stack || failure.message || ""));
+ xml += '\n ';
+ }
+ return xml;
+ }
function specAsXml(spec) {
var xml = '\n ';
} else if (isFailed(spec)) {
- for (var i = 0, failure; i < spec.failedExpectations.length; i++) {
- failure = spec.failedExpectations[i];
- xml += '\n ';
- xml += '';
- xml += '\n ';
- }
+ xml += failuresAsXml(spec.failedExpectations);
}
xml += '\n ';
return xml;
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/terminal_reporter.js b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/terminal_reporter.js
index cda6e0627..78b7d2fce 100644
--- a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/terminal_reporter.js
+++ b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine-reporters/terminal_reporter.js
@@ -10,7 +10,9 @@
function elapsed(start, end) { return (end - start)/1000; }
function isFailed(obj) { return obj.status === "failed"; }
- function isSkipped(obj) { return obj.status === "pending"; }
+ function isSkipped(obj) {
+ return obj.status === "pending" || obj.status === "excluded" || obj.status === "notApplicable";
+ }
function extend(dupe, obj) { // performs a shallow copy of all props of `obj` onto `dupe`
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
@@ -66,8 +68,19 @@
totalSpecsExecuted = 0,
totalSpecsSkipped = 0,
totalSpecsFailed = 0,
+ totalOtherFailures = 0,
totalSpecsDefined;
+ function logFailures(depth, header, failures) {
+ log(indentWithLevel(depth, inColor(header, 'red')));
+ for (var i = 0; i < failures.length; i++) {
+ log(inColor(indentWithLevel(depth, indent_string + failures[i].message), 'red'));
+ if (failures[i].stack) {
+ log(indentWithLevel(depth, indent_string + failures[i].stack));
+ }
+ }
+ }
+
var __suites = {}, __specs = {};
function getSuite(suite) {
__suites[suite.id] = extend(__suites[suite.id] || {}, suite);
@@ -189,6 +202,10 @@
};
self.suiteDone = function(suite) {
suite = getSuite(suite);
+ if (suite.failedExpectations && suite.failedExpectations.length) {
+ totalOtherFailures++;
+ logFailures(1, 'Suite-level errors in "' + suite.fullName + '":', suite.failedExpectations);
+ }
// disabled suite (xdescribe) -- suiteStarted was never called
if (suite._parent === UNDEFINED) {
self.suiteStarted(suite);
@@ -212,7 +229,21 @@
str = passed + ' of ' + total + ' passed (' + skipped + ' skipped)';
log(indentWithLevel(suite._depth, inColor(str+'.', color)));
};
- self.jasmineDone = function() {
+ self.jasmineDone = function(result) {
+ result = result || {};
+ if (result.failedExpectations && result.failedExpectations.length) {
+ totalOtherFailures++;
+ logFailures(1, 'Run-level errors:', result.failedExpectations);
+ }
+ if (result.overallStatus === "incomplete") {
+ totalOtherFailures++;
+ log(inColor('Run incomplete: ' + result.incompleteReason, 'red'));
+ }
+ var deprecations = result.deprecationWarnings || [];
+ for (var d = 0; d < deprecations.length; d++) {
+ log('DEPRECATION: ' + deprecations[d].message);
+ }
+ var failedOverall = totalSpecsFailed > 0 || totalOtherFailures > 0;
var now = new Date(),
dur = elapsed(startTime, now),
total = totalSpecsDefined || totalSpecsExecuted,
@@ -222,9 +253,11 @@
fail_str = totalSpecsFailed + (totalSpecsFailed === 1 ? " failure, " : " failures, "),
skip_str = skipped + " skipped, ",
disabled_str = disabled + " disabled in ",
- summary_str = spec_str + fail_str + skip_str + disabled_str + dur + "s.",
- result_str = (totalSpecsFailed && "FAILURE: " || "SUCCESS: ") + summary_str,
- result_color = totalSpecsFailed && "red+bold" || "green+bold";
+ other_str = totalOtherFailures === 0 ? "" :
+ totalOtherFailures + (totalOtherFailures === 1 ? " suite/run-level error, " : " suite/run-level errors, "),
+ summary_str = spec_str + fail_str + other_str + skip_str + disabled_str + dur + "s.",
+ result_str = (failedOverall ? "FAILURE: " : "SUCCESS: ") + summary_str,
+ result_color = failedOverall ? "red+bold" : "green+bold";
if (self.verbosity === 2) {
log('');
diff --git a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine.d.ts b/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine.d.ts
deleted file mode 100644
index 7ccfa9594..000000000
--- a/test-app/app/src/main/assets/app/Infrastructure/Jasmine/jasmine.d.ts
+++ /dev/null
@@ -1,434 +0,0 @@
-// Type definitions for Jasmine 2.0
-// Project: http://pivotal.github.com/jasmine/
-// Definitions by: Boris Yankov , Theodore Brown
-// Definitions: https://github.com/borisyankov/DefinitelyTyped
-
-
-// For ddescribe / iit use : https://github.com/borisyankov/DefinitelyTyped/blob/master/karma-jasmine/karma-jasmine.d.ts
-
-declare function describe(description: string, specDefinitions: () => void): void;
-// declare function ddescribe(description: string, specDefinitions: () => void): void; Not a part of jasmine. Angular team adds these
-declare function xdescribe(description: string, specDefinitions: () => void): void;
-
-declare function it(expectation: string, assertion?: () => void): void;
-declare function it(expectation: string, assertion?: (done: () => void) => void): void;
-// declare function iit(expectation: string, assertion?: () => void): void; Not a part of jasmine. Angular team adds these
-// declare function iit(expectation: string, assertion?: (done: () => void) => void): void; Not a part of jasmine. Angular team adds these
-declare function xit(expectation: string, assertion?: () => void): void;
-declare function xit(expectation: string, assertion?: (done: () => void) => void): void;
-
-/** If you call the function pending anywhere in the spec body, no matter the expectations, the spec will be marked pending. */
-declare function pending(): void;
-
-declare function beforeEach(action: () => void): void;
-declare function beforeEach(action: (done: () => void) => void): void;
-declare function afterEach(action: () => void): void;
-declare function afterEach(action: (done: () => void) => void): void;
-
-declare function expect(spy: Function): jasmine.Matchers;
-declare function expect(actual: any): jasmine.Matchers;
-
-declare function spyOn(object: any, method: string): jasmine.Spy;
-
-declare function runs(asyncMethod: Function): void;
-declare function waitsFor(latchMethod: () => boolean, failureMessage?: string, timeout?: number): void;
-declare function waits(timeout?: number): void;
-
-declare module jasmine {
-
- var clock: () => Clock;
-
- function any(aclass: any): Any;
- function objectContaining(sample: any): ObjectContaining;
- function createSpy(name: string, originalFn?: Function): Spy;
- function createSpyObj(baseName: string, methodNames: any[]): any;
- function createSpyObj(baseName: string, methodNames: any[]): T;
- function pp(value: any): string;
- function getEnv(): Env;
- function addMatchers(matchers: any): Any;
-
- interface Any {
-
- new (expectedClass: any): any;
-
- jasmineMatches(other: any): boolean;
- jasmineToString(): string;
- }
-
- interface ObjectContaining {
- new (sample: any): any;
-
- jasmineMatches(other: any, mismatchKeys: any[], mismatchValues: any[]): boolean;
- jasmineToString(): string;
- }
-
- interface Block {
-
- new (env: Env, func: SpecFunction, spec: Spec): any;
-
- execute(onComplete: () => void): void;
- }
-
- interface WaitsBlock extends Block {
- new (env: Env, timeout: number, spec: Spec): any;
- }
-
- interface WaitsForBlock extends Block {
- new (env: Env, timeout: number, latchFunction: SpecFunction, message: string, spec: Spec): any;
- }
-
- interface Clock {
- install(): void;
- uninstall(): void;
- /** Calls to any registered callback are triggered when the clock is ticked forward via the jasmine.clock().tick function, which takes a number of milliseconds. */
- tick(ms: number): void;
- }
-
- interface Env {
- setTimeout: any;
- clearTimeout: void;
- setInterval: any;
- clearInterval: void;
- updateInterval: number;
-
- currentSpec: Spec;
-
- matchersClass: Matchers;
-
- version(): any;
- versionString(): string;
- nextSpecId(): number;
- addReporter(reporter: Reporter): void;
- execute(): void;
- describe(description: string, specDefinitions: () => void): Suite;
- // ddescribe(description: string, specDefinitions: () => void): Suite; Not a part of jasmine. Angular team adds these
- beforeEach(beforeEachFunction: () => void): void;
- currentRunner(): Runner;
- afterEach(afterEachFunction: () => void): void;
- xdescribe(desc: string, specDefinitions: () => void): XSuite;
- it(description: string, func: () => void): Spec;
- // iit(description: string, func: () => void): Spec; Not a part of jasmine. Angular team adds these
- xit(desc: string, func: () => void): XSpec;
- compareRegExps_(a: RegExp, b: RegExp, mismatchKeys: string[], mismatchValues: string[]): boolean;
- compareObjects_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean;
- equals_(a: any, b: any, mismatchKeys: string[], mismatchValues: string[]): boolean;
- contains_(haystack: any, needle: any): boolean;
- addEqualityTester(equalityTester: (a: any, b: any, env: Env, mismatchKeys: string[], mismatchValues: string[]) => boolean): void;
- specFilter(spec: Spec): boolean;
- }
-
- interface FakeTimer {
-
- new (): any;
-
- reset(): void;
- tick(millis: number): void;
- runFunctionsWithinRange(oldMillis: number, nowMillis: number): void;
- scheduleFunction(timeoutKey: any, funcToCall: () => void, millis: number, recurring: boolean): void;
- }
-
- interface HtmlReporter {
- new (): any;
- }
-
- interface HtmlSpecFilter {
- new (): any;
- }
-
- interface Result {
- type: string;
- }
-
- interface NestedResults extends Result {
- description: string;
-
- totalCount: number;
- passedCount: number;
- failedCount: number;
-
- skipped: boolean;
-
- rollupCounts(result: NestedResults): void;
- log(values: any): void;
- getItems(): Result[];
- addResult(result: Result): void;
- passed(): boolean;
- }
-
- interface MessageResult extends Result {
- values: any;
- trace: Trace;
- }
-
- interface ExpectationResult extends Result {
- matcherName: string;
- passed(): boolean;
- expected: any;
- actual: any;
- message: string;
- trace: Trace;
- }
-
- interface Trace {
- name: string;
- message: string;
- stack: any;
- }
-
- interface PrettyPrinter {
-
- new (): any;
-
- format(value: any): void;
- iterateObject(obj: any, fn: (property: string, isGetter: boolean) => void): void;
- emitScalar(value: any): void;
- emitString(value: string): void;
- emitArray(array: any[]): void;
- emitObject(obj: any): void;
- append(value: any): void;
- }
-
- interface StringPrettyPrinter extends PrettyPrinter {
- }
-
- interface Queue {
-
- new (env: any): any;
-
- env: Env;
- ensured: boolean[];
- blocks: Block[];
- running: boolean;
- index: number;
- offset: number;
- abort: boolean;
-
- addBefore(block: Block, ensure?: boolean): void;
- add(block: any, ensure?: boolean): void;
- insertNext(block: any, ensure?: boolean): void;
- start(onComplete?: () => void): void;
- isRunning(): boolean;
- next_(): void;
- results(): NestedResults;
- }
-
- interface Matchers {
-
- new (env: Env, actual: any, spec: Env, isNot?: boolean): any;
-
- env: Env;
- actual: any;
- spec: Env;
- isNot?: boolean;
- message(): any;
-
- toBe(expected: any): boolean;
- toNotBe(expected: any): boolean;
- toEqual(expected: any): boolean;
- toNotEqual(expected: any): boolean;
- toMatch(expected: any): boolean;
- toNotMatch(expected: any): boolean;
- toBeDefined(): boolean;
- toBeUndefined(): boolean;
- toBeNull(): boolean;
- toBeNaN(): boolean;
- toBeTruthy(): boolean;
- toBeFalsy(): boolean;
- toHaveBeenCalled(): boolean;
- wasNotCalled(): boolean;
- toHaveBeenCalledWith(...params: any[]): boolean;
- toContain(expected: any): boolean;
- toNotContain(expected: any): boolean;
- toBeLessThan(expected: any): boolean;
- toBeGreaterThan(expected: any): boolean;
- toBeCloseTo(expected: any, precision: any): boolean;
- toContainHtml(expected: string): boolean;
- toContainText(expected: string): boolean;
- toThrow(expected?: any): boolean;
- toThrowError(expected?: any): boolean;
- not: Matchers;
-
- Any: Any;
- }
-
- interface Reporter {
- reportRunnerStarting(runner: Runner): void;
- reportRunnerResults(runner: Runner): void;
- reportSuiteResults(suite: Suite): void;
- reportSpecStarting(spec: Spec): void;
- reportSpecResults(spec: Spec): void;
- log(str: string): void;
- }
-
- interface MultiReporter extends Reporter {
- addReporter(reporter: Reporter): void;
- }
-
- interface Runner {
-
- new (env: Env): any;
-
- execute(): void;
- beforeEach(beforeEachFunction: SpecFunction): void;
- afterEach(afterEachFunction: SpecFunction): void;
- finishCallback(): void;
- addSuite(suite: Suite): void;
- add(block: Block): void;
- specs(): Spec[];
- suites(): Suite[];
- topLevelSuites(): Suite[];
- results(): NestedResults;
- }
-
- interface SpecFunction {
- (spec?: Spec): void;
- }
-
- interface SuiteOrSpec {
- id: number;
- env: Env;
- description: string;
- queue: Queue;
- }
-
- interface Spec extends SuiteOrSpec {
-
- new (env: Env, suite: Suite, description: string): any;
-
- suite: Suite;
-
- afterCallbacks: SpecFunction[];
- spies_: Spy[];
-
- results_: NestedResults;
- matchersClass: Matchers;
-
- getFullName(): string;
- results(): NestedResults;
- log(arguments: any): any;
- runs(func: SpecFunction): Spec;
- addToQueue(block: Block): void;
- addMatcherResult(result: Result): void;
- expect(actual: any): any;
- waits(timeout: number): Spec;
- waitsFor(latchFunction: SpecFunction, timeoutMessage?: string, timeout?: number): Spec;
- fail(e?: any): void;
- getMatchersClass_(): Matchers;
- addMatchers(matchersPrototype: any): void;
- finishCallback(): void;
- finish(onComplete?: () => void): void;
- after(doAfter: SpecFunction): void;
- execute(onComplete?: () => void): any;
- addBeforesAndAftersToQueue(): void;
- explodes(): void;
- spyOn(obj: any, methodName: string, ignoreMethodDoesntExist: boolean): Spy;
- removeAllSpies(): void;
- }
-
- interface XSpec {
- id: number;
- runs(): void;
- }
-
- interface Suite extends SuiteOrSpec {
-
- new (env: Env, description: string, specDefinitions: () => void, parentSuite: Suite): any;
-
- parentSuite: Suite;
-
- getFullName(): string;
- finish(onComplete?: () => void): void;
- beforeEach(beforeEachFunction: SpecFunction): void;
- afterEach(afterEachFunction: SpecFunction): void;
- results(): NestedResults;
- add(suiteOrSpec: SuiteOrSpec): void;
- specs(): Spec[];
- suites(): Suite[];
- children(): any[];
- execute(onComplete?: () => void): void;
- }
-
- interface XSuite {
- execute(): void;
- }
-
- interface Spy {
- (...params: any[]): any;
-
- identity: string;
- and: SpyAnd;
- calls: Calls;
- mostRecentCall: { args: any[]; };
- argsForCall: any[];
- wasCalled: boolean;
- callCount: number;
- }
-
- interface SpyAnd {
- /** By chaining the spy with and.callThrough, the spy will still track all calls to it but in addition it will delegate to the actual implementation. */
- callThrough(): void;
- /** By chaining the spy with and.returnValue, all calls to the function will return a specific value. */
- returnValue(val: any): void;
- /** By chaining the spy with and.callFake, all calls to the spy will delegate to the supplied function. */
- callFake(fn: Function): void;
- /** By chaining the spy with and.throwError, all calls to the spy will throw the specified value. */
- throwError(msg: string): void;
- /** When a calling strategy is used for a spy, the original stubbing behavior can be returned at any time with and.stub. */
- stub(): void;
- }
-
- interface Calls {
- /** By chaining the spy with calls.any(), will return false if the spy has not been called at all, and then true once at least one call happens. **/
- any(): boolean;
- /** By chaining the spy with calls.count(), will return the number of times the spy was called **/
- count(): number;
- /** By chaining the spy with calls.argsFor(), will return the arguments passed to call number index **/
- argsFor(index: number): any[];
- /** By chaining the spy with calls.allArgs(), will return the arguments to all calls **/
- allArgs(): any[];
- /** By chaining the spy with calls.all(), will return the context (the this) and arguments passed all calls **/
- all(): any;
- /** By chaining the spy with calls.mostRecent(), will return the context (the this) and arguments for the most recent call **/
- mostRecent(): any;
- /** By chaining the spy with calls.first(), will return the context (the this) and arguments for the first call **/
- first(): any;
- /** By chaining the spy with calls.reset(), will clears all tracking for a spy **/
- reset(): void;
- }
-
- interface Util {
- inherit(childClass: Function, parentClass: Function): any;
- formatException(e: any): any;
- htmlEscape(str: string): string;
- argsToArray(args: any): any;
- extend(destination: any, source: any): any;
- }
-
- interface JsApiReporter extends Reporter {
-
- started: boolean;
- finished: boolean;
- result: any;
- messages: any;
-
- new (): any;
-
- suites(): Suite[];
- summarize_(suiteOrSpec: SuiteOrSpec): any;
- results(): any;
- resultsForSpec(specId: any): any;
- log(str: any): any;
- resultsForSpecs(specIds: any): any;
- summarizeResult_(result: any): any;
- }
-
- interface Jasmine {
- Spec: Spec;
- clock: Clock;
- util: Util;
- }
-
- export var HtmlReporter: HtmlReporter;
- export var HtmlSpecFilter: HtmlSpecFilter;
- export var DEFAULT_TIMEOUT_INTERVAL: number;
-}
diff --git a/test-app/app/src/main/assets/app/MyActivity.js b/test-app/app/src/main/assets/app/MyActivity.js
index fbea5688e..05f1139b7 100644
--- a/test-app/app/src/main/assets/app/MyActivity.js
+++ b/test-app/app/src/main/assets/app/MyActivity.js
@@ -21,6 +21,8 @@
}
}
*/
+var testRunStarted = false;
+
var MyActivity = (function (_super) {
__extends(MyActivity, _super);
function MyActivity() {
@@ -29,8 +31,13 @@ var MyActivity = (function (_super) {
MyActivity.prototype.onCreate = function (bundle) {
_super.prototype.onCreate.call(this, bundle);
- require('./tests/testsWithContext').run(this);
- execute(); //run jasmine
+ // A recreated activity in the same process must not register or run the
+ // suite again: Jasmine rejects both once the run has started.
+ if (!testRunStarted) {
+ testRunStarted = true;
+ require('./tests/testsWithContext').run(this);
+ require('./Infrastructure/Jasmine/boot').execute();
+ }
var layout = new android.widget.LinearLayout(this);
layout.setOrientation(1);
diff --git a/test-app/app/src/main/assets/app/boot.js b/test-app/app/src/main/assets/app/boot.js
index 8d38bfad7..62f840c46 100644
--- a/test-app/app/src/main/assets/app/boot.js
+++ b/test-app/app/src/main/assets/app/boot.js
@@ -32,7 +32,7 @@ global.__JUnitSaveResults = function (unitTestResults) {
if (com.tns.tests.JniBench.isEnabled()) {
require("./tests/benchmarks/jniBenchmarks").run();
} else {
- require('./Infrastructure/Jasmine/jasmine-2.0.1/boot'); //runs jasmine, attaches the junitOutputter
+ require('./Infrastructure/Jasmine/boot');
require("./mainpage");
}
\ No newline at end of file
diff --git a/test-app/app/src/main/assets/app/shared b/test-app/app/src/main/assets/app/shared
index aa7f8cfcc..2cb9c23ce 160000
--- a/test-app/app/src/main/assets/app/shared
+++ b/test-app/app/src/main/assets/app/shared
@@ -1 +1 @@
-Subproject commit aa7f8cfcc29ac2945e190fafe1259827ab6ab2e6
+Subproject commit 2cb9c23ceae51f05e37b170cbbe0bafa4788c9ce
diff --git a/test-app/app/src/main/assets/app/tests/console/logTests.js b/test-app/app/src/main/assets/app/tests/console/logTests.js
index 6f4ea0e2f..c10fe0ef7 100644
--- a/test-app/app/src/main/assets/app/tests/console/logTests.js
+++ b/test-app/app/src/main/assets/app/tests/console/logTests.js
@@ -1,4 +1,4 @@
-describe("Test JSONObject conversions", () => {
+describe("Test console.log arguments", () => {
it("console.log with number param should not crash", () => {
console.log(123);
});
diff --git a/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js b/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js
index ddeee9bf0..0fb80f9de 100644
--- a/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js
+++ b/test-app/app/src/main/assets/app/tests/discardedExceptionsTest.js
@@ -1,3 +1,5 @@
+const { raisesGlobalErrors } = require("../Infrastructure/Jasmine/globalErrorSpy");
+
describe("Tests discarded exception ", function () {
var originalOnDiscardedError = null;
@@ -5,7 +7,7 @@ describe("Tests discarded exception ", function () {
originalOnDiscardedError = global.__onDiscardedError;
});
- it("should report discarded exception", function () {
+ it("should report discarded exception", raisesGlobalErrors(function (done) {
var reportedException = null;
global.__onDiscardedError = (error) => {
@@ -20,7 +22,8 @@ describe("Tests discarded exception ", function () {
expect(reportedException.nativeException.getMessage()).toBe('Exception to suppress');
expect(reportedException.message).toBe('Exception to suppress');
expect(reportedException.stackTrace).toContain('com.tns.tests.DiscardedExceptionTest.reportSupressedException');
- });
+ done();
+ }));
afterEach(function() {
global.__onDiscardedError = originalOnDiscardedError;
diff --git a/test-app/app/src/main/assets/app/tests/dispatchCallbacksOnUiThreadTests.js b/test-app/app/src/main/assets/app/tests/dispatchCallbacksOnUiThreadTests.js
index fba118c8e..cb9da41e8 100644
--- a/test-app/app/src/main/assets/app/tests/dispatchCallbacksOnUiThreadTests.js
+++ b/test-app/app/src/main/assets/app/tests/dispatchCallbacksOnUiThreadTests.js
@@ -1,28 +1,22 @@
describe("Tests dispatch callbacks on UI thread ", function () {
- it("TestProcessDataCallbackShouldBeExecutedOnUiThread", function () {
+ it("TestProcessDataCallbackFromBackgroundThreadReceivesAllData", function (done) {
- __log("TEST: TestProcessDataCallbackShouldBeExecutedOnUiThread");
+ __log("TEST: TestProcessDataCallbackFromBackgroundThreadReceivesAllData");
+ var received = [];
var D = com.tns.tests.DispatchAsyncOpOnUIThreadTest.extend("DispatchAsyncOpOnUIThreadTest", {
processData: function(index, data) {
- it("inner spec", function () {
- if (index === 0) {
- expect(data).toBe(123);
- } else if (index === 1) {
- expect(data).toBe(456);
- } else if (index === 2) {
- expect(data).toBe(789);
- } else {
- //one of the above has to be called ... else fail
- expect(true).toBe(false);
- }
- });
+ received.push([index, data]);
+ if (received.length === 3) {
+ expect(received).toEqual([[0, 123], [1, 456], [2, 789]]);
+ done();
+ }
}
});
-
+
var d = new D();
-
+
d.processDataAsync([123, 456, 789]);
});
});
diff --git a/test-app/app/src/main/assets/app/tests/kotlin/enums/testEnumsSupport.js b/test-app/app/src/main/assets/app/tests/kotlin/enums/testEnumsSupport.js
index 3ff0bd04d..e57b03ed5 100644
--- a/test-app/app/src/main/assets/app/tests/kotlin/enums/testEnumsSupport.js
+++ b/test-app/app/src/main/assets/app/tests/kotlin/enums/testEnumsSupport.js
@@ -1,4 +1,4 @@
-describe("Tests Kotlin extension functions support", function () {
+describe("Tests Kotlin enums support", function () {
it("Test Kotlin enum entries are accessible", function () {
var enumEntry = com.tns.tests.kotlin.enums.KotlinEnum.TEST_ENTRY;
diff --git a/test-app/app/src/main/assets/app/tests/testErrorEvents.js b/test-app/app/src/main/assets/app/tests/testErrorEvents.js
index 2e1cbd988..509db10c8 100644
--- a/test-app/app/src/main/assets/app/tests/testErrorEvents.js
+++ b/test-app/app/src/main/assets/app/tests/testErrorEvents.js
@@ -1,3 +1,5 @@
+const { raisesGlobalErrors } = require("../Infrastructure/Jasmine/globalErrorSpy");
+
describe("WHATWG error events", function () {
// Many tests exercise the global error path, which ends in the
// __onUncaughtError / __onDiscardedError hooks when a listener does not
@@ -47,7 +49,7 @@ describe("WHATWG error events", function () {
}, 25);
}
- it("reportError fires an 'error' listener with an ErrorEvent carrying error and message", function (done) {
+ it("reportError fires an 'error' listener with an ErrorEvent carrying error and message", raisesGlobalErrors(function (done) {
var err = new Error("x");
var received = null;
onGlobal("error", function (e) {
@@ -67,9 +69,9 @@ describe("WHATWG error events", function () {
expect(uncaught.length).toBe(0);
done();
});
- });
+ }));
- it("reportError without preventDefault still invokes __onUncaughtError (back-compat)", function () {
+ it("reportError without preventDefault still invokes __onUncaughtError (back-compat)", raisesGlobalErrors(function (done) {
var err = new Error("back-compat");
var received = null;
onGlobal("error", function (e) {
@@ -82,7 +84,8 @@ describe("WHATWG error events", function () {
expect(received.error).toBe(err);
expect(uncaught.length).toBe(1);
expect(uncaught[0]).toBe(err);
- });
+ done();
+ }));
it("reportError throws TypeError when called with no arguments", function () {
expect(function () {
@@ -90,7 +93,7 @@ describe("WHATWG error events", function () {
}).toThrowError(TypeError);
});
- it("a discarded Java exception dispatches an 'error' event before __onDiscardedError", function () {
+ it("a discarded Java exception dispatches an 'error' event before __onDiscardedError", raisesGlobalErrors(function (done) {
var received = null;
onGlobal("error", function (e) {
received = e;
@@ -106,9 +109,10 @@ describe("WHATWG error events", function () {
// Unprevented, so the existing hook still fires (back-compat).
expect(discarded.length).toBe(1);
expect(discarded[0]).toBe(received.error);
- });
+ done();
+ }));
- it("preventDefault() on the 'error' event suppresses __onDiscardedError", function () {
+ it("preventDefault() on the 'error' event suppresses __onDiscardedError", raisesGlobalErrors(function (done) {
var received = null;
onGlobal("error", function (e) {
received = e;
@@ -120,7 +124,8 @@ describe("WHATWG error events", function () {
expect(received).not.toBeNull();
expect(discarded.length).toBe(0);
- });
+ done();
+ }));
describe("constructors and EventTarget semantics", function () {
it("Event is spec-sane and cancelable via preventDefault", function () {
@@ -219,7 +224,7 @@ describe("WHATWG error events", function () {
});
});
- it("reportError still fires listeners after globalThis.dispatchEvent is overwritten", function (done) {
+ it("reportError still fires listeners after globalThis.dispatchEvent is overwritten", raisesGlobalErrors(function (done) {
var err = new Error("resilient");
var received = null;
onGlobal("error", function (e) {
@@ -241,5 +246,5 @@ describe("WHATWG error events", function () {
expect(uncaught.length).toBe(0);
done();
});
- });
+ }));
});
diff --git a/test-app/app/src/main/assets/app/tests/testEsmHttpLoader.js b/test-app/app/src/main/assets/app/tests/testEsmHttpLoader.js
index 839a1674e..576e4f086 100644
--- a/test-app/app/src/main/assets/app/tests/testEsmHttpLoader.js
+++ b/test-app/app/src/main/assets/app/tests/testEsmHttpLoader.js
@@ -18,12 +18,8 @@ describe("HTTP ESM Loader", function () {
}
}
- // This Jasmine's fail() throws, which inside a promise reaction surfaces as
- // an opaque spec timeout instead of a diff. Every rejection handler below
- // reports through a non-throwing expect for that reason.
function reportRejection(error, done) {
- expect("rejected: " + formatError(error)).toBe("resolved");
- done();
+ done.fail("rejected: " + formatError(error));
}
function withTimeout(promise, ms, label) {
diff --git a/test-app/app/src/main/assets/app/tests/testGC.js b/test-app/app/src/main/assets/app/tests/testGC.js
index 43c5b9ae5..20b0b6a74 100644
--- a/test-app/app/src/main/assets/app/tests/testGC.js
+++ b/test-app/app/src/main/assets/app/tests/testGC.js
@@ -37,179 +37,6 @@ describe("Tests garbage collection", function () {
normalTest();
});
- // this test has implicit assert in com.tns.Runtime.getJavaObjectByID method
- it("test1", function () {
-
- function createObjects(name) {
- var c1 = new com.tns.tests.Class1();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback5")).toBe(true);
- expect(createObjects("Callback26")).toBe(true);
-
- gc();
- java.lang.System.gc();
- });
-
- // this test has implicit assert in com.tns.Runtime.getJavaObjectByID method
- it("test2", function () {
-
- function indref1() {
- this.class1 = new com.tns.tests.Class1();
- }
- indref1.prototype.getMessage = function() {
- return "~~~" + this.class1.getMessage();
- }
-
- function createObjects(name) {
- var c1 = new indref1();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback55")).toBe(true);
- expect(createObjects("Callback56")).toBe(true);
- gc();
- java.lang.System.gc();
- });
-
- // this test has implicit assert in com.tns.Runtime.getJavaObjectByID method
- it("test3", function () {
-
- function indref2() {
- this.helper = new indref2helper();
- }
- indref2.prototype.getMessage = function() {
- return "---" + this.helper.getMessage();
- }
- function indref2helper() {
- this.class1 = new com.tns.tests.Class1();
- }
- indref2helper.prototype.getMessage = function() {
- return "***" + this.class1.getMessage();
- }
-
- function createObjects(name) {
- var c1 = new indref2();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback91")).toBe(true);
- expect(createObjects("Callback92")).toBe(true);
- gc();
- java.lang.System.gc();
- });
-
- // this test has implicit assert in com.tns.Runtime.getJavaObjectByID method
- it("test4", function () {
-
- function indref3() {
- this.helper = new indref3helper();
- }
- indref3.prototype.getMessage = function() {
- return "+++" + this.helper.getMessage();
- }
- function indref3helper() {
- this._class1 = new com.tns.tests.Class1();
-
- Object.defineProperty(this, "class1", {
- get: function() {
- return this._class1
- }
- });
- }
- indref3helper.prototype.getMessage = function() {
- return "^^^" + this.class1.getMessage();
- }
-
- function createObjects(name) {
- var c1 = new indref3();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback1133")).toBe(true);
- expect(createObjects("Callback1134")).toBe(true);
- gc();
- java.lang.System.gc();
- });
-
- // this test has implicit assert in com.tns.Runtime.getJavaObjectByID method
- //originally test was commented out
- xit("test5", function () {
-
- function indref4() {
- this.helper = new indref4helper();
- }
- indref4.prototype.getMessage = function() {
- return "&&&" + this.helper.getMessageZZZ();
- }
- function indref4helper() {
- var _class1 = new com.tns.tests.Class1();
-
- __log("indref4helper _class1=" + _class1);
-
- Object.defineProperty(this, "class1", {
- get: function() {
- return _class1
- }
- ,enumerable: false
- });
- }
- indref4helper.prototype.getMessageZZZ = function() {
- return "```" + this.class1.getMessage();
- }
-
- function createObjects(name) {
- var c1 = new indref4();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback1178")).toBe(true);
- expect(createObjects("Callback1179")).toBe(true);
- gc();
- java.lang.System.gc();
- });
-
it("testAccessingStringFieldWontLeak", function () {
__log("TEST: testAccessingStringFieldWontLeak");
@@ -241,52 +68,6 @@ describe("Tests garbage collection", function () {
expect(o.x).toBe(123);
});
- it("should keep extended instances alive after GC", function () {
- var C1 = com.tns.tests.Class1.extend({});
-
- function createObjects(name) {
- var c1 = new C1();
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = c1.getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 5 * 1000);
- }
-
- expect(createObjects("Callback452356")).toBe(true);
- expect(createObjects("Callback417892")).toBe(true);
-
- gc();
- java.lang.System.gc();
- });
-
- it("should keep array-enclosed objects alive after GC", function () {
- function createObjects(name) {
- var arr = new Array();
- arr.push(new com.tns.tests.Class1());
-
- var cb1 = new com.tns.tests.Class1.Callback1(name, {
- getMessage: function() {
- var msg = arr[0].getMessage();
- return msg;
- }
- });
-
- return com.tns.tests.Class1.Class2.printMessageWithDelay(cb1, 2 * 1000);
- }
-
- expect(createObjects("Callback1")).toBe(true);
- expect(createObjects("Callback2")).toBe(true);
- expect(createObjects("Callback3")).toBe(true);
-
- gc();
- java.lang.System.gc();
- })
-
it("should properly reintroduce Java object back in a callback", function () {
function getTestObject() {
return new com.tns.tests.BadEqualsTest(
diff --git a/test-app/app/src/main/assets/app/tests/testMessaging.js b/test-app/app/src/main/assets/app/tests/testMessaging.js
index 6e4d30e99..c1a94a44e 100644
--- a/test-app/app/src/main/assets/app/tests/testMessaging.js
+++ b/test-app/app/src/main/assets/app/tests/testMessaging.js
@@ -1,3 +1,5 @@
+const { raisesGlobalErrors } = require("../Infrastructure/Jasmine/globalErrorSpy");
+
// Android-side regression specs for the messaging tier. The shared suites under
// app/shared cover the specified behavior; these pin runtime edges that need
// native wrappers, a worker that never settles, or a collection.
@@ -540,7 +542,7 @@ describe("Messaging runtime edges", function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
- it("reports an error the Worker object left unhandled to the parent scope", function (done) {
+ it("reports an error the Worker object left unhandled to the parent scope", raisesGlobalErrors(function (done) {
var seen = [];
var worker = null;
var listener = function (event) {
@@ -561,7 +563,7 @@ describe("Messaging runtime edges", function () {
};
addEventListener("error", listener);
worker = new Worker("./messaging/throwingWorker.js");
- });
+ }));
it("forwards the error a throwing scope onerror raised for a rejection, once", function (done) {
var worker = new Worker("./messaging/rejectingWorker.js");
diff --git a/test-app/app/src/main/assets/app/tests/testNativeTimers.js b/test-app/app/src/main/assets/app/tests/testNativeTimers.js
index a40734ced..80b5b27f6 100644
--- a/test-app/app/src/main/assets/app/tests/testNativeTimers.js
+++ b/test-app/app/src/main/assets/app/tests/testNativeTimers.js
@@ -51,14 +51,6 @@ describe('native timer', () => {
}, 100);
});
- it('triggers timeout', (done) => {
- const now = Date.now();
- setTimeout(() => {
- expect(Date.now() - now).not.toBeLessThan(100);
- done();
- }, 100);
- });
-
it('triggers interval', (done) => {
let calls = 0;
const itv = setInterval(() => {
diff --git a/test-app/app/src/main/assets/app/tests/testNsModule.js b/test-app/app/src/main/assets/app/tests/testNsModule.js
index 7d4d75866..b3597024e 100644
--- a/test-app/app/src/main/assets/app/tests/testNsModule.js
+++ b/test-app/app/src/main/assets/app/tests/testNsModule.js
@@ -29,10 +29,7 @@ describe("ns:module", function () {
expect(ns.configureLoader).toBe(nsModule.configureLoader);
done();
}).catch(function (error) {
- // fail() throws in this Jasmine, which inside a promise chain
- // surfaces as an opaque timeout instead of the real reason.
- expect("rejected: " + String((error && error.message) || error)).toBe("resolved");
- done();
+ done.fail("rejected: " + String((error && error.message) || error));
});
});
diff --git a/test-app/app/src/main/assets/app/tests/testUncaughtErrorPolicy.js b/test-app/app/src/main/assets/app/tests/testUncaughtErrorPolicy.js
index 655bd76fb..aa77d380c 100644
--- a/test-app/app/src/main/assets/app/tests/testUncaughtErrorPolicy.js
+++ b/test-app/app/src/main/assets/app/tests/testUncaughtErrorPolicy.js
@@ -1,3 +1,5 @@
+const { raisesGlobalErrors } = require("../Infrastructure/Jasmine/globalErrorSpy");
+
describe("uncaughtErrorPolicy (default: report)", function () {
// Under the default "report" policy, an uncaught JS throw in a
// native-initiated callback is contained: reported through the `error`
@@ -53,7 +55,7 @@ describe("uncaughtErrorPolicy (default: report)", function () {
}, 20);
}
- it("contains an uncaught throw in a native-initiated callback and keeps the app alive", function (done) {
+ it("contains an uncaught throw in a native-initiated callback and keeps the app alive", raisesGlobalErrors(function (done) {
var reason = new Error("contained-post-throw");
var received = null;
onGlobal("error", function (e) {
@@ -83,9 +85,9 @@ describe("uncaughtErrorPolicy (default: report)", function () {
expect(1 + 1).toBe(2);
done();
});
- });
+ }));
- it("preventDefault() on the error event suppresses the legacy hook", function (done) {
+ it("preventDefault() on the error event suppresses the legacy hook", raisesGlobalErrors(function (done) {
var reason = new Error("contained-prevented-throw");
var ran = false;
onGlobal("error", function (e) {
@@ -108,9 +110,9 @@ describe("uncaughtErrorPolicy (default: report)", function () {
done();
});
});
- });
+ }));
- it("contains an uncaught throw in a setTimeout callback", function (done) {
+ it("contains an uncaught throw in a setTimeout callback", raisesGlobalErrors(function (done) {
var reason = new Error("contained-timer-throw");
setTimeout(function () {
throw reason;
@@ -121,9 +123,9 @@ describe("uncaughtErrorPolicy (default: report)", function () {
expect(1 + 1).toBe(2);
done();
});
- });
+ }));
- it("a contained throw in a primitive-returning override yields the type's default", function (done) {
+ it("a contained throw in a primitive-returning override yields the type's default", raisesGlobalErrors(function (done) {
var reason = new Error("contained-compare-throw");
var doneRan = false;
var comparator = new java.util.Comparator({
@@ -144,7 +146,7 @@ describe("uncaughtErrorPolicy (default: report)", function () {
expect(uncaughtSeen(reason)).toBe(true);
done();
});
- });
+ }));
it("propagates a JS-initiated chain back to the outer JS catch with identity", function () {
var reason = new Error("chain-identity");
diff --git a/test-app/app/src/main/assets/app/tests/testUnhandledRejections.js b/test-app/app/src/main/assets/app/tests/testUnhandledRejections.js
index e847aa6d0..ab65ebfd3 100644
--- a/test-app/app/src/main/assets/app/tests/testUnhandledRejections.js
+++ b/test-app/app/src/main/assets/app/tests/testUnhandledRejections.js
@@ -1,3 +1,5 @@
+const { raisesGlobalErrors } = require("../Infrastructure/Jasmine/globalErrorSpy");
+
describe("unhandled promise rejections", function () {
// Unhandled rejections are tracked per-isolate and reported once per
// looper turn through the same uncaught-error machinery exposed via
@@ -57,14 +59,14 @@ describe("unhandled promise rejections", function () {
}, 20);
}
- it("reports an unhandled Promise.reject through __onUncaughtError", function (done) {
+ it("reports an unhandled Promise.reject through __onUncaughtError", raisesGlobalErrors(function (done) {
var reason = new Error("unhandled-promise-reject");
Promise.reject(reason);
pollUntil(function () { return reportedSeen(reason); }, function () {
expect(reportedSeen(reason)).toBe(true);
done();
});
- });
+ }));
it("does not report when .catch is attached synchronously in the same turn", function (done) {
var reason = new Error("handled-same-turn");
@@ -76,7 +78,7 @@ describe("unhandled promise rejections", function () {
});
});
- it("reports an uncaught throw from an async function", function (done) {
+ it("reports an uncaught throw from an async function", raisesGlobalErrors(function (done) {
var reason = new Error("async-function-throw");
(async () => {
throw reason;
@@ -85,9 +87,9 @@ describe("unhandled promise rejections", function () {
expect(reportedSeen(reason)).toBe(true);
done();
});
- });
+ }));
- it("reports an unhandled rejection thrown from a .then callback", function (done) {
+ it("reports an unhandled rejection thrown from a .then callback", raisesGlobalErrors(function (done) {
var reason = new Error("then-callback-throw");
Promise.resolve().then(function () {
throw reason;
@@ -96,9 +98,9 @@ describe("unhandled promise rejections", function () {
expect(reportedSeen(reason)).toBe(true);
done();
});
- });
+ }));
- it("ignores a late .catch attached after the rejection was already reported", function (done) {
+ it("ignores a late .catch attached after the rejection was already reported", raisesGlobalErrors(function (done) {
var reason = new Error("late-catch");
var p = Promise.reject(reason);
pollUntil(function () { return reportedSeen(reason); }, function () {
@@ -112,9 +114,9 @@ describe("unhandled promise rejections", function () {
done();
});
});
- });
+ }));
- it("unhandledrejection listener receives reason and promise; preventDefault suppresses the hook", function (done) {
+ it("unhandledrejection listener receives reason and promise; preventDefault suppresses the hook", raisesGlobalErrors(function (done) {
var reason = new Error("rejected-with-listener");
var received = null;
onGlobal("unhandledrejection", function (e) {
@@ -141,9 +143,9 @@ describe("unhandled promise rejections", function () {
done();
});
});
- });
+ }));
- it("fires rejectionhandled when a handler is attached after the rejection was reported", function (done) {
+ it("fires rejectionhandled when a handler is attached after the rejection was reported", raisesGlobalErrors(function (done) {
var reason = new Error("late-handler");
var rejectionHandled = null;
onGlobal("rejectionhandled", function (e) {
@@ -181,5 +183,5 @@ describe("unhandled promise rejections", function () {
});
}, 20);
});
- });
+ }));
});
diff --git a/test-app/app/src/main/assets/app/tests/testWorkerResourceLimits.js b/test-app/app/src/main/assets/app/tests/testWorkerResourceLimits.js
index 6dfeac03f..bf03867ba 100644
--- a/test-app/app/src/main/assets/app/tests/testWorkerResourceLimits.js
+++ b/test-app/app/src/main/assets/app/tests/testWorkerResourceLimits.js
@@ -61,9 +61,11 @@ describe("Worker resourceLimits", function () {
expect("worker posted a message").toBe("worker exhausted its heap");
};
+ // Returns true so the error is not re-reported on the main global scope,
+ // where Jasmine would charge it to whatever spec runs next.
worker.onerror = function (e) {
if (settled) {
- return;
+ return true;
}
settled = true;
var message = String(e && e.message ? e.message : e);
@@ -73,6 +75,7 @@ describe("Worker resourceLimits", function () {
expect(message).toMatch(/maxOldGenerationSizeMb: 32/);
worker.terminate();
done();
+ return true;
};
});
diff --git a/test-app/app/src/main/assets/app/tests/tests.js b/test-app/app/src/main/assets/app/tests/tests.js
index 6475937e9..e2e4f0166 100644
--- a/test-app/app/src/main/assets/app/tests/tests.js
+++ b/test-app/app/src/main/assets/app/tests/tests.js
@@ -927,9 +927,9 @@ describe("Tests ", function () {
expect(s).toBe("1, test, false");
});
- it("TestCallMethodWithByteParameter", function () {
+ it("TestCallByteValueOfWithByteParameter", function () {
- __log("TEST: TestCallMethodWithByteParameter");
+ __log("TEST: TestCallByteValueOfWithByteParameter");
var b = java.lang.Byte.valueOf(byte(123));
diff --git a/test-app/app/src/main/assets/app/tests/testsForTypescript.js b/test-app/app/src/main/assets/app/tests/testsForTypescript.js
index fa76b7d31..ae80690ec 100644
--- a/test-app/app/src/main/assets/app/tests/testsForTypescript.js
+++ b/test-app/app/src/main/assets/app/tests/testsForTypescript.js
@@ -201,9 +201,9 @@ describe("Tests typescript", function () {
expect(isInstanceOf).toEqual(true);
});
- it("When_creating_a_typescript_instance_it_should_be_a_valid_nativescript_instance", function () {
+ it("When_creating_a_typescript_instance_with_constructor_arguments_it_should_be_a_valid_nativescript_instance", function () {
- __log("TEST: When_creating_a_typescript_instance_it_should_be_a_valid_nativescript_instance");
+ __log("TEST: When_creating_a_typescript_instance_with_constructor_arguments_it_should_be_a_valid_nativescript_instance");
var MyButtonWithArgs = (function (_super) {
__extends(MyButtonWithArgs, _super);
diff --git a/test-app/dependencies.json b/test-app/dependencies.json
index 32960f8ce..a9ebb3108 100644
--- a/test-app/dependencies.json
+++ b/test-app/dependencies.json
@@ -1,2 +1,7 @@
[
-]
\ No newline at end of file
+ {
+ "name": "test-runner-deps",
+ "directory": "test-runner-deps",
+ "dependencies": []
+ }
+]
diff --git a/test-app/test-runner-deps/package.json b/test-app/test-runner-deps/package.json
new file mode 100644
index 000000000..47b6fae96
--- /dev/null
+++ b/test-app/test-runner-deps/package.json
@@ -0,0 +1,5 @@
+{
+ "name": "test-runner-deps",
+ "private": true,
+ "description": "Test app only: stages the npm packages the Jasmine harness loads at runtime into the APK's assets."
+}
diff --git a/test-app/test-runner-deps/platforms/android/include.gradle b/test-app/test-runner-deps/platforms/android/include.gradle
new file mode 100644
index 000000000..7733e59f8
--- /dev/null
+++ b/test-app/test-runner-deps/platforms/android/include.gradle
@@ -0,0 +1,42 @@
+// Copies the npm packages the test app's Jasmine harness loads at runtime from
+// the repo's node_modules (`npm install` at the repo root) into a generated
+// assets folder. Each package's files land flat in
+// app/Infrastructure/Jasmine/vendor//.
+def testRunnerDepsNodeModules = new File(rootDir, "../node_modules").canonicalFile
+def testRunnerDepsPackages = [
+ "jasmine-core": ["lib/jasmine-core/jasmine.js", "LICENSE"],
+]
+def testRunnerDepsAssetsDir = new File(project.buildDir, "generated/test-runner-deps/assets")
+
+def stageTestRunnerDeps = project.tasks.register("stageTestRunnerDeps") {
+ def sources = [:]
+ testRunnerDepsPackages.each { name, files ->
+ files.each { path ->
+ sources[new File(testRunnerDepsNodeModules, "$name/$path")] = "app/Infrastructure/Jasmine/vendor/$name/${new File(path).name}"
+ }
+ }
+ def outDir = testRunnerDepsAssetsDir
+ def nodeModules = testRunnerDepsNodeModules
+
+ inputs.files(sources.keySet())
+ outputs.dir(outDir)
+
+ doLast {
+ def missing = sources.keySet().findAll { !it.isFile() }
+ if (!missing.isEmpty()) {
+ throw new GradleException("Test runner dependencies are not installed (missing ${missing.join(', ')}). " +
+ "Run 'npm install' in ${nodeModules.parentFile}.")
+ }
+ outDir.deleteDir()
+ sources.each { from, to ->
+ def dest = new File(outDir, to)
+ dest.parentFile.mkdirs()
+ java.nio.file.Files.copy(from.toPath(), dest.toPath(), java.nio.file.StandardCopyOption.REPLACE_EXISTING)
+ }
+ }
+}
+
+android.sourceSets.main.assets.srcDir(testRunnerDepsAssetsDir)
+project.tasks.matching { it.name == "preBuild" }.configureEach {
+ dependsOn stageTestRunnerDeps
+}