Merge remote-tracking branch 'upstream/main' into array_buffer

# Conflicts:
#	spec/core/matchers/matchersUtilSpec.js
This commit is contained in:
Surgie Finesse
2021-03-22 18:31:35 +10:00
246 changed files with 21415 additions and 8225 deletions

View File

@@ -1,14 +1,14 @@
getJasmineRequireObj().CallTracker = function(j$) {
/**
* @namespace Spy#calls
* @since 2.0.0
*/
function CallTracker() {
var calls = [];
var opts = {};
this.track = function(context) {
if(opts.cloneArgs) {
if (opts.cloneArgs) {
context.args = j$.util.cloneArgs(context.args);
}
calls.push(context);
@@ -17,6 +17,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Check whether this spy has been invoked.
* @name Spy#calls#any
* @since 2.0.0
* @function
* @return {Boolean}
*/
@@ -27,6 +28,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the number of invocations of this spy.
* @name Spy#calls#count
* @since 2.0.0
* @function
* @return {Integer}
*/
@@ -37,6 +39,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the arguments that were passed to a specific invocation of this spy.
* @name Spy#calls#argsFor
* @since 2.0.0
* @function
* @param {Integer} index The 0-based invocation index.
* @return {Array}
@@ -49,6 +52,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the raw calls array for this spy.
* @name Spy#calls#all
* @since 2.0.0
* @function
* @return {Spy.callData[]}
*/
@@ -59,12 +63,13 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get all of the arguments for each invocation of this spy in the order they were received.
* @name Spy#calls#allArgs
* @since 2.0.0
* @function
* @return {Array}
*/
this.allArgs = function() {
var callArgs = [];
for(var i = 0; i < calls.length; i++){
for (var i = 0; i < calls.length; i++) {
callArgs.push(calls[i].args);
}
@@ -74,6 +79,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the first invocation of this spy.
* @name Spy#calls#first
* @since 2.0.0
* @function
* @return {ObjecSpy.callData}
*/
@@ -84,6 +90,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Get the most recent invocation of this spy.
* @name Spy#calls#mostRecent
* @since 2.0.0
* @function
* @return {ObjecSpy.callData}
*/
@@ -94,6 +101,7 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Reset this spy as if it has never been called.
* @name Spy#calls#reset
* @since 2.0.0
* @function
*/
this.reset = function() {
@@ -103,12 +111,12 @@ getJasmineRequireObj().CallTracker = function(j$) {
/**
* Set this spy to do a shallow clone of arguments passed to each invocation.
* @name Spy#calls#saveArgumentsByValue
* @since 2.5.0
* @function
*/
this.saveArgumentsByValue = function() {
opts.cloneArgs = true;
};
}
return CallTracker;

View File

@@ -3,8 +3,8 @@ getJasmineRequireObj().clearStack = function(j$) {
function messageChannelImpl(global, setTimeout) {
var channel = new global.MessageChannel(),
head = {},
tail = head;
head = {},
tail = head;
var taskRunning = false;
channel.port1.onmessage = function() {
@@ -42,7 +42,7 @@ getJasmineRequireObj().clearStack = function(j$) {
var currentCallCount = 0;
var realSetTimeout = global.setTimeout;
var setTimeoutImpl = function clearStack(fn) {
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
};
if (j$.isFunction_(global.setImmediate)) {

View File

@@ -1,7 +1,9 @@
getJasmineRequireObj().Clock = function() {
/* global process */
var NODE_JS = typeof process !== 'undefined' && process.versions && typeof process.versions.node === 'string';
var NODE_JS =
typeof process !== 'undefined' &&
process.versions &&
typeof process.versions.node === 'string';
/**
* _Note:_ Do not construct this directly, Jasmine will make one during booting. You can get the current clock with {@link jasmine.clock}.
@@ -31,12 +33,15 @@ getJasmineRequireObj().Clock = function() {
/**
* Install the mock clock over the built-in methods.
* @name Clock#install
* @since 2.0.0
* @function
* @return {Clock}
*/
self.install = function() {
if(!originalTimingFunctionsIntact()) {
throw new Error('Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?');
if (!originalTimingFunctionsIntact()) {
throw new Error(
'Jasmine Clock was unable to install over custom global timer functions. Is the clock already installed?'
);
}
replace(global, fakeTimingFunctions);
timer = fakeTimingFunctions;
@@ -49,6 +54,7 @@ getJasmineRequireObj().Clock = function() {
/**
* Uninstall the mock clock, returning the built-in methods to their places.
* @name Clock#uninstall
* @since 2.0.0
* @function
*/
self.uninstall = function() {
@@ -65,6 +71,7 @@ getJasmineRequireObj().Clock = function() {
*
* The clock will be {@link Clock#install|install}ed before the function is called and {@link Clock#uninstall|uninstall}ed in a `finally` after the function completes.
* @name Clock#withMock
* @since 2.3.0
* @function
* @param {Function} closure The function to be called.
*/
@@ -80,6 +87,7 @@ getJasmineRequireObj().Clock = function() {
/**
* Instruct the installed Clock to also mock the date returned by `new Date()`
* @name Clock#mockDate
* @since 2.1.0
* @function
* @param {Date} [initialDate=now] The `Date` to provide.
*/
@@ -88,11 +96,17 @@ getJasmineRequireObj().Clock = function() {
};
self.setTimeout = function(fn, delay, params) {
return Function.prototype.apply.apply(timer.setTimeout, [global, arguments]);
return Function.prototype.apply.apply(timer.setTimeout, [
global,
arguments
]);
};
self.setInterval = function(fn, delay, params) {
return Function.prototype.apply.apply(timer.setInterval, [global, arguments]);
return Function.prototype.apply.apply(timer.setInterval, [
global,
arguments
]);
};
self.clearTimeout = function(id) {
@@ -106,24 +120,31 @@ getJasmineRequireObj().Clock = function() {
/**
* Tick the Clock forward, running any enqueued timeouts along the way
* @name Clock#tick
* @since 1.3.0
* @function
* @param {int} millis The number of milliseconds to tick.
*/
self.tick = function(millis) {
if (installed) {
delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
delayedFunctionScheduler.tick(millis, function(millis) {
mockDate.tick(millis);
});
} else {
throw new Error('Mock clock is not installed, use jasmine.clock().install()');
throw new Error(
'Mock clock is not installed, use jasmine.clock().install()'
);
}
};
return self;
function originalTimingFunctionsIntact() {
return global.setTimeout === realTimingFunctions.setTimeout &&
return (
global.setTimeout === realTimingFunctions.setTimeout &&
global.clearTimeout === realTimingFunctions.clearTimeout &&
global.setInterval === realTimingFunctions.setInterval &&
global.clearInterval === realTimingFunctions.clearInterval;
global.clearInterval === realTimingFunctions.clearInterval
);
}
function replace(dest, source) {
@@ -134,12 +155,22 @@ getJasmineRequireObj().Clock = function() {
function setTimeout(fn, delay) {
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2));
return delayedFunctionScheduler.scheduleFunction(
fn,
delay,
argSlice(arguments, 2)
);
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, delay, argSlice(arguments, 2), false, timeout);
delayedFunctionScheduler.scheduleFunction(
fn,
delay,
argSlice(arguments, 2),
false,
timeout
);
return timeout;
}
@@ -150,12 +181,23 @@ getJasmineRequireObj().Clock = function() {
function setInterval(fn, interval) {
if (!NODE_JS) {
return delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true);
return delayedFunctionScheduler.scheduleFunction(
fn,
interval,
argSlice(arguments, 2),
true
);
}
var timeout = new FakeTimeout();
delayedFunctionScheduler.scheduleFunction(fn, interval, argSlice(arguments, 2), true, timeout);
delayedFunctionScheduler.scheduleFunction(
fn,
interval,
argSlice(arguments, 2),
true,
timeout
);
return timeout;
}
@@ -174,11 +216,11 @@ getJasmineRequireObj().Clock = function() {
*/
function FakeTimeout() {}
FakeTimeout.prototype.ref = function () {
FakeTimeout.prototype.ref = function() {
return this;
};
FakeTimeout.prototype.unref = function () {
FakeTimeout.prototype.unref = function() {
return this;
};

View File

@@ -15,11 +15,20 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
currentTime = endTime;
};
self.scheduleFunction = function(funcToCall, millis, params, recurring, timeoutKey, runAtMillis) {
self.scheduleFunction = function(
funcToCall,
millis,
params,
recurring,
timeoutKey,
runAtMillis
) {
var f;
if (typeof(funcToCall) === 'string') {
if (typeof funcToCall === 'string') {
/* jshint evil: true */
f = function() { return eval(funcToCall); };
f = function() {
return eval(funcToCall);
};
/* jshint evil: false */
} else {
f = funcToCall;
@@ -27,7 +36,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
millis = millis || 0;
timeoutKey = timeoutKey || ++delayedFnCount;
runAtMillis = runAtMillis || (currentTime + millis);
runAtMillis = runAtMillis || currentTime + millis;
var funcToSchedule = {
runAtMillis: runAtMillis,
@@ -43,7 +52,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
} else {
scheduledFunctions[runAtMillis] = [funcToSchedule];
scheduledLookup.push(runAtMillis);
scheduledLookup.sort(function (a, b) {
scheduledLookup.sort(function(a, b) {
return a - b;
});
}
@@ -56,7 +65,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
for (var runAtMillis in scheduledFunctions) {
var funcs = scheduledFunctions[runAtMillis];
var i = indexOfFirstToPass(funcs, function (func) {
var i = indexOfFirstToPass(funcs, function(func) {
return func.timeoutKey === timeoutKey;
});
@@ -92,7 +101,7 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
function deleteFromLookup(key) {
var value = Number(key);
var i = indexOfFirstToPass(scheduledLookup, function (millis) {
var i = indexOfFirstToPass(scheduledLookup, function(millis) {
return millis === value;
});
@@ -102,12 +111,14 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
}
function reschedule(scheduledFn) {
self.scheduleFunction(scheduledFn.funcToCall,
self.scheduleFunction(
scheduledFn.funcToCall,
scheduledFn.millis,
scheduledFn.params,
true,
scheduledFn.timeoutKey,
scheduledFn.runAtMillis + scheduledFn.millis);
scheduledFn.runAtMillis + scheduledFn.millis
);
}
function forEachFunction(funcsToRun, callback) {
@@ -148,11 +159,13 @@ getJasmineRequireObj().DelayedFunctionScheduler = function(j$) {
funcToRun.funcToCall.apply(null, funcToRun.params || []);
});
deletedKeys = [];
} 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);
} 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
);
// ran out of functions to call, but still time left on the clock
if (currentTime !== endTime) {

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,16 @@
getJasmineRequireObj().ExceptionFormatter = function(j$) {
var ignoredProperties = ['name', 'message', 'stack', 'fileName', 'sourceURL', 'line', 'lineNumber', 'column', 'description', 'jasmineMessage'];
var ignoredProperties = [
'name',
'message',
'stack',
'fileName',
'sourceURL',
'line',
'lineNumber',
'column',
'description',
'jasmineMessage'
];
function ExceptionFormatter(options) {
var jasmineFile = (options && options.jasmineFile) || j$.util.jasmineFile();
@@ -49,10 +59,11 @@ getJasmineRequireObj().ExceptionFormatter = function(j$) {
function filterJasmine(stackTrace) {
var result = [],
jasmineMarker = stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
jasmineMarker =
stackTrace.style === 'webkit' ? '<Jasmine>' : ' at <Jasmine>';
stackTrace.frames.forEach(function(frame) {
if (frame.file && frame.file !== jasmineFile) {
if (frame.file !== jasmineFile) {
result.push(frame.raw);
} else if (result[result.length - 1] !== jasmineMarker) {
result.push(jasmineMarker);

View File

@@ -1,8 +1,4 @@
getJasmineRequireObj().Expectation = function(j$) {
var promiseForMessage = {
jasmineToString: function() { return 'a promise'; }
};
/**
* Matchers that come with Jasmine out of the box.
* @namespace matchers
@@ -12,7 +8,10 @@ getJasmineRequireObj().Expectation = function(j$) {
var customMatchers = options.customMatchers || {};
for (var matcherName in customMatchers) {
this[matcherName] = wrapSyncCompare(matcherName, customMatchers[matcherName]);
this[matcherName] = wrapSyncCompare(
matcherName,
customMatchers[matcherName]
);
}
}
@@ -20,6 +19,7 @@ getJasmineRequireObj().Expectation = function(j$) {
* Add some context for an {@link expect}
* @function
* @name matchers#withContext
* @since 3.3.0
* @param {String} message - Additional context to show when the matcher fails
* @return {matchers}
*/
@@ -31,6 +31,7 @@ getJasmineRequireObj().Expectation = function(j$) {
* Invert the matcher following this {@link expect}
* @member
* @name matchers#not
* @since 1.3.0
* @type {matchers}
* @example
* expect(something).not.toBe(true);
@@ -50,11 +51,17 @@ getJasmineRequireObj().Expectation = function(j$) {
this.expector = new j$.Expector(options);
if (!global.Promise) {
throw new Error('expectAsync is unavailable because the environment does not support promises.');
throw new Error(
'expectAsync is unavailable because the environment does not support promises.'
);
}
if (!j$.isPromiseLike(this.expector.actual)) {
throw new Error('Expected expectAsync to be called with a promise.');
var customAsyncMatchers = options.customAsyncMatchers || {};
for (var matcherName in customAsyncMatchers) {
this[matcherName] = wrapAsyncCompare(
matcherName,
customAsyncMatchers[matcherName]
);
}
}
@@ -62,6 +69,7 @@ getJasmineRequireObj().Expectation = function(j$) {
* Add some context for an {@link expectAsync}
* @function
* @name async-matchers#withContext
* @since 3.3.0
* @param {String} message - Additional context to show when the async matcher fails
* @return {async-matchers}
*/
@@ -100,9 +108,11 @@ getJasmineRequireObj().Expectation = function(j$) {
// frames that are relevant to the user instead of just parts of Jasmine.
var errorForStack = j$.util.errorWithStack();
return this.expector.compare(name, matcherFactory, arguments).then(function(result) {
self.expector.processResult(result, errorForStack, promiseForMessage);
});
return this.expector
.compare(name, matcherFactory, arguments)
.then(function(result) {
self.expector.processResult(result, errorForStack);
});
};
}
@@ -119,7 +129,7 @@ getJasmineRequireObj().Expectation = function(j$) {
return result;
}
function negatedFailureMessage(result, matcherName, args, util) {
function negatedFailureMessage(result, matcherName, args, matchersUtil) {
if (result.message) {
if (j$.isFunction_(result.message)) {
return result.message();
@@ -131,7 +141,7 @@ getJasmineRequireObj().Expectation = function(j$) {
args = args.slice();
args.unshift(true);
args.unshift(matcherName);
return util.buildFailureMessage.apply(null, args);
return matchersUtil.buildFailureMessage.apply(matchersUtil, args);
}
function negate(result) {
@@ -156,7 +166,7 @@ getJasmineRequireObj().Expectation = function(j$) {
return matcher.compare.apply(this, arguments).then(negate);
}
return defaultNegativeCompare;
return matcher.negativeCompare || defaultNegativeCompare;
},
buildFailureMessage: negatedFailureMessage
};
@@ -166,9 +176,19 @@ getJasmineRequireObj().Expectation = function(j$) {
}
ContextAddingFilter.prototype.modifyFailureMessage = function(msg) {
return this.message + ': ' + msg;
var nl = msg.indexOf('\n');
if (nl === -1) {
return this.message + ': ' + msg;
} else {
return this.message + ':\n' + indent(msg);
}
};
function indent(s) {
return s.replace(/^/gm, ' ');
}
return {
factory: function(options) {
return new Expectation(options || {});

View File

@@ -12,7 +12,12 @@ getJasmineRequireObj().ExpectationFilterChain = function() {
return this.callFirst_('selectComparisonFunc', arguments).result;
};
ExpectationFilterChain.prototype.buildFailureMessage = function(result, matcherName, args, util) {
ExpectationFilterChain.prototype.buildFailureMessage = function(
result,
matcherName,
args,
matchersUtil
) {
return this.callFirst_('buildFailureMessage', arguments).result;
};
@@ -39,7 +44,7 @@ getJasmineRequireObj().ExpectationFilterChain = function() {
};
}
return {found: false};
return { found: false };
};
return ExpectationFilterChain;

View File

@@ -1,5 +1,5 @@
//TODO: expectation result may make more sense as a presentation of an expectation.
getJasmineRequireObj().buildExpectationResult = function() {
getJasmineRequireObj().buildExpectationResult = function(j$) {
function buildExpectationResult(options) {
var messageFormatter = options.messageFormatter || function() {},
stackFormatter = options.stackFormatter || function() {};
@@ -20,9 +20,25 @@ getJasmineRequireObj().buildExpectationResult = function() {
passed: options.passed
};
if(!result.passed) {
if (!result.passed) {
result.expected = options.expected;
result.actual = options.actual;
if (options.error && !j$.isString_(options.error)) {
if ('code' in options.error) {
result.code = options.error.code;
}
if (
options.error.code === 'ERR_ASSERTION' &&
options.expected === '' &&
options.actual === ''
) {
result.expected = options.error.expected;
result.actual = options.error.actual;
result.matcherName = 'assert ' + options.error.operator;
}
}
}
return result;

View File

@@ -1,20 +1,26 @@
getJasmineRequireObj().Expector = function(j$) {
function Expector(options) {
this.util = options.util || { buildFailureMessage: function() {} };
this.matchersUtil = options.matchersUtil || {
buildFailureMessage: function() {}
};
this.customEqualityTesters = options.customEqualityTesters || [];
this.actual = options.actual;
this.addExpectationResult = options.addExpectationResult || function(){};
this.addExpectationResult = options.addExpectationResult || function() {};
this.filters = new j$.ExpectationFilterChain();
}
Expector.prototype.instantiateMatcher = function(matcherName, matcherFactory, args) {
Expector.prototype.instantiateMatcher = function(
matcherName,
matcherFactory,
args
) {
this.matcherName = matcherName;
this.args = Array.prototype.slice.call(args, 0);
this.expected = this.args.slice(0);
this.args.unshift(this.actual);
var matcher = matcherFactory(this.util, this.customEqualityTesters);
var matcher = matcherFactory(this.matchersUtil, this.customEqualityTesters);
var comparisonFunc = this.filters.selectComparisonFunc(matcher);
return comparisonFunc || matcher.compare;
};
@@ -26,7 +32,13 @@ getJasmineRequireObj().Expector = function(j$) {
return '';
}
var msg = this.filters.buildFailureMessage(result, this.matcherName, this.args, this.util, defaultMessage);
var msg = this.filters.buildFailureMessage(
result,
this.matcherName,
this.args,
this.matchersUtil,
defaultMessage
);
return this.filters.modifyFailureMessage(msg || defaultMessage());
function defaultMessage() {
@@ -34,7 +46,10 @@ getJasmineRequireObj().Expector = function(j$) {
var args = self.args.slice();
args.unshift(false);
args.unshift(self.matcherName);
return self.util.buildFailureMessage.apply(null, args);
return self.matchersUtil.buildFailureMessage.apply(
self.matchersUtil,
args
);
} else if (j$.isFunction_(result.message)) {
return result.message();
} else {
@@ -44,7 +59,11 @@ getJasmineRequireObj().Expector = function(j$) {
};
Expector.prototype.compare = function(matcherName, matcherFactory, args) {
var matcherCompare = this.instantiateMatcher(matcherName, matcherFactory, args);
var matcherCompare = this.instantiateMatcher(
matcherName,
matcherFactory,
args
);
return matcherCompare.apply(null, this.args);
};
@@ -54,26 +73,22 @@ getJasmineRequireObj().Expector = function(j$) {
return result;
};
Expector.prototype.processResult = function(result, errorForStack, actualOverride) {
this.args[0] = actualOverride || this.args[0];
Expector.prototype.processResult = function(result, errorForStack) {
var message = this.buildMessage(result);
if (this.expected.length === 1) {
this.expected = this.expected[0];
}
this.addExpectationResult(
result.pass,
{
matcherName: this.matcherName,
passed: result.pass,
message: message,
error: errorForStack ? undefined : result.error,
errorForStack: errorForStack || undefined,
actual: this.actual,
expected: this.expected // TODO: this may need to be arrayified/sliced
}
);
this.addExpectationResult(result.pass, {
matcherName: this.matcherName,
passed: result.pass,
message: message,
error: errorForStack ? undefined : result.error,
errorForStack: errorForStack || undefined,
actual: this.actual,
expected: this.expected // TODO: this may need to be arrayified/sliced
});
};
return Expector;

View File

@@ -38,7 +38,10 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
var errorTypes = Object.keys(this.originalHandlers);
for (var iType = 0; iType < errorTypes.length; iType++) {
var errorType = errorTypes[iType];
global.process.removeListener(errorType, this.jasmineHandlers[errorType]);
global.process.removeListener(
errorType,
this.jasmineHandlers[errorType]
);
for (var i = 0; i < this.originalHandlers[errorType].length; i++) {
global.process.on(errorType, this.originalHandlers[errorType][i]);
}
@@ -49,15 +52,42 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
};
this.install = function install() {
if (global.process && global.process.listeners && j$.isFunction_(global.process.on)) {
if (
global.process &&
global.process.listeners &&
j$.isFunction_(global.process.on)
) {
this.installOne_('uncaughtException', 'Uncaught exception');
this.installOne_('unhandledRejection', 'Unhandled promise rejection');
} else {
var originalHandler = global.onerror;
global.onerror = onerror;
var browserRejectionHandler = function browserRejectionHandler(event) {
if (j$.isError_(event.reason)) {
event.reason.jasmineMessage =
'Unhandled promise rejection: ' + event.reason;
global.onerror(event.reason);
} else {
global.onerror('Unhandled promise rejection: ' + event.reason);
}
};
if (global.addEventListener) {
global.addEventListener(
'unhandledrejection',
browserRejectionHandler
);
}
this.uninstall = function uninstall() {
global.onerror = originalHandler;
if (global.removeEventListener) {
global.removeEventListener(
'unhandledrejection',
browserRejectionHandler
);
}
};
}
};
@@ -66,7 +96,11 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
handlers.push(listener);
};
this.popListener = function popListener() {
this.popListener = function popListener(listener) {
if (!listener) {
throw new Error('popListener expects a listener');
}
handlers.pop();
};
}

View File

@@ -6,8 +6,8 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
* @hideconstructor
*/
function JsApiReporter(options) {
var timer = options.timer || j$.noopTimer,
status = 'loaded';
var timer = options.timer || new j$.Timer(),
status = 'loaded';
this.started = false;
this.finished = false;
@@ -31,6 +31,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
/**
* Get the current status for the Jasmine environment.
* @name jsApiReporter#status
* @since 2.0.0
* @function
* @return {String} - One of `loaded`, `started`, or `done`
*/
@@ -54,6 +55,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
*
* Retrievable in slices for easier serialization.
* @name jsApiReporter#suiteResults
* @since 2.1.0
* @function
* @param {Number} index - The position in the suites list to start from.
* @param {Number} length - Maximum number of suite results to return.
@@ -71,6 +73,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
/**
* Get all of the suites in a single object, with their `id` as the key.
* @name jsApiReporter#suites
* @since 2.0.0
* @function
* @return {Object} - Map of suite id to {@link SuiteResult}
*/
@@ -89,6 +92,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
*
* Retrievable in slices for easier serialization.
* @name jsApiReporter#specResults
* @since 2.0.0
* @function
* @param {Number} index - The position in the specs list to start from.
* @param {Number} length - Maximum number of specs results to return.
@@ -101,6 +105,7 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
/**
* Get all spec results.
* @name jsApiReporter#specs
* @since 2.0.0
* @function
* @return {SpecResult[]}
*/
@@ -111,13 +116,13 @@ getJasmineRequireObj().JsApiReporter = function(j$) {
/**
* Get the number of milliseconds it took for the full Jasmine suite to run.
* @name jsApiReporter#executionTime
* @since 2.0.0
* @function
* @return {Number}
*/
this.executionTime = function() {
return executionTime;
};
}
return JsApiReporter;

View File

@@ -37,7 +37,7 @@ getJasmineRequireObj().MockDate = function() {
return self;
function FakeDate() {
switch(arguments.length) {
switch (arguments.length) {
case 0:
return new GlobalDate(currentTime);
case 1:
@@ -47,16 +47,39 @@ getJasmineRequireObj().MockDate = function() {
case 3:
return new GlobalDate(arguments[0], arguments[1], arguments[2]);
case 4:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3]);
return new GlobalDate(
arguments[0],
arguments[1],
arguments[2],
arguments[3]
);
case 5:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4]);
return new GlobalDate(
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4]
);
case 6:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5]);
return new GlobalDate(
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5]
);
default:
return new GlobalDate(arguments[0], arguments[1], arguments[2], arguments[3],
arguments[4], arguments[5], arguments[6]);
return new GlobalDate(
arguments[0],
arguments[1],
arguments[2],
arguments[3],
arguments[4],
arguments[5],
arguments[6]
);
}
}
@@ -76,7 +99,7 @@ getJasmineRequireObj().MockDate = function() {
FakeDate.parse = GlobalDate.parse;
FakeDate.UTC = GlobalDate.UTC;
}
}
}
return MockDate;
};

View File

@@ -3,7 +3,7 @@
getJasmineRequireObj().Order = function() {
function Order(options) {
this.random = 'random' in options ? options.random : true;
var seed = this.seed = options.seed || generateSeed();
var seed = (this.seed = options.seed || generateSeed());
this.sort = this.random ? randomOrder : naturalOrder;
function naturalOrder(items) {
@@ -29,17 +29,16 @@ getJasmineRequireObj().Order = function() {
function jenkinsHash(key) {
var hash, i;
for(hash = i = 0; i < key.length; ++i) {
for (hash = i = 0; i < key.length; ++i) {
hash += key.charCodeAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
hash += hash << 10;
hash ^= hash >> 6;
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
hash += hash << 3;
hash ^= hash >> 11;
hash += hash << 15;
return hash;
}
}
return Order;

View File

@@ -1,35 +1,51 @@
getJasmineRequireObj().pp = function(j$) {
function PrettyPrinter() {
getJasmineRequireObj().makePrettyPrinter = function(j$) {
function SinglePrettyPrintRun(customObjectFormatters, pp) {
this.customObjectFormatters_ = customObjectFormatters;
this.ppNestLevel_ = 0;
this.seen = [];
this.length = 0;
this.stringParts = [];
this.pp_ = pp;
}
function hasCustomToString(value) {
// value.toString !== Object.prototype.toString if value has no custom toString but is from another context (e.g.
// iframe, web worker)
return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
try {
return (
j$.isFunction_(value.toString) &&
value.toString !== Object.prototype.toString &&
value.toString() !== Object.prototype.toString.call(value)
);
} catch (e) {
// The custom toString() threw.
return true;
}
}
PrettyPrinter.prototype.format = function(value) {
SinglePrettyPrintRun.prototype.format = function(value) {
this.ppNestLevel_++;
try {
if (j$.util.isUndefined(value)) {
var customFormatResult = this.applyCustomFormatters_(value);
if (customFormatResult) {
this.emitScalar(customFormatResult);
} else if (j$.util.isUndefined(value)) {
this.emitScalar('undefined');
} else if (value === null) {
this.emitScalar('null');
} else if (value === 0 && 1/value === -Infinity) {
} else if (value === 0 && 1 / value === -Infinity) {
this.emitScalar('-0');
} else if (value === j$.getGlobal()) {
this.emitScalar('<global>');
} else if (value.jasmineToString) {
this.emitScalar(value.jasmineToString());
this.emitScalar(value.jasmineToString(this.pp_));
} else if (typeof value === 'string') {
this.emitString(value);
} else if (j$.isSpy(value)) {
this.emitScalar('spy on ' + value.and.identity);
} else if (j$.isSpy(value.toString)) {
this.emitScalar('spy on ' + value.toString.and.identity);
} else if (value instanceof RegExp) {
this.emitScalar(value.toString());
} else if (typeof value === 'function') {
@@ -48,10 +64,23 @@ getJasmineRequireObj().pp = function(j$) {
this.emitMap(value);
} else if (j$.isTypedArray_(value)) {
this.emitTypedArray(value);
} else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
this.emitScalar(value.toString());
} else if (
value.toString &&
typeof value === 'object' &&
!j$.isArray_(value) &&
hasCustomToString(value)
) {
try {
this.emitScalar(value.toString());
} catch (e) {
this.emitScalar('has-invalid-toString-method');
}
} else if (j$.util.arrayContains(this.seen, value)) {
this.emitScalar('<circular reference: ' + (j$.isArray_(value) ? 'Array' : 'Object') + '>');
this.emitScalar(
'<circular reference: ' +
(j$.isArray_(value) ? 'Array' : 'Object') +
'>'
);
} else if (j$.isArray_(value) || j$.isA_('Object', value)) {
this.seen.push(value);
if (j$.isArray_(value)) {
@@ -72,7 +101,11 @@ getJasmineRequireObj().pp = function(j$) {
}
};
PrettyPrinter.prototype.iterateObject = function(obj, fn) {
SinglePrettyPrintRun.prototype.applyCustomFormatters_ = function(value) {
return customFormat(value, this.customObjectFormatters_);
};
SinglePrettyPrintRun.prototype.iterateObject = function(obj, fn) {
var objKeys = keys(obj, j$.isArray_(obj));
var isGetter = function isGetter(prop) {};
@@ -81,7 +114,6 @@ getJasmineRequireObj().pp = function(j$) {
var getter = obj.__lookupGetter__(prop);
return !j$.util.isUndefined(getter) && getter !== null;
};
}
var length = Math.min(objKeys.length, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
for (var i = 0; i < length; i++) {
@@ -92,15 +124,15 @@ getJasmineRequireObj().pp = function(j$) {
return objKeys.length > length;
};
PrettyPrinter.prototype.emitScalar = function(value) {
SinglePrettyPrintRun.prototype.emitScalar = function(value) {
this.append(value);
};
PrettyPrinter.prototype.emitString = function(value) {
this.append('\'' + value + '\'');
SinglePrettyPrintRun.prototype.emitString = function(value) {
this.append("'" + value + "'");
};
PrettyPrinter.prototype.emitArray = function(array) {
SinglePrettyPrintRun.prototype.emitArray = function(array) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Array');
return;
@@ -113,7 +145,7 @@ getJasmineRequireObj().pp = function(j$) {
}
this.format(array[i]);
}
if(array.length > length){
if (array.length > length) {
this.append(', ...');
}
@@ -129,12 +161,14 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(array, property, isGetter);
});
if (truncated) { this.append(', ...'); }
if (truncated) {
this.append(', ...');
}
this.append(' ]');
};
PrettyPrinter.prototype.emitSet = function(set) {
SinglePrettyPrintRun.prototype.emitSet = function(set) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Set');
return;
@@ -142,7 +176,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append('Set( ');
var size = Math.min(set.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var i = 0;
set.forEach( function( value, key ) {
set.forEach(function(value, key) {
if (i >= size) {
return;
}
@@ -152,14 +186,14 @@ getJasmineRequireObj().pp = function(j$) {
this.format(value);
i++;
}, this );
if (set.size > size){
}, this);
if (set.size > size) {
this.append(', ...');
}
this.append(' )');
};
PrettyPrinter.prototype.emitMap = function(map) {
SinglePrettyPrintRun.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
@@ -167,30 +201,31 @@ getJasmineRequireObj().pp = function(j$) {
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var i = 0;
map.forEach( function( value, key ) {
map.forEach(function(value, key) {
if (i >= size) {
return;
}
if (i > 0) {
this.append(', ');
}
this.format([key,value]);
this.format([key, value]);
i++;
}, this );
if (map.size > size){
}, this);
if (map.size > size) {
this.append(', ...');
}
this.append(' )');
};
PrettyPrinter.prototype.emitObject = function(obj) {
SinglePrettyPrintRun.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
constructorName;
constructorName = typeof ctor === 'function' && obj instanceof ctor ?
j$.fnNameFor(obj.constructor) :
'null';
constructorName =
typeof ctor === 'function' && obj instanceof ctor
? j$.fnNameFor(obj.constructor)
: 'null';
this.append(constructorName);
@@ -212,14 +247,20 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(obj, property, isGetter);
});
if (truncated) { this.append(', ...'); }
if (truncated) {
this.append(', ...');
}
this.append(' })');
};
PrettyPrinter.prototype.emitTypedArray = function(arr) {
SinglePrettyPrintRun.prototype.emitTypedArray = function(arr) {
var constructorName = j$.fnNameFor(arr.constructor),
limitedArray = Array.prototype.slice.call(arr, 0, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH),
limitedArray = Array.prototype.slice.call(
arr,
0,
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH
),
itemsString = Array.prototype.join.call(limitedArray, ', ');
if (limitedArray.length !== arr.length) {
@@ -229,7 +270,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append(constructorName + ' [ ' + itemsString + ' ]');
};
PrettyPrinter.prototype.emitDomElement = function(el) {
SinglePrettyPrintRun.prototype.emitDomElement = function(el) {
var tagName = el.tagName.toLowerCase(),
attrs = el.attributes,
i,
@@ -255,17 +296,27 @@ getJasmineRequireObj().pp = function(j$) {
this.append(out);
};
PrettyPrinter.prototype.formatProperty = function(obj, property, isGetter) {
this.append(property);
this.append(': ');
if (isGetter) {
this.append('<getter>');
} else {
this.format(obj[property]);
}
SinglePrettyPrintRun.prototype.formatProperty = function(
obj,
property,
isGetter
) {
this.append(property);
this.append(': ');
if (isGetter) {
this.append('<getter>');
} else {
this.format(obj[property]);
}
};
PrettyPrinter.prototype.append = function(value) {
SinglePrettyPrintRun.prototype.append = function(value) {
// This check protects us from the rare case where an object has overriden
// `toString()` with an invalid implementation (returning a non-string).
if (typeof value !== 'string') {
value = Object.prototype.toString.call(value);
}
var result = truncate(value, j$.MAX_PRETTY_PRINT_CHARS - this.length);
this.length += result.value.length;
this.stringParts.push(result.value);
@@ -275,7 +326,6 @@ getJasmineRequireObj().pp = function(j$) {
}
};
function truncate(s, maxlen) {
if (s.length <= maxlen) {
return { value: s, truncated: false };
@@ -286,30 +336,33 @@ getJasmineRequireObj().pp = function(j$) {
}
function MaxCharsReachedError() {
this.message = 'Exceeded ' + j$.MAX_PRETTY_PRINT_CHARS +
this.message =
'Exceeded ' +
j$.MAX_PRETTY_PRINT_CHARS +
' characters while pretty-printing a value';
}
MaxCharsReachedError.prototype = new Error();
function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) :
(function(o) {
var allKeys = Object.keys
? Object.keys(obj)
: (function(o) {
var keys = [];
for (var key in o) {
if (j$.util.has(o, key)) {
keys.push(key);
}
if (j$.util.has(o, key)) {
keys.push(key);
}
}
return keys;
})(obj);
})(obj);
if (!isArray) {
return allKeys;
}
if (allKeys.length === 0) {
return allKeys;
return allKeys;
}
var extraKeys = [];
@@ -321,9 +374,32 @@ getJasmineRequireObj().pp = function(j$) {
return extraKeys;
}
return function(value) {
var prettyPrinter = new PrettyPrinter();
prettyPrinter.format(value);
return prettyPrinter.stringParts.join('');
function customFormat(value, customObjectFormatters) {
var i, result;
for (i = 0; i < customObjectFormatters.length; i++) {
result = customObjectFormatters[i](value);
if (result !== undefined) {
return result;
}
}
}
return function(customObjectFormatters) {
customObjectFormatters = customObjectFormatters || [];
var pp = function(value) {
var prettyPrinter = new SinglePrettyPrintRun(customObjectFormatters, pp);
prettyPrinter.format(value);
return prettyPrinter.stringParts.join('');
};
pp.customFormat_ = function(value) {
return customFormat(value, customObjectFormatters);
};
return pp;
};
};

View File

@@ -1,4 +1,6 @@
getJasmineRequireObj().QueueRunner = function(j$) {
var nextid = 1;
function StopExecutionError() {}
StopExecutionError.prototype = new Error();
j$.StopExecutionError = StopExecutionError;
@@ -18,20 +20,31 @@ getJasmineRequireObj().QueueRunner = function(j$) {
function emptyFn() {}
function QueueRunner(attrs) {
this.id_ = nextid++;
var queueableFns = attrs.queueableFns || [];
this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
this.firstCleanupIx = queueableFns.length;
this.onComplete = attrs.onComplete || emptyFn;
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.clearStack =
attrs.clearStack ||
function(fn) {
fn();
};
this.onException = attrs.onException || emptyFn;
this.userContext = attrs.userContext || new j$.UserContext();
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.timeout = attrs.timeout || {
setTimeout: setTimeout,
clearTimeout: clearTimeout
};
this.fail = attrs.fail || emptyFn;
this.globalErrors = attrs.globalErrors || { pushListener: emptyFn, popListener: emptyFn };
this.globalErrors = attrs.globalErrors || {
pushListener: emptyFn,
popListener: emptyFn
};
this.completeOnFirstError = !!attrs.completeOnFirstError;
this.errored = false;
if (typeof(this.onComplete) !== 'function') {
if (typeof this.onComplete !== 'function') {
throw new Error('invalid onComplete ' + JSON.stringify(this.onComplete));
}
this.deprecated = attrs.deprecated;
@@ -39,8 +52,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
QueueRunner.prototype.execute = function() {
var self = this;
this.handleFinalError = function(error) {
self.onException(error);
this.handleFinalError = function(message, source, lineno, colno, error) {
// Older browsers would send the error as the first parameter. HTML5
// specifies the the five parameters above. The error instance should
// be preffered, otherwise the call stack would get lost.
self.onException(error || message);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(0);
@@ -55,15 +71,22 @@ getJasmineRequireObj().QueueRunner = function(j$) {
};
QueueRunner.prototype.clearTimeout = function(timeoutId) {
Function.prototype.apply.apply(this.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
Function.prototype.apply.apply(this.timeout.clearTimeout, [
j$.getGlobal(),
[timeoutId]
]);
};
QueueRunner.prototype.setTimeout = function(fn, timeout) {
return Function.prototype.apply.apply(this.timeout.setTimeout, [j$.getGlobal(), [fn, timeout]]);
return Function.prototype.apply.apply(this.timeout.setTimeout, [
j$.getGlobal(),
[fn, timeout]
]);
};
QueueRunner.prototype.attempt = function attempt(iterativeIndex) {
var self = this, completedSynchronously = true,
var self = this,
completedSynchronously = true,
handleError = function handleError(error) {
onException(error);
next(error);
@@ -100,7 +123,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}),
errored = false,
queueableFn = self.queueableFns[iterativeIndex],
timeoutId;
timeoutId,
maybeThenable;
next.fail = function nextFail() {
self.fail.apply(null, arguments);
@@ -114,8 +138,12 @@ getJasmineRequireObj().QueueRunner = function(j$) {
var timeoutInterval = queueableFn.timeout || j$.DEFAULT_TIMEOUT_INTERVAL;
timeoutId = self.setTimeout(function() {
var error = new Error(
'Timeout - Async callback was not invoked within ' + timeoutInterval + 'ms ' +
(queueableFn.timeout ? '(custom timeout)' : '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
'Timeout - Async function did not complete within ' +
timeoutInterval +
'ms ' +
(queueableFn.timeout
? '(custom timeout)'
: '(set by jasmine.DEFAULT_TIMEOUT_INTERVAL)')
);
onException(error);
next();
@@ -124,7 +152,7 @@ getJasmineRequireObj().QueueRunner = function(j$) {
try {
if (queueableFn.fn.length === 0) {
var maybeThenable = queueableFn.fn.call(self.userContext);
maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, onPromiseRejection);
@@ -132,7 +160,8 @@ getJasmineRequireObj().QueueRunner = function(j$) {
return { completedSynchronously: false };
}
} else {
queueableFn.fn.call(self.userContext, next);
maybeThenable = queueableFn.fn.call(self.userContext, next);
this.diagnoseConflictingAsync_(queueableFn.fn, maybeThenable);
completedSynchronously = false;
return { completedSynchronously: false };
}
@@ -160,8 +189,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self = this,
iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
for (
iterativeIndex = recursiveIndex;
iterativeIndex < length;
iterativeIndex++
) {
var result = this.attempt(iterativeIndex);
if (!result.completedSynchronously) {
@@ -180,7 +212,29 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.globalErrors.popListener(self.handleFinalError);
self.onComplete(self.errored && new StopExecutionError());
});
};
QueueRunner.prototype.diagnoseConflictingAsync_ = function(fn, retval) {
if (retval && j$.isFunction_(retval.then)) {
// Issue a warning that matches the user's code
if (j$.isAsyncFunction_(fn)) {
this.deprecated(
'An asynchronous before/it/after ' +
'function was defined with the async keyword but also took a ' +
'done callback. This is not supported and will stop working in' +
' the future. Either remove the done callback (recommended) or ' +
'remove the async keyword.'
);
} else {
this.deprecated(
'An asynchronous before/it/after ' +
'function took a done callback but also returned a promise. ' +
'This is not supported and will stop working in the future. ' +
'Either remove the done callback (recommended) or change the ' +
'function to not return a promise.'
);
}
}
};
return QueueRunner;

View File

@@ -1,6 +1,5 @@
getJasmineRequireObj().ReportDispatcher = function(j$) {
function ReportDispatcher(methods, queueRunnerFactory) {
var dispatchedMethods = methods || [];
for (var i = 0; i < dispatchedMethods.length; i++) {
@@ -9,7 +8,7 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
return function() {
dispatch(m, arguments);
};
}(method));
})(method);
}
var reporters = [];
@@ -31,7 +30,7 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
function dispatch(method, args) {
if (reporters.length === 0 && fallbackReporter !== null) {
reporters.push(fallbackReporter);
reporters.push(fallbackReporter);
}
var onComplete = args[args.length - 1];
args = j$.util.argsToArray(args).splice(0, args.length - 1);
@@ -57,13 +56,13 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
var thisArgs = j$.util.cloneArgs(args);
if (fn.length <= 1) {
fns.push({
fn: function () {
fn: function() {
return fn.apply(reporter, thisArgs);
}
});
} else {
fns.push({
fn: function (done) {
fn: function(done) {
return fn.apply(reporter, thisArgs.concat([done]));
}
});
@@ -73,4 +72,3 @@ getJasmineRequireObj().ReportDispatcher = function(j$) {
return ReportDispatcher;
};

View File

@@ -6,15 +6,32 @@ getJasmineRequireObj().Spec = function(j$) {
this.id = attrs.id;
this.description = attrs.description || '';
this.queueableFn = attrs.queueableFn;
this.beforeAndAfterFns = attrs.beforeAndAfterFns || function() { return {befores: [], afters: []}; };
this.userContext = attrs.userContext || function() { return {}; };
this.beforeAndAfterFns =
attrs.beforeAndAfterFns ||
function() {
return { befores: [], afters: [] };
};
this.userContext =
attrs.userContext ||
function() {
return {};
};
this.onStart = attrs.onStart || function() {};
this.getSpecName = attrs.getSpecName || function() { return ''; };
this.expectationResultFactory = attrs.expectationResultFactory || function() { };
this.getSpecName =
attrs.getSpecName ||
function() {
return '';
};
this.expectationResultFactory =
attrs.expectationResultFactory || function() {};
this.queueRunnerFactory = attrs.queueRunnerFactory || function() {};
this.catchingExceptions = attrs.catchingExceptions || function() { return true; };
this.catchingExceptions =
attrs.catchingExceptions ||
function() {
return true;
};
this.throwOnExpectationFailure = !!attrs.throwOnExpectationFailure;
this.timer = attrs.timer || j$.noopTimer;
this.timer = attrs.timer || new j$.Timer();
if (!this.queueableFn.fn) {
this.pend();
@@ -31,6 +48,7 @@ getJasmineRequireObj().Spec = function(j$) {
* @property {String} pendingReason - If the spec is {@link pending}, this will be the reason.
* @property {String} status - Once the spec has completed, this string represents the pass/fail status of this spec.
* @property {number} duration - The time in ms used by the spec execution, including any before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSpecProperty}
*/
this.result = {
id: this.id,
@@ -41,6 +59,7 @@ getJasmineRequireObj().Spec = function(j$) {
deprecationWarnings: [],
pendingReason: '',
duration: null,
properties: null
};
}
@@ -57,6 +76,11 @@ getJasmineRequireObj().Spec = function(j$) {
}
};
Spec.prototype.setSpecProperty = function(key, value) {
this.result.properties = this.result.properties || {};
this.result.properties[key] = value;
};
Spec.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
@@ -65,7 +89,7 @@ getJasmineRequireObj().Spec = function(j$) {
return this.asyncExpectationFactory(actual, this);
};
Spec.prototype.execute = function(onComplete, excluded) {
Spec.prototype.execute = function(onComplete, excluded, failSpecWithNoExp) {
var self = this;
var onStart = {
@@ -78,7 +102,8 @@ getJasmineRequireObj().Spec = function(j$) {
var complete = {
fn: function(done) {
self.queueableFn.fn = null;
self.result.status = self.status(excluded);
self.result.status = self.status(excluded, failSpecWithNoExp);
self.result.duration = self.timer.elapsed();
self.resultCallback(self.result, done);
}
};
@@ -90,12 +115,14 @@ getJasmineRequireObj().Spec = function(j$) {
isLeaf: true,
queueableFns: regularFns,
cleanupFns: fns.afters,
onException: function () {
onException: function() {
self.onException.apply(self, arguments);
},
onComplete: function() {
self.result.duration = self.timer.elapsed();
onComplete(self.result.status === 'failed' && new j$.StopExecutionError('spec failed'));
onComplete(
self.result.status === 'failed' &&
new j$.StopExecutionError('spec failed')
);
},
userContext: this.userContext()
};
@@ -121,13 +148,17 @@ getJasmineRequireObj().Spec = function(j$) {
return;
}
this.addExpectationResult(false, {
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
}, true);
this.addExpectationResult(
false,
{
matcherName: '',
passed: false,
expected: '',
actual: '',
error: e
},
true
);
};
Spec.prototype.pend = function(message) {
@@ -142,7 +173,7 @@ getJasmineRequireObj().Spec = function(j$) {
return this.result;
};
Spec.prototype.status = function(excluded) {
Spec.prototype.status = function(excluded, failSpecWithNoExpectations) {
if (excluded === true) {
return 'excluded';
}
@@ -151,11 +182,17 @@ getJasmineRequireObj().Spec = function(j$) {
return 'pending';
}
if (this.result.failedExpectations.length > 0) {
if (
this.result.failedExpectations.length > 0 ||
(failSpecWithNoExpectations &&
this.result.failedExpectations.length +
this.result.passedExpectations.length ===
0)
) {
return 'failed';
} else {
return 'passed';
}
return 'passed';
};
Spec.prototype.getFullName = function() {
@@ -166,13 +203,16 @@ getJasmineRequireObj().Spec = function(j$) {
if (typeof deprecation === 'string') {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(this.expectationResultFactory(deprecation));
this.result.deprecationWarnings.push(
this.expectationResultFactory(deprecation)
);
};
var extractCustomPendingMessage = function(e) {
var fullMessage = e.toString(),
boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
boilerplateEnd = boilerplateStart + Spec.pendingSpecExceptionMessage.length;
boilerplateStart = fullMessage.indexOf(Spec.pendingSpecExceptionMessage),
boilerplateEnd =
boilerplateStart + Spec.pendingSpecExceptionMessage.length;
return fullMessage.substr(boilerplateEnd);
};
@@ -180,7 +220,11 @@ getJasmineRequireObj().Spec = function(j$) {
Spec.pendingSpecExceptionMessage = '=> marked Pending';
Spec.isPendingSpecException = function(e) {
return !!(e && e.toString && e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1);
return !!(
e &&
e.toString &&
e.toString().indexOf(Spec.pendingSpecExceptionMessage) !== -1
);
};
return Spec;

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().Spy = function (j$) {
getJasmineRequireObj().Spy = function(j$) {
var nextOrder = (function() {
var order = 0;
@@ -8,26 +7,38 @@ getJasmineRequireObj().Spy = function (j$) {
};
})();
var matchersUtil = new j$.MatchersUtil({
customTesters: [],
pp: j$.makePrettyPrinter()
});
/**
* _Note:_ Do not construct this directly, use {@link spyOn}, {@link spyOnProperty}, {@link jasmine.createSpy}, or {@link jasmine.createSpyObj}
* @constructor
* @name Spy
*/
function Spy(name, originalFn, customStrategies) {
var numArgs = (typeof originalFn === 'function' ? originalFn.length : 0),
wrapper = makeFunc(numArgs, function () {
return spy.apply(this, Array.prototype.slice.call(arguments));
function Spy(
name,
originalFn,
customStrategies,
defaultStrategyFn,
getPromise
) {
var numArgs = typeof originalFn === 'function' ? originalFn.length : 0,
wrapper = makeFunc(numArgs, function(context, args, invokeNew) {
return spy(context, args, invokeNew);
}),
strategyDispatcher = new SpyStrategyDispatcher({
name: name,
fn: originalFn,
getSpy: function () {
getSpy: function() {
return wrapper;
},
customStrategies: customStrategies
customStrategies: customStrategies,
getPromise: getPromise
}),
callTracker = new j$.CallTracker(),
spy = function () {
spy = function(context, args, invokeNew) {
/**
* @name Spy.callData
* @property {object} object - `this` context for the invocation.
@@ -35,13 +46,13 @@ getJasmineRequireObj().Spy = function (j$) {
* @property {Array} args - The arguments passed for this invocation.
*/
var callData = {
object: this,
object: context,
invocationOrder: nextOrder(),
args: Array.prototype.slice.apply(arguments)
args: Array.prototype.slice.apply(args)
};
callTracker.track(callData);
var returnValue = strategyDispatcher.exec(this, arguments);
var returnValue = strategyDispatcher.exec(context, args, invokeNew);
callData.returnValue = returnValue;
return returnValue;
@@ -49,22 +60,54 @@ getJasmineRequireObj().Spy = function (j$) {
function makeFunc(length, fn) {
switch (length) {
case 1 : return function (a) { return fn.apply(this, arguments); };
case 2 : return function (a,b) { return fn.apply(this, arguments); };
case 3 : return function (a,b,c) { return fn.apply(this, arguments); };
case 4 : return function (a,b,c,d) { return fn.apply(this, arguments); };
case 5 : return function (a,b,c,d,e) { return fn.apply(this, arguments); };
case 6 : return function (a,b,c,d,e,f) { return fn.apply(this, arguments); };
case 7 : return function (a,b,c,d,e,f,g) { return fn.apply(this, arguments); };
case 8 : return function (a,b,c,d,e,f,g,h) { return fn.apply(this, arguments); };
case 9 : return function (a,b,c,d,e,f,g,h,i) { return fn.apply(this, arguments); };
default : return function () { return fn.apply(this, arguments); };
case 1:
return function wrap1(a) {
return fn(this, arguments, this instanceof wrap1);
};
case 2:
return function wrap2(a, b) {
return fn(this, arguments, this instanceof wrap2);
};
case 3:
return function wrap3(a, b, c) {
return fn(this, arguments, this instanceof wrap3);
};
case 4:
return function wrap4(a, b, c, d) {
return fn(this, arguments, this instanceof wrap4);
};
case 5:
return function wrap5(a, b, c, d, e) {
return fn(this, arguments, this instanceof wrap5);
};
case 6:
return function wrap6(a, b, c, d, e, f) {
return fn(this, arguments, this instanceof wrap6);
};
case 7:
return function wrap7(a, b, c, d, e, f, g) {
return fn(this, arguments, this instanceof wrap7);
};
case 8:
return function wrap8(a, b, c, d, e, f, g, h) {
return fn(this, arguments, this instanceof wrap8);
};
case 9:
return function wrap9(a, b, c, d, e, f, g, h, i) {
return fn(this, arguments, this instanceof wrap9);
};
default:
return function wrap() {
return fn(this, arguments, this instanceof wrap);
};
}
}
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');
throw new Error(
"Jasmine spies would overwrite the 'and' and 'calls' properties on the object being spied upon"
);
}
wrapper[prop] = originalFn[prop];
@@ -75,6 +118,7 @@ getJasmineRequireObj().Spy = function (j$) {
* whenever the spy is called with arguments that don't match any strategy
* created with {@link Spy#withArgs}.
* @name Spy#and
* @since 2.0.0
* @example
* spyOn(someObj, 'func').and.returnValue(42);
*/
@@ -83,6 +127,7 @@ getJasmineRequireObj().Spy = function (j$) {
* Specifies a strategy to be used for calls to the spy that have the
* specified arguments.
* @name Spy#withArgs
* @since 3.0.0
* @function
* @param {...*} args - The arguments to match
* @type {SpyStrategy}
@@ -95,10 +140,13 @@ getJasmineRequireObj().Spy = function (j$) {
};
wrapper.calls = callTracker;
if (defaultStrategyFn) {
defaultStrategyFn(wrapper.and);
}
return wrapper;
}
function SpyStrategyDispatcher(strategyArgs) {
var baseStrategy = new j$.SpyStrategy(strategyArgs);
var argsStrategies = new StrategyDict(function() {
@@ -107,18 +155,24 @@ getJasmineRequireObj().Spy = function (j$) {
this.and = baseStrategy;
this.exec = function(spy, args) {
this.exec = function(spy, args, invokeNew) {
var strategy = argsStrategies.get(args);
if (!strategy) {
if (argsStrategies.any() && !baseStrategy.isConfigured()) {
throw new Error('Spy \'' + strategyArgs.name + '\' received a call with arguments ' + j$.pp(Array.prototype.slice.call(args)) + ' but all configured strategies specify other arguments.');
throw new Error(
"Spy '" +
strategyArgs.name +
"' received a call with arguments " +
j$.pp(Array.prototype.slice.call(args)) +
' but all configured strategies specify other arguments.'
);
} else {
strategy = baseStrategy;
}
}
return strategy.exec(spy, args);
return strategy.exec(spy, args, invokeNew);
};
this.withArgs = function() {
@@ -153,7 +207,7 @@ getJasmineRequireObj().Spy = function (j$) {
var i;
for (i = 0; i < this.strategies.length; i++) {
if (j$.matchersUtil.equals(args, this.strategies[i].args)) {
if (matchersUtil.equals(args, this.strategies[i].args)) {
return this.strategies[i].strategy;
}
}

View File

@@ -1,39 +1,55 @@
getJasmineRequireObj().SpyFactory = function(j$) {
function SpyFactory(getCustomStrategies) {
function SpyFactory(getCustomStrategies, getDefaultStrategyFn, getPromise) {
var self = this;
this.createSpy = function(name, originalFn) {
return j$.Spy(name, originalFn, getCustomStrategies());
return j$.Spy(
name,
originalFn,
getCustomStrategies(),
getDefaultStrategyFn(),
getPromise
);
};
this.createSpyObj = function(baseName, methodNames) {
var baseNameIsCollection = j$.isObject_(baseName) || j$.isArray_(baseName);
this.createSpyObj = function(baseName, methodNames, propertyNames) {
var baseNameIsCollection =
j$.isObject_(baseName) || j$.isArray_(baseName);
if (baseNameIsCollection && j$.util.isUndefined(methodNames)) {
if (baseNameIsCollection) {
propertyNames = methodNames;
methodNames = baseName;
baseName = 'unknown';
}
var obj = {};
var spiesWereSet = false;
var spy, descriptor;
if (j$.isArray_(methodNames)) {
for (var i = 0; i < methodNames.length; i++) {
obj[methodNames[i]] = self.createSpy(baseName + '.' + methodNames[i]);
spiesWereSet = true;
}
} else if (j$.isObject_(methodNames)) {
for (var key in methodNames) {
if (methodNames.hasOwnProperty(key)) {
obj[key] = self.createSpy(baseName + '.' + key);
obj[key].and.returnValue(methodNames[key]);
spiesWereSet = true;
}
var methods = normalizeKeyValues(methodNames);
for (var i = 0; i < methods.length; i++) {
spy = obj[methods[i][0]] = self.createSpy(
baseName + '.' + methods[i][0]
);
if (methods[i].length > 1) {
spy.and.returnValue(methods[i][1]);
}
}
if (!spiesWereSet) {
var properties = normalizeKeyValues(propertyNames);
for (var i = 0; i < properties.length; i++) {
descriptor = {
enumerable: true,
get: self.createSpy(baseName + '.' + properties[i][0] + '.get'),
set: self.createSpy(baseName + '.' + properties[i][0] + '.set')
};
if (properties[i].length > 1) {
descriptor.get.and.returnValue(properties[i][1]);
descriptor.set.and.returnValue(properties[i][1]);
}
Object.defineProperty(obj, properties[i][0], descriptor);
}
if (methods.length === 0 && properties.length === 0) {
throw 'createSpyObj requires a non-empty array or object of method names to create spies for';
}
@@ -41,5 +57,21 @@ getJasmineRequireObj().SpyFactory = function(j$) {
};
}
function normalizeKeyValues(object) {
var result = [];
if (j$.isArray_(object)) {
for (var i = 0; i < object.length; i++) {
result.push([object[i]]);
}
} else if (j$.isObject_(object)) {
for (var key in object) {
if (object.hasOwnProperty(key)) {
result.push([key, object[key]]);
}
}
}
return result;
}
return SpyFactory;
};

View File

@@ -1,21 +1,33 @@
getJasmineRequireObj().SpyRegistry = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
var spyOnMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
var spyOnPropertyMsg = j$.formatErrorMsg(
'<spyOnProperty>',
'spyOnProperty(<object>, <propName>, [accessType])'
);
function SpyRegistry(options) {
options = options || {};
var global = options.global || j$.getGlobal();
var createSpy = options.createSpy;
var currentSpies = options.currentSpies || function() { return []; };
var currentSpies =
options.currentSpies ||
function() {
return [];
};
this.allowRespy = function(allow){
this.allowRespy = function(allow) {
this.respy = allow;
};
this.spyOn = function(obj, methodName) {
var getErrorMsg = spyOnMsg;
if (j$.util.isUndefined(obj) || obj === null) {
throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
throw new Error(
getErrorMsg(
'could not find an object to spy upon for ' + methodName + '()'
)
);
}
if (j$.util.isUndefined(methodName) || methodName === null) {
@@ -26,25 +38,32 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
throw new Error(getErrorMsg(methodName + '() method does not exist'));
}
if (obj[methodName] && j$.isSpy(obj[methodName]) ) {
if ( !!this.respy ){
if (obj[methodName] && j$.isSpy(obj[methodName])) {
if (this.respy) {
return obj[methodName];
}else {
throw new Error(getErrorMsg(methodName + ' has already been spied upon'));
} else {
throw new Error(
getErrorMsg(methodName + ' has already been spied upon')
);
}
}
var descriptor = Object.getOwnPropertyDescriptor(obj, methodName);
if (descriptor && !(descriptor.writable || descriptor.set)) {
throw new Error(getErrorMsg(methodName + ' is not declared writable or has no setter'));
throw new Error(
getErrorMsg(methodName + ' is not declared writable or has no setter')
);
}
var originalMethod = obj[methodName],
spiedMethod = createSpy(methodName, originalMethod),
restoreStrategy;
if (Object.prototype.hasOwnProperty.call(obj, methodName) || (obj === global && methodName === 'onerror')) {
if (
Object.prototype.hasOwnProperty.call(obj, methodName) ||
(obj === global && methodName === 'onerror')
) {
restoreStrategy = function() {
obj[methodName] = originalMethod;
};
@@ -65,34 +84,58 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
return spiedMethod;
};
this.spyOnProperty = function (obj, propertyName, accessType) {
this.spyOnProperty = function(obj, propertyName, accessType) {
var getErrorMsg = spyOnPropertyMsg;
accessType = accessType || 'get';
if (j$.util.isUndefined(obj)) {
throw new Error('spyOn could not find an object to spy upon for ' + propertyName + '');
throw new Error(
getErrorMsg(
'spyOn could not find an object to spy upon for ' +
propertyName +
''
)
);
}
if (j$.util.isUndefined(propertyName)) {
throw new Error('No property name supplied');
throw new Error(getErrorMsg('No property name supplied'));
}
var descriptor = j$.util.getPropertyDescriptor(obj, propertyName);
if (!descriptor) {
throw new Error(propertyName + ' property does not exist');
throw new Error(getErrorMsg(propertyName + ' property does not exist'));
}
if (!descriptor.configurable) {
throw new Error(propertyName + ' is not declared configurable');
throw new Error(
getErrorMsg(propertyName + ' is not declared configurable')
);
}
if(!descriptor[accessType]) {
throw new Error('Property ' + propertyName + ' does not have access type ' + accessType);
if (!descriptor[accessType]) {
throw new Error(
getErrorMsg(
'Property ' +
propertyName +
' does not have access type ' +
accessType
)
);
}
if (j$.isSpy(descriptor[accessType])) {
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
throw new Error(propertyName + ' has already been spied upon');
if (this.respy) {
return descriptor[accessType];
} else {
throw new Error(
getErrorMsg(
propertyName + '#' + accessType + ' has already been spied upon'
)
);
}
}
var originalDescriptor = j$.util.clone(descriptor),
@@ -122,16 +165,36 @@ getJasmineRequireObj().SpyRegistry = function(j$) {
this.spyOnAllFunctions = function(obj) {
if (j$.util.isUndefined(obj)) {
throw new Error('spyOnAllFunctions could not find an object to spy upon');
throw new Error(
'spyOnAllFunctions could not find an object to spy upon'
);
}
for (var prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] instanceof Function) {
var descriptor = Object.getOwnPropertyDescriptor(obj, prop);
if ((descriptor.writable || descriptor.set) && descriptor.configurable) {
this.spyOn(obj, prop);
var pointer = obj,
props = [],
prop,
descriptor;
while (pointer) {
for (prop in pointer) {
if (
Object.prototype.hasOwnProperty.call(pointer, prop) &&
pointer[prop] instanceof Function
) {
descriptor = Object.getOwnPropertyDescriptor(pointer, prop);
if (
(descriptor.writable || descriptor.set) &&
descriptor.configurable
) {
props.push(prop);
}
}
}
pointer = Object.getPrototypeOf(pointer);
}
for (var i = 0; i < props.length; i++) {
this.spyOn(obj, props[i]);
}
return obj;

View File

@@ -1,14 +1,16 @@
getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* @interface SpyStrategy
*/
function SpyStrategy(options) {
options = options || {};
var self = this;
/**
* Get the identifying information for the spy.
* @name SpyStrategy#identity
* @since 3.0.0
* @member
* @type {String}
*/
@@ -17,12 +19,62 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
this.getSpy = options.getSpy || function() {};
this.plan = this._defaultPlan = function() {};
var k, cs = options.customStrategies || {};
var k,
cs = options.customStrategies || {};
for (k in cs) {
if (j$.util.has(cs, k) && !this[k]) {
this[k] = createCustomPlan(cs[k]);
}
}
var getPromise =
typeof options.getPromise === 'function'
? options.getPromise
: function() {};
var requirePromise = function(name) {
var Promise = getPromise();
if (!Promise) {
throw new Error(
name +
' requires global Promise, or `Promise` configured with `jasmine.getEnv().configure()`'
);
}
return Promise;
};
/**
* Tell the spy to return a promise resolving to the specified value when invoked.
* @name SpyStrategy#resolveTo
* @since 3.5.0
* @function
* @param {*} value The value to return.
*/
this.resolveTo = function(value) {
var Promise = requirePromise('resolveTo');
self.plan = function() {
return Promise.resolve(value);
};
return self.getSpy();
};
/**
* Tell the spy to return a promise rejecting with the specified value when invoked.
* @name SpyStrategy#rejectWith
* @since 3.5.0
* @function
* @param {*} value The value to return.
*/
this.rejectWith = function(value) {
var Promise = requirePromise('rejectWith');
self.plan = function() {
return Promise.reject(value);
};
return self.getSpy();
};
}
function createCustomPlan(factory) {
@@ -41,15 +93,22 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Execute the current spy strategy.
* @name SpyStrategy#exec
* @since 2.0.0
* @function
*/
SpyStrategy.prototype.exec = function(context, args) {
return this.plan.apply(context, args);
SpyStrategy.prototype.exec = function(context, args, invokeNew) {
var contextArgs = [context].concat(
args ? Array.prototype.slice.call(args) : []
);
var target = this.plan.bind.apply(this.plan, contextArgs);
return invokeNew ? new target() : target();
};
/**
* Tell the spy to call through to the real implementation when invoked.
* @name SpyStrategy#callThrough
* @since 2.0.0
* @function
*/
SpyStrategy.prototype.callThrough = function() {
@@ -60,6 +119,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Tell the spy to return the value when invoked.
* @name SpyStrategy#returnValue
* @since 2.0.0
* @function
* @param {*} value The value to return.
*/
@@ -73,12 +133,13 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Tell the spy to return one of the specified values (sequentially) each time the spy is invoked.
* @name SpyStrategy#returnValues
* @since 2.1.0
* @function
* @param {...*} values - Values to be returned on subsequent calls to the spy.
*/
SpyStrategy.prototype.returnValues = function() {
var values = Array.prototype.slice.call(arguments);
this.plan = function () {
this.plan = function() {
return values.shift();
};
return this.getSpy();
@@ -87,11 +148,12 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Tell the spy to throw an error when invoked.
* @name SpyStrategy#throwError
* @since 2.0.0
* @function
* @param {Error|String} something Thing to throw
* @param {Error|Object|String} something Thing to throw
*/
SpyStrategy.prototype.throwError = function(something) {
var error = (something instanceof Error) ? something : new Error(something);
var error = j$.isString_(something) ? new Error(something) : something;
this.plan = function() {
throw error;
};
@@ -101,12 +163,21 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Tell the spy to call a fake implementation when invoked.
* @name SpyStrategy#callFake
* @since 2.0.0
* @function
* @param {Function} fn The function to invoke with the passed parameters.
*/
SpyStrategy.prototype.callFake = function(fn) {
if(!(j$.isFunction_(fn) || j$.isAsyncFunction_(fn))) {
throw new Error('Argument passed to callFake should be a function, got ' + fn);
if (
!(
j$.isFunction_(fn) ||
j$.isAsyncFunction_(fn) ||
j$.isGeneratorFunction_(fn)
)
) {
throw new Error(
'Argument passed to callFake should be a function, got ' + fn
);
}
this.plan = fn;
return this.getSpy();
@@ -115,6 +186,7 @@ getJasmineRequireObj().SpyStrategy = function(j$) {
/**
* Tell the spy to do nothing when invoked. This is the default.
* @name SpyStrategy#stub
* @since 2.0.0
* @function
*/
SpyStrategy.prototype.stub = function(fn) {

View File

@@ -1,8 +1,8 @@
getJasmineRequireObj().StackTrace = function(j$) {
function StackTrace(error) {
var lines = error.stack
.split('\n')
.filter(function(line) { return line !== ''; });
var lines = error.stack.split('\n').filter(function(line) {
return line !== '';
});
var extractResult = extractMessage(error.message, lines);
@@ -21,7 +21,12 @@ getJasmineRequireObj().StackTrace = function(j$) {
// e.g. " at QueueRunner.run (http://localhost:8888/__jasmine__/jasmine.js:4320:20)"
// Note that the "function name" can include a surprisingly large set of
// characters, including angle brackets and square brackets.
{ re: /^\s*at ([^\)]+) \(([^\)]+)\)$/, fnIx: 1, fileLineColIx: 2, style: 'v8' },
{
re: /^\s*at ([^\)]+) \(([^\)]+)\)$/,
fnIx: 1,
fileLineColIx: 2,
style: 'v8'
},
// NodeJS alternate form, often mixed in with the Chrome style
// e.g. " at /some/path:4320:20
@@ -30,7 +35,12 @@ getJasmineRequireObj().StackTrace = function(j$) {
// PhantomJS on OS X, Safari, Firefox
// e.g. "run@http://localhost:8888/__jasmine__/jasmine.js:4320:27"
// or "http://localhost:8888/__jasmine__/jasmine.js:4320:27"
{ re: /^(([^@\s]+)@)?([^\s]+)$/, fnIx: 2, fileLineColIx: 3, style: 'webkit' }
{
re: /^(([^@\s]+)@)?([^\s]+)$/,
fnIx: 2,
fileLineColIx: 3,
style: 'webkit'
}
];
// regexes should capture the function name (if any) as group 1
@@ -41,11 +51,16 @@ getJasmineRequireObj().StackTrace = function(j$) {
var convertedLine = first(framePatterns, function(pattern) {
var overallMatch = line.match(pattern.re),
fileLineColMatch;
if (!overallMatch) { return null; }
if (!overallMatch) {
return null;
}
fileLineColMatch = overallMatch[pattern.fileLineColIx].match(
/^(.*):(\d+):\d+$/);
if (!fileLineColMatch) { return null; }
/^(.*):(\d+):\d+$/
);
if (!fileLineColMatch) {
return null;
}
style = style || pattern.style;
return {
@@ -89,7 +104,7 @@ getJasmineRequireObj().StackTrace = function(j$) {
}
function messagePrefixLength(message, stackLines) {
if (!stackLines[0].match(/^Error/)) {
if (!stackLines[0].match(/^\w*Error/)) {
return 0;
}
@@ -104,6 +119,6 @@ getJasmineRequireObj().StackTrace = function(j$) {
return messageLines.length;
}
return StackTrace;
};

View File

@@ -14,7 +14,7 @@ getJasmineRequireObj().Suite = function(j$) {
this.beforeAllFns = [];
this.afterAllFns = [];
this.timer = attrs.timer || j$.noopTimer;
this.timer = attrs.timer || new j$.Timer();
this.children = [];
@@ -27,6 +27,7 @@ getJasmineRequireObj().Suite = function(j$) {
* @property {Expectation[]} deprecationWarnings - The list of deprecation warnings that occurred on this suite.
* @property {String} status - Once the suite has completed, this string represents the pass/fail status of this suite.
* @property {number} duration - The time in ms for Suite execution, including any before/afterAll, before/afterEach.
* @property {Object} properties - User-supplied properties, if any, that were set using {@link Env#setSuiteProperty}
*/
this.result = {
id: this.id,
@@ -35,9 +36,15 @@ getJasmineRequireObj().Suite = function(j$) {
failedExpectations: [],
deprecationWarnings: [],
duration: null,
properties: null
};
}
Suite.prototype.setSuiteProperty = function(key, value) {
this.result.properties = this.result.properties || {};
this.result.properties[key] = value;
};
Suite.prototype.expect = function(actual) {
return this.expectationFactory(actual, this);
};
@@ -48,7 +55,11 @@ getJasmineRequireObj().Suite = function(j$) {
Suite.prototype.getFullName = function() {
var fullName = [];
for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
for (
var parentSuite = this;
parentSuite;
parentSuite = parentSuite.parentSuite
) {
if (parentSuite.parentSuite) {
fullName.unshift(parentSuite.description);
}
@@ -85,7 +96,7 @@ getJasmineRequireObj().Suite = function(j$) {
};
function removeFns(queueableFns) {
for(var i = 0; i < queueableFns.length; i++) {
for (var i = 0; i < queueableFns.length; i++) {
queueableFns[i].fn = null;
}
}
@@ -124,7 +135,9 @@ getJasmineRequireObj().Suite = function(j$) {
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
this.sharedContext = this.parentSuite
? this.parentSuite.clonedSharedUserContext()
: new j$.UserContext();
}
return this.sharedContext;
@@ -155,11 +168,11 @@ getJasmineRequireObj().Suite = function(j$) {
this.result.failedExpectations.push(failedExpectation);
};
Suite.prototype.addExpectationResult = function () {
if(isFailure(arguments)) {
Suite.prototype.addExpectationResult = function() {
if (isFailure(arguments)) {
var data = arguments[1];
this.result.failedExpectations.push(this.expectationResultFactory(data));
if(this.throwOnExpectationFailure) {
if (this.throwOnExpectationFailure) {
throw new j$.errors.ExpectationFailed();
}
}
@@ -169,7 +182,9 @@ getJasmineRequireObj().Suite = function(j$) {
if (typeof deprecation === 'string') {
deprecation = { message: deprecation };
}
this.result.deprecationWarnings.push(this.expectationResultFactory(deprecation));
this.result.deprecationWarnings.push(
this.expectationResultFactory(deprecation)
);
};
function isFailure(args) {

View File

@@ -1,6 +1,8 @@
getJasmineRequireObj().Timer = function() {
var defaultNow = (function(Date) {
return function() { return new Date().getTime(); };
return function() {
return new Date().getTime();
};
})(Date);
function Timer(options) {
@@ -20,10 +22,3 @@ getJasmineRequireObj().Timer = function() {
return Timer;
};
getJasmineRequireObj().noopTimer = function() {
return {
start: function() {},
elapsed: function() { return 0; }
};
};

View File

@@ -1,16 +1,25 @@
getJasmineRequireObj().TreeProcessor = function() {
function TreeProcessor(attrs) {
var tree = attrs.tree,
runnableIds = attrs.runnableIds,
queueRunnerFactory = attrs.queueRunnerFactory,
nodeStart = attrs.nodeStart || function() {},
nodeComplete = attrs.nodeComplete || function() {},
orderChildren = attrs.orderChildren || function(node) { return node.children; },
excludeNode = attrs.excludeNode || function(node) { return false; },
stats = { valid: true },
processed = false,
defaultMin = Infinity,
defaultMax = 1 - Infinity;
runnableIds = attrs.runnableIds,
queueRunnerFactory = attrs.queueRunnerFactory,
nodeStart = attrs.nodeStart || function() {},
nodeComplete = attrs.nodeComplete || function() {},
failSpecWithNoExpectations = !!attrs.failSpecWithNoExpectations,
orderChildren =
attrs.orderChildren ||
function(node) {
return node.children;
},
excludeNode =
attrs.excludeNode ||
function(node) {
return false;
},
stats = { valid: true },
processed = false,
defaultMin = Infinity,
defaultMax = 1 - Infinity;
this.processTree = function() {
processNode(tree, true);
@@ -59,13 +68,15 @@ getJasmineRequireObj().TreeProcessor = function() {
stats[node.id] = {
excluded: excluded,
willExecute: !excluded && !node.markedPending,
segments: [{
index: 0,
owner: node,
nodes: [node],
min: startingMin(executableIndex),
max: startingMax(executableIndex)
}]
segments: [
{
index: 0,
owner: node,
nodes: [node],
min: startingMin(executableIndex),
max: startingMax(executableIndex)
}
]
};
} else {
var hasExecutableChild = false;
@@ -107,14 +118,29 @@ getJasmineRequireObj().TreeProcessor = function() {
return executableIndex === undefined ? defaultMax : executableIndex;
}
function segmentChildren(node, orderedChildren, nodeStats, executableIndex) {
var currentSegment = { index: 0, owner: node, nodes: [], min: startingMin(executableIndex), max: startingMax(executableIndex) },
result = [currentSegment],
lastMax = defaultMax,
orderedChildSegments = orderChildSegments(orderedChildren);
function segmentChildren(
node,
orderedChildren,
nodeStats,
executableIndex
) {
var currentSegment = {
index: 0,
owner: node,
nodes: [],
min: startingMin(executableIndex),
max: startingMax(executableIndex)
},
result = [currentSegment],
lastMax = defaultMax,
orderedChildSegments = orderChildSegments(orderedChildren);
function isSegmentBoundary(minIndex) {
return lastMax !== defaultMax && minIndex !== defaultMin && lastMax < minIndex - 1;
return (
lastMax !== defaultMax &&
minIndex !== defaultMin &&
lastMax < minIndex - 1
);
}
for (var i = 0; i < orderedChildSegments.length; i++) {
@@ -123,7 +149,13 @@ getJasmineRequireObj().TreeProcessor = function() {
minIndex = childSegment.min;
if (isSegmentBoundary(minIndex)) {
currentSegment = {index: result.length, owner: node, nodes: [], min: defaultMin, max: defaultMax};
currentSegment = {
index: result.length,
owner: node,
nodes: [],
min: defaultMin,
max: defaultMax
};
result.push(currentSegment);
}
@@ -138,11 +170,11 @@ getJasmineRequireObj().TreeProcessor = function() {
function orderChildSegments(children) {
var specifiedOrder = [],
unspecifiedOrder = [];
unspecifiedOrder = [];
for (var i = 0; i < children.length; i++) {
var child = children[i],
segments = stats[child.id].segments;
segments = stats[child.id].segments;
for (var j = 0; j < segments.length; j++) {
var seg = segments[j];
@@ -173,7 +205,7 @@ getJasmineRequireObj().TreeProcessor = function() {
};
queueRunnerFactory({
onComplete: function () {
onComplete: function() {
var args = Array.prototype.slice.call(arguments, [0]);
node.cleanupBeforeAfter();
nodeComplete(node, node.getResult(), function() {
@@ -182,7 +214,7 @@ getJasmineRequireObj().TreeProcessor = function() {
},
queueableFns: [onStart].concat(wrapChildren(node, segmentNumber)),
userContext: node.sharedUserContext(),
onException: function () {
onException: function() {
node.onException.apply(node, arguments);
}
});
@@ -190,17 +222,25 @@ getJasmineRequireObj().TreeProcessor = function() {
};
} else {
return {
fn: function(done) { node.execute(done, stats[node.id].excluded); }
fn: function(done) {
node.execute(
done,
stats[node.id].excluded,
failSpecWithNoExpectations
);
}
};
}
}
function wrapChildren(node, segmentNumber) {
var result = [],
segmentChildren = stats[node.id].segments[segmentNumber].nodes;
segmentChildren = stats[node.id].segments[segmentNumber].nodes;
for (var i = 0; i < segmentChildren.length; i++) {
result.push(executeNode(segmentChildren[i].owner, segmentChildren[i].index));
result.push(
executeNode(segmentChildren[i].owner, segmentChildren[i].index)
);
}
if (!stats[node.id].willExecute) {

View File

@@ -1,6 +1,5 @@
getJasmineRequireObj().UserContext = function(j$) {
function UserContext() {
}
function UserContext() {}
UserContext.fromExisting = function(oldContext) {
var context = new UserContext();
@@ -14,5 +13,5 @@ getJasmineRequireObj().UserContext = function(j$) {
return context;
};
return UserContext;
return UserContext;
};

View File

@@ -0,0 +1,107 @@
getJasmineRequireObj().asymmetricEqualityTesterArgCompatShim = function(j$) {
/*
Older versions of Jasmine passed an array of custom equality testers as the
second argument to each asymmetric equality tester's `asymmetricMatch`
method. Newer versions will pass a `MatchersUtil` instance. The
asymmetricEqualityTesterArgCompatShim allows for a graceful migration from
the old interface to the new by "being" both an array of custom equality
testers and a `MatchersUtil` at the same time.
This code should be removed in the next major release.
*/
var likelyArrayProps = [
'concat',
'constructor',
'copyWithin',
'entries',
'every',
'fill',
'filter',
'find',
'findIndex',
'flat',
'flatMap',
'forEach',
'includes',
'indexOf',
'join',
'keys',
'lastIndexOf',
'length',
'map',
'pop',
'push',
'reduce',
'reduceRight',
'reverse',
'shift',
'slice',
'some',
'sort',
'splice',
'toLocaleString',
'toSource',
'toString',
'unshift',
'values'
];
function asymmetricEqualityTesterArgCompatShim(
matchersUtil,
customEqualityTesters
) {
var self = Object.create(matchersUtil),
props,
i,
k;
copy(self, customEqualityTesters, 'length');
for (i = 0; i < customEqualityTesters.length; i++) {
copy(self, customEqualityTesters, i);
}
var props = arrayProps();
for (i = 0; i < props.length; i++) {
k = props[i];
// Skip length (dealt with above), and anything that collides with
// MatchesUtil e.g. an Array.prototype.contains method added by user code
if (k !== 'length' && !self[k]) {
copy(self, Array.prototype, k);
}
}
return self;
}
function copy(dest, src, propName) {
Object.defineProperty(dest, propName, {
get: function() {
return src[propName];
}
});
}
function arrayProps() {
var props, a, k;
if (!Object.getOwnPropertyDescriptors) {
return likelyArrayProps.filter(function(k) {
return Array.prototype.hasOwnProperty(k);
});
}
props = Object.getOwnPropertyDescriptors(Array.prototype); // eslint-disable-line compat/compat
a = [];
for (k in props) {
a.push(k);
}
return a;
}
return asymmetricEqualityTesterArgCompatShim;
};

View File

@@ -1,10 +1,9 @@
getJasmineRequireObj().Any = function(j$) {
function Any(expectedObject) {
if (typeof expectedObject === 'undefined') {
throw new TypeError(
'jasmine.any() expects to be passed a constructor function. ' +
'Please pass one or use jasmine.anything() to match any object.'
'Please pass one or use jasmine.anything() to match any object.'
);
}
this.expectedObject = expectedObject;

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().Anything = function(j$) {
function Anything() {}
Anything.prototype.asymmetricMatch = function(other) {

View File

@@ -3,14 +3,25 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
this.sample = sample;
}
ArrayContaining.prototype.asymmetricMatch = function(other, customTesters) {
ArrayContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayContaining, not ' + j$.pp(this.sample) + '.');
throw new Error(
'You must provide an array to arrayContaining, not ' +
j$.pp(this.sample) +
'.'
);
}
// If the actual parameter is not an array, we can fail immediately, since it couldn't
// possibly be an "array containing" anything. However, we also want an empty sample
// array to match anything, so we need to double-check we aren't in that case
if (!j$.isArray_(other) && this.sample.length > 0) {
return false;
}
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) {
if (!matchersUtil.contains(other, item)) {
return false;
}
}
@@ -18,8 +29,8 @@ getJasmineRequireObj().ArrayContaining = function(j$) {
return true;
};
ArrayContaining.prototype.jasmineToString = function () {
return '<jasmine.arrayContaining(' + j$.pp(this.sample) +')>';
ArrayContaining.prototype.jasmineToString = function(pp) {
return '<jasmine.arrayContaining(' + pp(this.sample) + ')>';
};
return ArrayContaining;

View File

@@ -1,12 +1,18 @@
getJasmineRequireObj().ArrayWithExactContents = function(j$) {
function ArrayWithExactContents(sample) {
this.sample = sample;
}
ArrayWithExactContents.prototype.asymmetricMatch = function(other, customTesters) {
ArrayWithExactContents.prototype.asymmetricMatch = function(
other,
matchersUtil
) {
if (!j$.isArray_(this.sample)) {
throw new Error('You must provide an array to arrayWithExactContents, not ' + j$.pp(this.sample) + '.');
throw new Error(
'You must provide an array to arrayWithExactContents, not ' +
j$.pp(this.sample) +
'.'
);
}
if (this.sample.length !== other.length) {
@@ -15,7 +21,7 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
for (var i = 0; i < this.sample.length; i++) {
var item = this.sample[i];
if (!j$.matchersUtil.contains(other, item, customTesters)) {
if (!matchersUtil.contains(other, item)) {
return false;
}
}
@@ -23,8 +29,8 @@ getJasmineRequireObj().ArrayWithExactContents = function(j$) {
return true;
};
ArrayWithExactContents.prototype.jasmineToString = function() {
return '<jasmine.arrayWithExactContents ' + j$.pp(this.sample) + '>';
ArrayWithExactContents.prototype.jasmineToString = function(pp) {
return '<jasmine.arrayWithExactContents(' + pp(this.sample) + ')>';
};
return ArrayWithExactContents;

View File

@@ -1,8 +1,7 @@
getJasmineRequireObj().Empty = function (j$) {
getJasmineRequireObj().Empty = function(j$) {
function Empty() {}
Empty.prototype.asymmetricMatch = function (other) {
Empty.prototype.asymmetricMatch = function(other) {
if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
return other.length === 0;
}
@@ -17,7 +16,7 @@ getJasmineRequireObj().Empty = function (j$) {
return false;
};
Empty.prototype.jasmineToString = function () {
Empty.prototype.jasmineToString = function() {
return '<jasmine.empty>';
};

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().Falsy = function(j$) {
function Falsy() {}
Falsy.prototype.asymmetricMatch = function(other) {

View File

@@ -0,0 +1,43 @@
getJasmineRequireObj().MapContaining = function(j$) {
function MapContaining(sample) {
if (!j$.isMap(sample)) {
throw new Error(
'You must provide a map to `mapContaining`, not ' + j$.pp(sample)
);
}
this.sample = sample;
}
MapContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isMap(other)) return false;
var hasAllMatches = true;
j$.util.forEachBreakable(this.sample, function(breakLoop, value, key) {
// for each key/value pair in `sample`
// there should be at least one pair in `other` whose key and value both match
var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oValue, oKey) {
if (
matchersUtil.equals(oKey, key) &&
matchersUtil.equals(oValue, value)
) {
hasMatch = true;
oBreakLoop();
}
});
if (!hasMatch) {
hasAllMatches = false;
breakLoop();
}
});
return hasAllMatches;
};
MapContaining.prototype.jasmineToString = function(pp) {
return '<jasmine.mapContaining(' + pp(this.sample) + ')>';
};
return MapContaining;
};

View File

@@ -1,8 +1,7 @@
getJasmineRequireObj().NotEmpty = function (j$) {
getJasmineRequireObj().NotEmpty = function(j$) {
function NotEmpty() {}
NotEmpty.prototype.asymmetricMatch = function (other) {
NotEmpty.prototype.asymmetricMatch = function(other) {
if (j$.isString_(other) || j$.isArray_(other) || j$.isTypedArray_(other)) {
return other.length !== 0;
}
@@ -18,7 +17,7 @@ getJasmineRequireObj().NotEmpty = function (j$) {
return false;
};
NotEmpty.prototype.jasmineToString = function () {
NotEmpty.prototype.jasmineToString = function() {
return '<jasmine.notEmpty>';
};

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().ObjectContaining = function(j$) {
function ObjectContaining(sample) {
this.sample = sample;
}
@@ -17,7 +16,7 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
}
function hasProperty(obj, property) {
if (!obj) {
if (!obj || typeof obj !== 'object') {
return false;
}
@@ -28,12 +27,23 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
return hasProperty(getPrototype(obj), property);
}
ObjectContaining.prototype.asymmetricMatch = function(other, customTesters) {
if (typeof(this.sample) !== 'object') { throw new Error('You must provide an object to objectContaining, not \''+this.sample+'\'.'); }
ObjectContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (typeof this.sample !== 'object') {
throw new Error(
"You must provide an object to objectContaining, not '" +
this.sample +
"'."
);
}
if (typeof other !== 'object') {
return false;
}
for (var property in this.sample) {
if (!hasProperty(other, property) ||
!j$.matchersUtil.equals(this.sample[property], other[property], customTesters)) {
if (
!hasProperty(other, property) ||
!matchersUtil.equals(this.sample[property], other[property])
) {
return false;
}
}
@@ -41,8 +51,29 @@ getJasmineRequireObj().ObjectContaining = function(j$) {
return true;
};
ObjectContaining.prototype.jasmineToString = function() {
return '<jasmine.objectContaining(' + j$.pp(this.sample) + ')>';
ObjectContaining.prototype.valuesForDiff_ = function(other, pp) {
if (!j$.isObject_(other)) {
return {
self: this.jasmineToString(pp),
other: other
};
}
var filteredOther = {};
Object.keys(this.sample).forEach(function(k) {
// eq short-circuits comparison of objects that have different key sets,
// so include all keys even if undefined.
filteredOther[k] = other[k];
});
return {
self: this.sample,
other: filteredOther
};
};
ObjectContaining.prototype.jasmineToString = function(pp) {
return '<jasmine.objectContaining(' + pp(this.sample) + ')>';
};
return ObjectContaining;

View File

@@ -0,0 +1,41 @@
getJasmineRequireObj().SetContaining = function(j$) {
function SetContaining(sample) {
if (!j$.isSet(sample)) {
throw new Error(
'You must provide a set to `setContaining`, not ' + j$.pp(sample)
);
}
this.sample = sample;
}
SetContaining.prototype.asymmetricMatch = function(other, matchersUtil) {
if (!j$.isSet(other)) return false;
var hasAllMatches = true;
j$.util.forEachBreakable(this.sample, function(breakLoop, item) {
// for each item in `sample` there should be at least one matching item in `other`
// (not using `matchersUtil.contains` because it compares set members by reference,
// not by deep value equality)
var hasMatch = false;
j$.util.forEachBreakable(other, function(oBreakLoop, oItem) {
if (matchersUtil.equals(oItem, item)) {
hasMatch = true;
oBreakLoop();
}
});
if (!hasMatch) {
hasAllMatches = false;
breakLoop();
}
});
return hasAllMatches;
};
SetContaining.prototype.jasmineToString = function(pp) {
return '<jasmine.setContaining(' + pp(this.sample) + ')>';
};
return SetContaining;
};

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().StringMatching = function(j$) {
function StringMatching(expected) {
if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
throw new Error('Expected is not a String or a RegExp');

View File

@@ -1,5 +1,4 @@
getJasmineRequireObj().Truthy = function(j$) {
function Truthy() {}
Truthy.prototype.asymmetricMatch = function(other) {

View File

@@ -7,6 +7,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Maximum object depth the pretty printer will print to.
* Set this to a lower value to speed up pretty printing if you have large objects.
* @name jasmine.MAX_PRETTY_PRINT_DEPTH
* @since 1.3.0
*/
j$.MAX_PRETTY_PRINT_DEPTH = 8;
/**
@@ -14,17 +15,20 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* This will also limit the number of keys and values displayed for an object.
* Elements past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_ARRAY_LENGTH
* @since 2.7.0
*/
j$.MAX_PRETTY_PRINT_ARRAY_LENGTH = 50;
/**
* Maximum number of characters to display when pretty printing objects.
* Characters past this number will be ellipised.
* @name jasmine.MAX_PRETTY_PRINT_CHARS
* @since 2.9.0
*/
j$.MAX_PRETTY_PRINT_CHARS = 1000;
/**
* Default number of milliseconds Jasmine will wait for an asynchronous spec to complete.
* @name jasmine.DEFAULT_TIMEOUT_INTERVAL
* @since 1.3.0
*/
j$.DEFAULT_TIMEOUT_INTERVAL = 5000;
@@ -36,11 +40,12 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get the currently booted Jasmine Environment.
*
* @name jasmine.getEnv
* @since 1.3.0
* @function
* @return {Env}
*/
j$.getEnv = function(options) {
var env = j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options);
var env = (j$.currentEnv_ = j$.currentEnv_ || new j$.Env(options));
//jasmine. singletons in here (setTimeout blah blah).
return env;
};
@@ -50,7 +55,9 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
j$.isObject_ = function(value) {
return !j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value);
return (
!j$.util.isUndefined(value) && value !== null && j$.isA_('Object', value)
);
};
j$.isString_ = function(value) {
@@ -69,8 +76,13 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return j$.isA_('AsyncFunction', value);
};
j$.isGeneratorFunction_ = function(value) {
return j$.isA_('GeneratorFunction', value);
};
j$.isTypedArray_ = function(value) {
return j$.isA_('Float32Array', value) ||
return (
j$.isA_('Float32Array', value) ||
j$.isA_('Float64Array', value) ||
j$.isA_('Int16Array', value) ||
j$.isA_('Int32Array', value) ||
@@ -78,7 +90,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
j$.isA_('Uint16Array', value) ||
j$.isA_('Uint32Array', value) ||
j$.isA_('Uint8Array', value) ||
j$.isA_('Uint8ClampedArray', value);
j$.isA_('Uint8ClampedArray', value)
);
};
j$.isA_ = function(typeName, value) {
@@ -102,15 +115,19 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return false;
};
j$.isAsymmetricEqualityTester_ = function(obj) {
return obj ? j$.isA_('Function', obj.asymmetricMatch) : false;
};
j$.getType_ = function(value) {
return Object.prototype.toString.apply(value);
};
j$.isDomNode = function(obj) {
// Node is a function, because constructors
return typeof jasmineGlobal.Node !== 'undefined' ?
obj instanceof jasmineGlobal.Node :
obj !== null &&
return typeof jasmineGlobal.Node !== 'undefined'
? obj instanceof jasmineGlobal.Node
: obj !== null &&
typeof obj === 'object' &&
typeof obj.nodeType === 'number' &&
typeof obj.nodeName === 'string';
@@ -118,15 +135,56 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
};
j$.isMap = function(obj) {
return typeof jasmineGlobal.Map !== 'undefined' && obj.constructor === jasmineGlobal.Map;
return (
obj !== null &&
typeof obj !== 'undefined' &&
typeof jasmineGlobal.Map !== 'undefined' &&
obj.constructor === jasmineGlobal.Map
);
};
j$.isSet = function(obj) {
return typeof jasmineGlobal.Set !== 'undefined' && obj.constructor === jasmineGlobal.Set;
return (
obj !== null &&
typeof obj !== 'undefined' &&
typeof jasmineGlobal.Set !== 'undefined' &&
obj.constructor === jasmineGlobal.Set
);
};
j$.isWeakMap = function(obj) {
return (
obj !== null &&
typeof obj !== 'undefined' &&
typeof jasmineGlobal.WeakMap !== 'undefined' &&
obj.constructor === jasmineGlobal.WeakMap
);
};
j$.isURL = function(obj) {
return (
obj !== null &&
typeof obj !== 'undefined' &&
typeof jasmineGlobal.URL !== 'undefined' &&
obj.constructor === jasmineGlobal.URL
);
};
j$.isDataView = function(obj) {
return (
obj !== null &&
typeof obj !== 'undefined' &&
typeof jasmineGlobal.DataView !== 'undefined' &&
obj.constructor === jasmineGlobal.DataView
);
};
j$.isPromise = function(obj) {
return typeof jasmineGlobal.Promise !== 'undefined' && !!obj && obj.constructor === jasmineGlobal.Promise;
return (
typeof jasmineGlobal.Promise !== 'undefined' &&
!!obj &&
obj.constructor === jasmineGlobal.Promise
);
};
j$.isPromiseLike = function(obj) {
@@ -138,7 +196,8 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return func.name;
}
var matches = func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
var matches =
func.toString().match(/^\s*function\s*(\w+)\s*\(/) ||
func.toString().match(/^\s*\[object\s*(\w+)Constructor\]/);
return matches ? matches[1] : '<anonymous>';
@@ -148,6 +207,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is an instance of the specified class/constructor.
* @name jasmine.any
* @since 1.3.0
* @function
* @param {Constructor} clazz - The constructor to check against.
*/
@@ -159,6 +219,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is not `null` and not `undefined`.
* @name jasmine.anything
* @since 2.2.0
* @function
*/
j$.anything = function() {
@@ -169,38 +230,51 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is `true` or anything truthy.
* @name jasmine.truthy
* @since 3.1.0
* @function
*/
j$.truthy = function() {return new j$.Truthy();};
j$.truthy = function() {
return new j$.Truthy();
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is `null`, `undefined`, `0`, `false` or anything falsey.
* @name jasmine.falsy
* @since 3.1.0
* @function
*/
j$.falsy = function() {return new j$.Falsy();};
j$.falsy = function() {
return new j$.Falsy();
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is empty.
* @name jasmine.empty
* @since 3.1.0
* @function
*/
j$.empty = function() {return new j$.Empty();};
j$.empty = function() {
return new j$.Empty();
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared is not empty.
* @name jasmine.notEmpty
* @since 3.1.0
* @function
*/
j$.notEmpty = function() {return new j$.NotEmpty();};
j$.notEmpty = function() {
return new j$.NotEmpty();
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value being compared contains at least the keys and values.
* @name jasmine.objectContaining
* @since 1.3.0
* @function
* @param {Object} sample - The subset of properties that _must_ be in the actual.
*/
@@ -212,6 +286,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is a `String` that matches the `RegExp` or `String`.
* @name jasmine.stringMatching
* @since 2.2.0
* @function
* @param {RegExp|String} expected
*/
@@ -223,6 +298,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains at least the elements in the sample.
* @name jasmine.arrayContaining
* @since 2.2.0
* @function
* @param {Array} sample
*/
@@ -234,6 +310,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if the actual value is an `Array` that contains all of the elements in the sample in any order.
* @name jasmine.arrayWithExactContents
* @since 2.8.0
* @function
* @param {Array} sample
*/
@@ -241,11 +318,47 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return new j$.ArrayWithExactContents(sample);
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if every key/value pair in the sample passes the deep equality comparison
* with at least one key/value pair in the actual value being compared
* @name jasmine.mapContaining
* @since 3.5.0
* @function
* @param {Map} sample - The subset of items that _must_ be in the actual.
*/
j$.mapContaining = function(sample) {
return new j$.MapContaining(sample);
};
/**
* Get a matcher, usable in any {@link matchers|matcher} that uses Jasmine's equality (e.g. {@link matchers#toEqual|toEqual}, {@link matchers#toContain|toContain}, or {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}),
* that will succeed if every item in the sample passes the deep equality comparison
* with at least one item in the actual value being compared
* @name jasmine.setContaining
* @since 3.5.0
* @function
* @param {Set} sample - The subset of items that _must_ be in the actual.
*/
j$.setContaining = function(sample) {
return new j$.SetContaining(sample);
};
/**
* Determines whether the provided function is a Jasmine spy.
* @name jasmine.isSpy
* @since 2.0.0
* @function
* @param {Function} putativeSpy - The function to check.
* @return {Boolean}
*/
j$.isSpy = function(putativeSpy) {
if (!putativeSpy) {
return false;
}
return putativeSpy.and instanceof j$.SpyStrategy &&
putativeSpy.calls instanceof j$.CallTracker;
return (
putativeSpy.and instanceof j$.SpyStrategy &&
putativeSpy.calls instanceof j$.CallTracker
);
};
};

View File

@@ -7,4 +7,4 @@ getJasmineRequireObj().errors = function() {
return {
ExpectationFailed: ExpectationFailed
};
};
};

View File

@@ -1,19 +1,69 @@
getJasmineRequireObj().DiffBuilder = function(j$) {
return function DiffBuilder() {
var path = new j$.ObjectPath(),
mismatches = [];
return function DiffBuilder(config) {
var prettyPrinter = (config || {}).prettyPrinter || j$.makePrettyPrinter(),
mismatches = new j$.MismatchTree(),
path = new j$.ObjectPath(),
actualRoot = undefined,
expectedRoot = undefined;
return {
record: function (actual, expected, formatter) {
formatter = formatter || defaultFormatter;
mismatches.push(formatter(actual, expected, path));
setRoots: function(actual, expected) {
actualRoot = actual;
expectedRoot = expected;
},
getMessage: function () {
return mismatches.join('\n');
recordMismatch: function(formatter) {
mismatches.add(path, formatter);
},
withPath: function (pathComponent, block) {
getMessage: function() {
var messages = [];
mismatches.traverse(function(path, isLeaf, formatter) {
var actualCustom,
expectedCustom,
useCustom,
derefResult = dereferencePath(
path,
actualRoot,
expectedRoot,
prettyPrinter
),
actual = derefResult.actual,
expected = derefResult.expected;
if (formatter) {
messages.push(formatter(actual, expected, path, prettyPrinter));
return true;
}
actualCustom = prettyPrinter.customFormat_(actual);
expectedCustom = prettyPrinter.customFormat_(expected);
useCustom = !(
j$.util.isUndefined(actualCustom) &&
j$.util.isUndefined(expectedCustom)
);
if (useCustom) {
messages.push(
wrapPrettyPrinted(actualCustom, expectedCustom, path)
);
return false; // don't recurse further
}
if (isLeaf) {
messages.push(
defaultFormatter(actual, expected, path, prettyPrinter)
);
}
return true;
});
return messages.join('\n');
},
withPath: function(pathComponent, block) {
var oldPath = path;
path = path.add(pathComponent);
block();
@@ -21,13 +71,48 @@ getJasmineRequireObj().DiffBuilder = function(j$) {
}
};
function defaultFormatter (actual, expected, path) {
return 'Expected ' +
path + (path.depth() ? ' = ' : '') +
j$.pp(actual) +
function defaultFormatter(actual, expected, path, prettyPrinter) {
return wrapPrettyPrinted(
prettyPrinter(actual),
prettyPrinter(expected),
path
);
}
function wrapPrettyPrinted(actual, expected, path) {
return (
'Expected ' +
path +
(path.depth() ? ' = ' : '') +
actual +
' to equal ' +
j$.pp(expected) +
'.';
expected +
'.'
);
}
};
function dereferencePath(objectPath, actual, expected, pp) {
function handleAsymmetricExpected() {
if (
j$.isAsymmetricEqualityTester_(expected) &&
j$.isFunction_(expected.valuesForDiff_)
) {
var asymmetricResult = expected.valuesForDiff_(actual, pp);
expected = asymmetricResult.self;
actual = asymmetricResult.other;
}
}
var i;
handleAsymmetricExpected();
for (i = 0; i < objectPath.components.length; i++) {
actual = actual[objectPath.components[i]];
expected = expected[objectPath.components[i]];
handleAsymmetricExpected();
}
return { actual: actual, expected: expected };
}
};

View File

@@ -0,0 +1,61 @@
getJasmineRequireObj().MismatchTree = function(j$) {
/*
To be able to apply custom object formatters at all possible levels of an
object graph, DiffBuilder needs to be able to know not just where the
mismatch occurred but also all ancestors of the mismatched value in both
the expected and actual object graphs. MismatchTree maintains that context
and provides it via the traverse method.
*/
function MismatchTree(path) {
this.path = path || new j$.ObjectPath([]);
this.formatter = undefined;
this.children = [];
this.isMismatch = false;
}
MismatchTree.prototype.add = function(path, formatter) {
var key, child;
if (path.depth() === 0) {
this.formatter = formatter;
this.isMismatch = true;
} else {
key = path.components[0];
path = path.shift();
child = this.child(key);
if (!child) {
child = new MismatchTree(this.path.add(key));
this.children.push(child);
}
child.add(path, formatter);
}
};
MismatchTree.prototype.traverse = function(visit) {
var i,
hasChildren = this.children.length > 0;
if (this.isMismatch || hasChildren) {
if (visit(this.path, !hasChildren, this.formatter)) {
for (i = 0; i < this.children.length; i++) {
this.children[i].traverse(visit);
}
}
}
};
MismatchTree.prototype.child = function(key) {
var i, pathEls;
for (i = 0; i < this.children.length; i++) {
pathEls = this.children[i].path.components;
if (pathEls[pathEls.length - 1] === key) {
return this.children[i];
}
}
};
return MismatchTree;
};

View File

@@ -4,7 +4,8 @@ getJasmineRequireObj().NullDiffBuilder = function(j$) {
withPath: function(_, block) {
block();
},
record: function() {}
setRoots: function() {},
recordMismatch: function() {}
};
};
};

View File

@@ -15,6 +15,10 @@ getJasmineRequireObj().ObjectPath = function(j$) {
return new ObjectPath(this.components.concat([component]));
};
ObjectPath.prototype.shift = function() {
return new ObjectPath(this.components.slice(1));
};
ObjectPath.prototype.depth = function() {
return this.components.length;
};
@@ -28,7 +32,7 @@ getJasmineRequireObj().ObjectPath = function(j$) {
return '.' + prop;
}
return '[\'' + prop + '\']';
return "['" + prop + "']";
}
function map(array, fn) {

View File

@@ -0,0 +1,30 @@
/* eslint-disable compat/compat */
getJasmineRequireObj().toBePending = function(j$) {
/**
* Expect a promise to be pending, i.e. the promise is neither resolved nor rejected.
* @function
* @async
* @name async-matchers#toBePending
* @since 3.6
* @example
* await expectAsync(aPromise).toBePending();
*/
return function toBePending() {
return {
compare: function(actual) {
if (!j$.isPromiseLike(actual)) {
throw new Error('Expected toBePending to be called on a promise.');
}
var want = {};
return Promise.race([actual, Promise.resolve(want)]).then(
function(got) {
return { pass: want === got };
},
function() {
return { pass: false };
}
);
}
};
};
};

View File

@@ -4,17 +4,25 @@ getJasmineRequireObj().toBeRejected = function(j$) {
* @function
* @async
* @name async-matchers#toBeRejected
* @since 3.1.0
* @example
* await expectAsync(aPromise).toBeRejected();
* @example
* return expectAsync(aPromise).toBeRejected();
*/
return function toBeResolved(util) {
return function toBeRejected() {
return {
compare: function(actual) {
if (!j$.isPromiseLike(actual)) {
throw new Error('Expected toBeRejected to be called on a promise.');
}
return actual.then(
function() { return {pass: false}; },
function() { return {pass: true}; }
function() {
return { pass: false };
},
function() {
return { pass: true };
}
);
}
};

View File

@@ -4,41 +4,55 @@ getJasmineRequireObj().toBeRejectedWith = function(j$) {
* @function
* @async
* @name async-matchers#toBeRejectedWith
* @since 3.3.0
* @param {Object} expected - Value that the promise is expected to be rejected with
* @example
* await expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
* @example
* return expectAsync(aPromise).toBeRejectedWith({prop: 'value'});
*/
return function toBeRejectedWith(util, customEqualityTesters) {
return function toBeRejectedWith(matchersUtil) {
return {
compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) {
throw new Error(
'Expected toBeRejectedWith to be called on a promise.'
);
}
function prefix(passed) {
return 'Expected a promise ' +
return (
'Expected a promise ' +
(passed ? 'not ' : '') +
'to be rejected with ' + j$.pp(expectedValue);
'to be rejected with ' +
matchersUtil.pp(expectedValue)
);
}
return actualPromise.then(
function() {
return {
pass: false,
message: prefix(false) + ' but it was resolved.'
};
},
function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
return {
pass: false,
message: prefix(false) + ' but it was rejected with ' + j$.pp(actualValue) + '.'
message: prefix(false) + ' but it was resolved.'
};
},
function(actualValue) {
if (matchersUtil.equals(actualValue, expectedValue)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
return {
pass: false,
message:
prefix(false) +
' but it was rejected with ' +
matchersUtil.pp(actualValue) +
'.'
};
}
}
}
);
}
};

View File

@@ -0,0 +1,122 @@
getJasmineRequireObj().toBeRejectedWithError = function(j$) {
/**
* Expect a promise to be rejected with a value matched to the expected
* @function
* @async
* @name async-matchers#toBeRejectedWithError
* @since 3.5.0
* @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
* @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
* @example
* await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, 'Error message');
* await expectAsync(aPromise).toBeRejectedWithError(MyCustomError, /Error message/);
* await expectAsync(aPromise).toBeRejectedWithError(MyCustomError);
* await expectAsync(aPromise).toBeRejectedWithError('Error message');
* return expectAsync(aPromise).toBeRejectedWithError(/Error message/);
*/
return function toBeRejectedWithError(matchersUtil) {
return {
compare: function(actualPromise, arg1, arg2) {
if (!j$.isPromiseLike(actualPromise)) {
throw new Error(
'Expected toBeRejectedWithError to be called on a promise.'
);
}
var expected = getExpectedFromArgs(arg1, arg2, matchersUtil);
return actualPromise.then(
function() {
return {
pass: false,
message: 'Expected a promise to be rejected but it was resolved.'
};
},
function(actualValue) {
return matchError(actualValue, expected, matchersUtil);
}
);
}
};
};
function matchError(actual, expected, matchersUtil) {
if (!j$.isError_(actual)) {
return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
}
if (!(actual instanceof expected.error)) {
return fail(
expected,
'rejected with type ' + j$.fnNameFor(actual.constructor)
);
}
var actualMessage = actual.message;
if (
actualMessage === expected.message ||
typeof expected.message === 'undefined'
) {
return pass(expected);
}
if (
expected.message instanceof RegExp &&
expected.message.test(actualMessage)
) {
return pass(expected);
}
return fail(expected, 'rejected with ' + matchersUtil.pp(actual));
}
function pass(expected) {
return {
pass: true,
message:
'Expected a promise not to be rejected with ' +
expected.printValue +
', but it was.'
};
}
function fail(expected, message) {
return {
pass: false,
message:
'Expected a promise to be rejected with ' +
expected.printValue +
' but it was ' +
message +
'.'
};
}
function getExpectedFromArgs(arg1, arg2, matchersUtil) {
var error, message;
if (isErrorConstructor(arg1)) {
error = arg1;
message = arg2;
} else {
error = Error;
message = arg1;
}
return {
error: error,
message: message,
printValue:
j$.fnNameFor(error) +
(typeof message === 'undefined' ? '' : ': ' + matchersUtil.pp(message))
};
}
function isErrorConstructor(value) {
return (
typeof value === 'function' &&
(value === Error || j$.isError_(value.prototype))
);
}
};

View File

@@ -4,17 +4,26 @@ getJasmineRequireObj().toBeResolved = function(j$) {
* @function
* @async
* @name async-matchers#toBeResolved
* @since 3.1.0
* @example
* await expectAsync(aPromise).toBeResolved();
* @example
* return expectAsync(aPromise).toBeResolved();
*/
return function toBeResolved(util) {
return function toBeResolved() {
return {
compare: function(actual) {
if (!j$.isPromiseLike(actual)) {
throw new Error('Expected toBeResolved to be called on a promise.');
}
return actual.then(
function() { return {pass: true}; },
function() { return {pass: false}; }
function() {
return { pass: true };
},
function() {
return { pass: false };
}
);
}
};

View File

@@ -4,41 +4,53 @@ getJasmineRequireObj().toBeResolvedTo = function(j$) {
* @function
* @async
* @name async-matchers#toBeResolvedTo
* @since 3.1.0
* @param {Object} expected - Value that the promise is expected to resolve to
* @example
* await expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
* @example
* return expectAsync(aPromise).toBeResolvedTo({prop: 'value'});
*/
return function toBeResolvedTo(util, customEqualityTesters) {
return function toBeResolvedTo(matchersUtil) {
return {
compare: function(actualPromise, expectedValue) {
if (!j$.isPromiseLike(actualPromise)) {
throw new Error('Expected toBeResolvedTo to be called on a promise.');
}
function prefix(passed) {
return 'Expected a promise ' +
return (
'Expected a promise ' +
(passed ? 'not ' : '') +
'to be resolved to ' + j$.pp(expectedValue);
'to be resolved to ' +
matchersUtil.pp(expectedValue)
);
}
return actualPromise.then(
function(actualValue) {
if (util.equals(actualValue, expectedValue, customEqualityTesters)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
if (matchersUtil.equals(actualValue, expectedValue)) {
return {
pass: true,
message: prefix(true) + '.'
};
} else {
return {
pass: false,
message:
prefix(false) +
' but it was resolved to ' +
matchersUtil.pp(actualValue) +
'.'
};
}
},
function() {
return {
pass: false,
message: prefix(false) + ' but it was resolved to ' + j$.pp(actualValue) + '.'
message: prefix(false) + ' but it was rejected.'
};
}
},
function() {
return {
pass: false,
message: prefix(false) + ' but it was rejected.'
};
}
);
}
};

View File

@@ -1,99 +1,201 @@
getJasmineRequireObj().matchersUtil = function(j$) {
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
getJasmineRequireObj().MatchersUtil = function(j$) {
// TODO: convert all uses of j$.pp to use the injected pp
return {
equals: equals,
/**
* _Note:_ Do not construct this directly. Jasmine will construct one and
* pass it to matchers and asymmetric equality testers.
* @name MatchersUtil
* @classdesc Utilities for use in implementing matchers
* @constructor
*/
function MatchersUtil(options) {
options = options || {};
this.customTesters_ = options.customTesters || [];
/**
* Formats a value for use in matcher failure messages and similar contexts,
* taking into account the current set of custom value formatters.
* @function
* @name MatchersUtil#pp
* @since 3.6.0
* @param {*} value The value to pretty-print
* @return {string} The pretty-printed value
*/
this.pp = options.pp || function() {};
}
contains: function(haystack, needle, customTesters) {
customTesters = customTesters || [];
/**
* Determines whether `haystack` contains `needle`, using the same comparison
* logic as {@link MatchersUtil#equals}.
* @function
* @name MatchersUtil#contains
* @since 2.0.0
* @param {*} haystack The collection to search
* @param {*} needle The value to search for
* @param [customTesters] An array of custom equality testers
* @returns {boolean} True if `needle` was found in `haystack`
*/
MatchersUtil.prototype.contains = function(haystack, needle, customTesters) {
if (j$.isSet(haystack)) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Set]')) {
return haystack.has(needle);
}
if ((Object.prototype.toString.apply(haystack) === '[object Array]') ||
(!!haystack && !haystack.indexOf))
{
for (var i = 0; i < haystack.length; i++) {
if (equals(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]);
if (
Object.prototype.toString.apply(haystack) === '[object Array]' ||
(!!haystack && !haystack.indexOf)
) {
for (var i = 0; i < haystack.length; i++) {
if (this.equals(haystack[i], needle, customTesters)) {
return true;
}
}
return false;
}
return message + '.';
return !!haystack && haystack.indexOf(needle) >= 0;
};
MatchersUtil.prototype.buildFailureMessage = function() {
var self = this;
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 ' +
self.pp(actual) +
(isNot ? ' not ' : ' ') +
englishyPredicate;
if (expected.length > 0) {
for (var i = 0; i < expected.length; i++) {
if (i > 0) {
message += ',';
}
message += ' ' + self.pp(expected[i]);
}
}
return message + '.';
};
MatchersUtil.prototype.asymmetricDiff_ = function(
a,
b,
aStack,
bStack,
customTesters,
diffBuilder
) {
if (j$.isFunction_(b.valuesForDiff_)) {
var values = b.valuesForDiff_(a, this.pp);
this.eq_(
values.other,
values.self,
aStack,
bStack,
customTesters,
diffBuilder
);
} else {
diffBuilder.recordMismatch();
}
};
function isAsymmetric(obj) {
return obj && j$.isA_('Function', obj.asymmetricMatch);
}
MatchersUtil.prototype.asymmetricMatch_ = function(
a,
b,
aStack,
bStack,
customTesters,
diffBuilder
) {
var asymmetricA = j$.isAsymmetricEqualityTester_(a),
asymmetricB = j$.isAsymmetricEqualityTester_(b),
shim,
result;
function asymmetricMatch(a, b, customTesters, diffBuilder) {
var asymmetricA = isAsymmetric(a),
asymmetricB = isAsymmetric(b),
result;
if (asymmetricA && asymmetricB) {
if (asymmetricA === asymmetricB) {
return undefined;
}
shim = j$.asymmetricEqualityTesterArgCompatShim(this, customTesters);
if (asymmetricA) {
result = a.asymmetricMatch(b, customTesters);
result = a.asymmetricMatch(b, shim);
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
}
if (asymmetricB) {
result = b.asymmetricMatch(a, customTesters);
result = b.asymmetricMatch(a, shim);
if (!result) {
diffBuilder.record(a, b);
this.asymmetricDiff_(a, b, aStack, bStack, customTesters, diffBuilder);
}
return result;
}
}
};
function equals(a, b, customTesters, diffBuilder) {
customTesters = customTesters || [];
/**
* Determines whether two values are deeply equal to each other.
* @function
* @name MatchersUtil#equals
* @since 2.0.0
* @param {*} a The first value to compare
* @param {*} b The second value to compare
* @param [customTesters] An array of custom equality testers
* @returns {boolean} True if the values are equal
*/
MatchersUtil.prototype.equals = function(
a,
b,
customTestersOrDiffBuilder,
diffBuilderOrNothing
) {
var customTesters, diffBuilder;
if (isDiffBuilder(customTestersOrDiffBuilder)) {
diffBuilder = customTestersOrDiffBuilder;
} else {
customTesters = customTestersOrDiffBuilder;
diffBuilder = diffBuilderOrNothing;
}
customTesters = customTesters || this.customTesters_;
diffBuilder = diffBuilder || j$.NullDiffBuilder();
diffBuilder.setRoots(a, b);
return eq(a, b, [], [], customTesters, diffBuilder);
}
return this.eq_(a, b, [], [], customTesters, diffBuilder);
};
// Equality function lovingly adapted from isEqual in
// [Underscore](http://underscorejs.org)
function eq(a, b, aStack, bStack, customTesters, diffBuilder) {
var result = true, i;
MatchersUtil.prototype.eq_ = function(
a,
b,
aStack,
bStack,
customTesters,
diffBuilder
) {
var result = true,
self = this,
i;
var asymmetricResult = asymmetricMatch(a, b, customTesters, diffBuilder);
var asymmetricResult = this.asymmetricMatch_(
a,
b,
aStack,
bStack,
customTesters,
diffBuilder
);
if (!j$.util.isUndefined(asymmetricResult)) {
return asymmetricResult;
}
@@ -102,7 +204,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
var customTesterResult = customTesters[i](a, b);
if (!j$.util.isUndefined(customTesterResult)) {
if (!customTesterResult) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return customTesterResult;
}
@@ -111,18 +213,17 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (a instanceof Error && b instanceof Error) {
result = a.message == b.message;
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
}
// 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) {
result = a !== 0 || 1 / a == 1 / b;
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
}
@@ -130,13 +231,13 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (a === null || b === null) {
result = a === b;
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
}
var className = Object.prototype.toString.call(a);
if (className != Object.prototype.toString.call(b)) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
switch (className) {
@@ -146,15 +247,16 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// equivalent to `new String("5")`.
result = a == String(b);
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
case '[object Number]':
// `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
// other numeric values.
result = a != +a ? b != +b : (a === 0 ? 1 / a == 1 / b : a == +b);
result =
a != +a ? b != +b : a === 0 && b === 0 ? 1 / a == 1 / b : a == +b;
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
case '[object Date]':
@@ -164,7 +266,7 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// of `NaN` are not equivalent.
result = +a == +b;
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
// RegExps are compared by their source patterns and flags.
@@ -199,13 +301,15 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}
return result;
case '[object RegExp]':
return a.source == b.source &&
return (
a.source == b.source &&
a.global == b.global &&
a.multiline == b.multiline &&
a.ignoreCase == b.ignoreCase;
a.ignoreCase == b.ignoreCase
);
}
if (typeof a != 'object' || typeof b != 'object') {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
@@ -215,12 +319,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// At first try to use DOM3 method isEqualNode
result = a.isEqualNode(b);
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
}
return result;
}
if (aIsDomNode || bIsDomNode) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
@@ -236,7 +340,9 @@ getJasmineRequireObj().matchersUtil = function(j$) {
while (length--) {
// Linear search. Performance is inversely proportional to the number of
// unique nested structures.
if (aStack[length] == a) { return bStack[length] == b; }
if (aStack[length] == a) {
return bStack[length] == b;
}
}
// Add the first object to the stack of traversed objects.
aStack.push(a);
@@ -250,19 +356,28 @@ getJasmineRequireObj().matchersUtil = function(j$) {
diffBuilder.withPath('length', function() {
if (aLength !== bLength) {
diffBuilder.record(aLength, bLength);
diffBuilder.recordMismatch();
result = false;
}
});
for (i = 0; i < aLength || i < bLength; i++) {
var formatter = false;
diffBuilder.withPath(i, function() {
if (i >= bLength) {
diffBuilder.record(a[i], void 0, actualArrayIsLongerFormatter);
diffBuilder.recordMismatch(
actualArrayIsLongerFormatter.bind(null, self.pp)
);
result = false;
} else {
result = eq(i < aLength ? a[i] : void 0, i < bLength ? b[i] : void 0, aStack, bStack, customTesters, diffBuilder) && result;
result =
self.eq_(
i < aLength ? a[i] : void 0,
i < bLength ? b[i] : void 0,
aStack,
bStack,
customTesters,
diffBuilder
) && result;
}
});
}
@@ -271,17 +386,17 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}
} else if (j$.isMap(a) && j$.isMap(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
var keysA = [];
var keysB = [];
a.forEach( function( valueA, keyA ) {
keysA.push( keyA );
a.forEach(function(valueA, keyA) {
keysA.push(keyA);
});
b.forEach( function( valueB, keyB ) {
keysB.push( keyB );
b.forEach(function(valueB, keyB) {
keysB.push(keyB);
});
// For both sets of keys, check they map to equal values in both maps.
@@ -302,33 +417,50 @@ getJasmineRequireObj().matchersUtil = function(j$) {
// Only use the cmpKey when one of the keys is asymmetric and the corresponding key matches,
// otherwise explicitly look up the mapKey in the other Map since we want keys with unique
// obj identity (that are otherwise equal) to not match.
if (isAsymmetric(mapKey) || isAsymmetric(cmpKey) &&
eq(mapKey, cmpKey, aStack, bStack, customTesters, j$.NullDiffBuilder())) {
if (
j$.isAsymmetricEqualityTester_(mapKey) ||
(j$.isAsymmetricEqualityTester_(cmpKey) &&
this.eq_(
mapKey,
cmpKey,
aStack,
bStack,
customTesters,
j$.NullDiffBuilder()
))
) {
mapValueB = b.get(cmpKey);
} else {
mapValueB = b.get(mapKey);
}
result = eq(mapValueA, mapValueB, aStack, bStack, customTesters, j$.NullDiffBuilder());
result = this.eq_(
mapValueA,
mapValueB,
aStack,
bStack,
customTesters,
j$.NullDiffBuilder()
);
}
}
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
} else if (j$.isSet(a) && j$.isSet(b)) {
if (a.size != b.size) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
var valuesA = [];
a.forEach( function( valueA ) {
valuesA.push( valueA );
a.forEach(function(valueA) {
valuesA.push(valueA);
});
var valuesB = [];
b.forEach( function( valueB ) {
valuesB.push( valueB );
b.forEach(function(valueB) {
valuesB.push(valueB);
});
// For both sets, check they are all contained in the other set
@@ -352,7 +484,14 @@ getJasmineRequireObj().matchersUtil = function(j$) {
otherValue = otherValues[l];
prevStackSize = baseStack.length;
// compare by value equality
found = eq(baseValue, otherValue, baseStack, otherStack, customTesters, j$.NullDiffBuilder());
found = this.eq_(
baseValue,
otherValue,
baseStack,
otherStack,
customTesters,
j$.NullDiffBuilder()
);
if (!found && prevStackSize !== baseStack.length) {
baseStack.splice(prevStackSize);
otherStack.splice(prevStackSize);
@@ -363,31 +502,43 @@ getJasmineRequireObj().matchersUtil = function(j$) {
}
if (!result) {
diffBuilder.record(a, b);
diffBuilder.recordMismatch();
return false;
}
} else if (j$.isURL(a) && j$.isURL(b)) {
// URLs have no enumrable properties, so the default object comparison
// would consider any two URLs to be equal.
return a.toString() === b.toString();
} else {
// Objects with different constructors are not equivalent, but `Object`s
// or `Array`s from different frames are.
var aCtor = a.constructor, bCtor = b.constructor;
if (aCtor !== bCtor &&
isFunction(aCtor) && isFunction(bCtor) &&
a instanceof aCtor && b instanceof bCtor &&
!(aCtor instanceof aCtor && bCtor instanceof bCtor)) {
diffBuilder.record(a, b, constructorsAreDifferentFormatter);
var aCtor = a.constructor,
bCtor = b.constructor;
if (
aCtor !== bCtor &&
isFunction(aCtor) &&
isFunction(bCtor) &&
a instanceof aCtor &&
b instanceof bCtor &&
!(aCtor instanceof aCtor && bCtor instanceof bCtor)
) {
diffBuilder.recordMismatch(
constructorsAreDifferentFormatter.bind(null, this.pp)
);
return false;
}
}
// Deep compare objects.
var aKeys = keys(a, className == '[object Array]'), key;
var aKeys = keys(a, className == '[object Array]'),
key;
size = aKeys.length;
// Ensure that both objects contain the same number of properties before comparing deep equality.
if (keys(b, className == '[object Array]').length !== size) {
diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
diffBuilder.recordMismatch(
objectKeysAreDifferentFormatter.bind(null, this.pp)
);
return false;
}
@@ -395,13 +546,17 @@ getJasmineRequireObj().matchersUtil = function(j$) {
key = aKeys[i];
// Deep compare each member
if (!j$.util.has(b, key)) {
diffBuilder.record(a, b, objectKeysAreDifferentFormatter);
diffBuilder.recordMismatch(
objectKeysAreDifferentFormatter.bind(null, this.pp)
);
result = false;
continue;
}
diffBuilder.withPath(key, function() {
if(!eq(a[key], b[key], aStack, bStack, customTesters, diffBuilder)) {
if (
!self.eq_(a[key], b[key], aStack, bStack, customTesters, diffBuilder)
) {
result = false;
}
});
@@ -416,26 +571,27 @@ getJasmineRequireObj().matchersUtil = function(j$) {
bStack.pop();
return result;
}
};
function keys(obj, isArray) {
var allKeys = Object.keys ? Object.keys(obj) :
(function(o) {
var allKeys = Object.keys
? Object.keys(obj)
: (function(o) {
var keys = [];
for (var key in o) {
if (j$.util.has(o, key)) {
keys.push(key);
}
if (j$.util.has(o, key)) {
keys.push(key);
}
}
return keys;
})(obj);
})(obj);
if (!isArray) {
return allKeys;
}
if (allKeys.length === 0) {
return allKeys;
return allKeys;
}
var extraKeys = [];
@@ -448,59 +604,73 @@ getJasmineRequireObj().matchersUtil = function(j$) {
return extraKeys;
}
function has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
function isFunction(obj) {
return typeof obj === 'function';
}
function objectKeysAreDifferentFormatter(actual, expected, path) {
function objectKeysAreDifferentFormatter(pp, actual, expected, path) {
var missingProperties = j$.util.objectDifference(expected, actual),
extraProperties = j$.util.objectDifference(actual, expected),
missingPropertiesMessage = formatKeyValuePairs(missingProperties),
extraPropertiesMessage = formatKeyValuePairs(extraProperties),
messages = [];
extraProperties = j$.util.objectDifference(actual, expected),
missingPropertiesMessage = formatKeyValuePairs(pp, missingProperties),
extraPropertiesMessage = formatKeyValuePairs(pp, extraProperties),
messages = [];
if (!path.depth()) {
path = 'object';
}
if (missingPropertiesMessage.length) {
messages.push('Expected ' + path + ' to have properties' + missingPropertiesMessage);
messages.push(
'Expected ' + path + ' to have properties' + missingPropertiesMessage
);
}
if (extraPropertiesMessage.length) {
messages.push('Expected ' + path + ' not to have properties' + extraPropertiesMessage);
messages.push(
'Expected ' + path + ' not to have properties' + extraPropertiesMessage
);
}
return messages.join('\n');
}
function constructorsAreDifferentFormatter(actual, expected, path) {
function constructorsAreDifferentFormatter(pp, actual, expected, path) {
if (!path.depth()) {
path = 'object';
}
return 'Expected ' +
path + ' to be a kind of ' +
return (
'Expected ' +
path +
' to be a kind of ' +
j$.fnNameFor(expected.constructor) +
', but was ' + j$.pp(actual) + '.';
', but was ' +
pp(actual) +
'.'
);
}
function actualArrayIsLongerFormatter(actual, expected, path) {
return 'Unexpected ' +
path + (path.depth() ? ' = ' : '') +
j$.pp(actual) +
' in array.';
function actualArrayIsLongerFormatter(pp, actual, expected, path) {
return (
'Unexpected ' +
path +
(path.depth() ? ' = ' : '') +
pp(actual) +
' in array.'
);
}
function formatKeyValuePairs(obj) {
function formatKeyValuePairs(pp, obj) {
var formatted = '';
for (var key in obj) {
formatted += '\n ' + key + ': ' + j$.pp(obj[key]);
formatted += '\n ' + key + ': ' + pp(obj[key]);
}
return formatted;
}
function isDiffBuilder(obj) {
return obj && typeof obj.recordMismatch === 'function';
}
return MatchersUtil;
};

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().nothing = function() {
* {@link expect} nothing explicitly.
* @function
* @name matchers#nothing
* @since 2.8.0
* @example
* expect().nothing();
*/

View File

@@ -1,9 +1,11 @@
getJasmineRequireObj().requireAsyncMatchers = function(jRequire, j$) {
var availableMatchers = [
'toBePending',
'toBeResolved',
'toBeRejected',
'toBeResolvedTo',
'toBeRejectedWith'
'toBeRejectedWith',
'toBeRejectedWithError'
],
matchers = {};

View File

@@ -4,6 +4,7 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
'toBe',
'toBeCloseTo',
'toBeDefined',
'toBeInstanceOf',
'toBeFalse',
'toBeFalsy',
'toBeGreaterThan',
@@ -19,15 +20,17 @@ getJasmineRequireObj().requireMatchers = function(jRequire, j$) {
'toBeUndefined',
'toContain',
'toEqual',
'toHaveSize',
'toHaveBeenCalled',
'toHaveBeenCalledBefore',
'toHaveBeenCalledOnceWith',
'toHaveBeenCalledTimes',
'toHaveBeenCalledWith',
'toHaveClass',
'toMatch',
'toThrow',
'toThrowError',
'toThrowMatching',
'toThrowMatching'
],
matchers = {};

View File

@@ -3,21 +3,29 @@ getJasmineRequireObj().toBe = function(j$) {
* {@link expect} the actual value to be `===` to the expected value.
* @function
* @name matchers#toBe
* @since 1.3.0
* @param {Object} expected - The expected value to compare against.
* @example
* expect(thing).toBe(realThing);
*/
function toBe(util) {
var tip = ' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
function toBe(matchersUtil) {
var tip =
' Tip: To check for deep equality, use .toEqual() instead of .toBe().';
return {
compare: function(actual, expected) {
var result = {
pass: actual === expected,
pass: actual === expected
};
if (typeof expected === 'object') {
result.message = util.buildFailureMessage('toBe', result.pass, actual, expected) + tip;
result.message =
matchersUtil.buildFailureMessage(
'toBe',
result.pass,
actual,
expected
) + tip;
}
return result;

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeCloseTo = function() {
* {@link expect} the actual value to be within a specified precision of the expected value.
* @function
* @name matchers#toBeCloseTo
* @since 1.3.0
* @param {Object} expected - The expected value to compare against.
* @param {Number} [precision=2] - The number of decimal points to check.
* @example
@@ -16,8 +17,13 @@ getJasmineRequireObj().toBeCloseTo = function() {
}
if (expected === null || actual === null) {
throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
'expect(' + actual + ').toBeCloseTo(' + expected + ').'
throw new Error(
'Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
'expect(' +
actual +
').toBeCloseTo(' +
expected +
').'
);
}
@@ -26,7 +32,7 @@ getJasmineRequireObj().toBeCloseTo = function() {
var maxDelta = Math.pow(10, -precision) / 2;
return {
pass: Math.round(delta * pow) / pow <= maxDelta
pass: Math.round(delta * pow) <= maxDelta * pow
};
}
};

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeDefined = function() {
* {@link expect} the actual value to be defined. (Not `undefined`)
* @function
* @name matchers#toBeDefined
* @since 1.3.0
* @example
* expect(result).toBeDefined();
*/
@@ -10,7 +11,7 @@ getJasmineRequireObj().toBeDefined = function() {
return {
compare: function(actual) {
return {
pass: (void 0 !== actual)
pass: void 0 !== actual
};
}
};

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeFalse = function() {
* {@link expect} the actual value to be `false`.
* @function
* @name matchers#toBeFalse
* @since 3.5.0
* @example
* expect(result).toBeFalse();
*/

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeFalsy = function() {
* {@link expect} the actual value to be falsy
* @function
* @name matchers#toBeFalsy
* @since 2.0.0
* @example
* expect(result).toBeFalsy();
*/
@@ -10,7 +11,7 @@ getJasmineRequireObj().toBeFalsy = function() {
return {
compare: function(actual) {
return {
pass: !!!actual
pass: !actual
};
}
};

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeGreaterThan = function() {
* {@link expect} the actual value to be greater than the expected value.
* @function
* @name matchers#toBeGreaterThan
* @since 2.0.0
* @param {Number} expected - The value to compare against.
* @example
* expect(result).toBeGreaterThan(3);
@@ -19,4 +20,3 @@ getJasmineRequireObj().toBeGreaterThan = function() {
return toBeGreaterThan;
};

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
* {@link expect} the actual value to be greater than or equal to the expected value.
* @function
* @name matchers#toBeGreaterThanOrEqual
* @since 2.0.0
* @param {Number} expected - The expected value to compare against.
* @example
* expect(result).toBeGreaterThanOrEqual(25);

View File

@@ -0,0 +1,64 @@
getJasmineRequireObj().toBeInstanceOf = function(j$) {
var usageError = j$.formatErrorMsg(
'<toBeInstanceOf>',
'expect(value).toBeInstanceOf(<ConstructorFunction>)'
);
/**
* {@link expect} the actual to be an instance of the expected class
* @function
* @name matchers#toBeInstanceOf
* @since 3.5.0
* @param {Object} expected - The class or constructor function to check for
* @example
* expect('foo').toBeInstanceOf(String);
* expect(3).toBeInstanceOf(Number);
* expect(new Error()).toBeInstanceOf(Error);
*/
function toBeInstanceOf(matchersUtil) {
return {
compare: function(actual, expected) {
var actualType =
actual && actual.constructor
? j$.fnNameFor(actual.constructor)
: matchersUtil.pp(actual),
expectedType = expected
? j$.fnNameFor(expected)
: matchersUtil.pp(expected),
expectedMatcher,
pass;
try {
expectedMatcher = new j$.Any(expected);
pass = expectedMatcher.asymmetricMatch(actual);
} catch (error) {
throw new Error(
usageError('Expected value is not a constructor function')
);
}
if (pass) {
return {
pass: true,
message:
'Expected instance of ' +
actualType +
' not to be an instance of ' +
expectedType
};
} else {
return {
pass: false,
message:
'Expected instance of ' +
actualType +
' to be an instance of ' +
expectedType
};
}
}
};
}
return toBeInstanceOf;
};

View File

@@ -3,13 +3,13 @@ getJasmineRequireObj().toBeLessThan = function() {
* {@link expect} the actual value to be less than the expected value.
* @function
* @name matchers#toBeLessThan
* @since 2.0.0
* @param {Number} expected - The expected value to compare against.
* @example
* expect(result).toBeLessThan(0);
*/
function toBeLessThan() {
return {
compare: function(actual, expected) {
return {
pass: actual < expected

View File

@@ -3,13 +3,13 @@ getJasmineRequireObj().toBeLessThanOrEqual = function() {
* {@link expect} the actual value to be less than or equal to the expected value.
* @function
* @name matchers#toBeLessThanOrEqual
* @since 2.0.0
* @param {Number} expected - The expected value to compare against.
* @example
* expect(result).toBeLessThanOrEqual(123);
*/
function toBeLessThanOrEqual() {
return {
compare: function(actual, expected) {
return {
pass: actual <= expected

View File

@@ -3,20 +3,23 @@ getJasmineRequireObj().toBeNaN = function(j$) {
* {@link expect} the actual value to be `NaN` (Not a Number).
* @function
* @name matchers#toBeNaN
* @since 1.3.0
* @example
* expect(thing).toBeNaN();
*/
function toBeNaN() {
function toBeNaN(matchersUtil) {
return {
compare: function(actual) {
var result = {
pass: (actual !== actual)
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.'; };
result.message = function() {
return 'Expected ' + matchersUtil.pp(actual) + ' to be NaN.';
};
}
return result;

View File

@@ -3,20 +3,23 @@ getJasmineRequireObj().toBeNegativeInfinity = function(j$) {
* {@link expect} the actual value to be `-Infinity` (-infinity).
* @function
* @name matchers#toBeNegativeInfinity
* @since 2.6.0
* @example
* expect(thing).toBeNegativeInfinity();
*/
function toBeNegativeInfinity() {
function toBeNegativeInfinity(matchersUtil) {
return {
compare: function(actual) {
var result = {
pass: (actual === Number.NEGATIVE_INFINITY)
pass: actual === Number.NEGATIVE_INFINITY
};
if (result.pass) {
result.message = 'Expected actual not to be -Infinity.';
} else {
result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be -Infinity.'; };
result.message = function() {
return 'Expected ' + matchersUtil.pp(actual) + ' to be -Infinity.';
};
}
return result;

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeNull = function() {
* {@link expect} the actual value to be `null`.
* @function
* @name matchers#toBeNull
* @since 1.3.0
* @example
* expect(result).toBeNull();
*/

View File

@@ -3,20 +3,23 @@ getJasmineRequireObj().toBePositiveInfinity = function(j$) {
* {@link expect} the actual value to be `Infinity` (infinity).
* @function
* @name matchers#toBePositiveInfinity
* @since 2.6.0
* @example
* expect(thing).toBePositiveInfinity();
*/
function toBePositiveInfinity() {
function toBePositiveInfinity(matchersUtil) {
return {
compare: function(actual) {
var result = {
pass: (actual === Number.POSITIVE_INFINITY)
pass: actual === Number.POSITIVE_INFINITY
};
if (result.pass) {
result.message = 'Expected actual not to be Infinity.';
} else {
result.message = function() { return 'Expected ' + j$.pp(actual) + ' to be Infinity.'; };
result.message = function() {
return 'Expected ' + matchersUtil.pp(actual) + ' to be Infinity.';
};
}
return result;

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeTrue = function() {
* {@link expect} the actual value to be `true`.
* @function
* @name matchers#toBeTrue
* @since 3.5.0
* @example
* expect(result).toBeTrue();
*/

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeTruthy = function() {
* {@link expect} the actual value to be truthy.
* @function
* @name matchers#toBeTruthy
* @since 2.0.0
* @example
* expect(thing).toBeTruthy();
*/

View File

@@ -3,6 +3,7 @@ getJasmineRequireObj().toBeUndefined = function() {
* {@link expect} the actual value to be `undefined`.
* @function
* @name matchers#toBeUndefined
* @since 1.3.0
* @example
* expect(result).toBeUndefined():
*/

View File

@@ -3,19 +3,17 @@ getJasmineRequireObj().toContain = function() {
* {@link expect} the actual value to contain a specific value.
* @function
* @name matchers#toContain
* @since 2.0.0
* @param {Object} expected - The value to look for.
* @example
* expect(array).toContain(anElement);
* expect(string).toContain(substring);
*/
function toContain(util, customEqualityTesters) {
customEqualityTesters = customEqualityTesters || [];
function toContain(matchersUtil) {
return {
compare: function(actual, expected) {
return {
pass: util.contains(actual, expected, customEqualityTesters)
pass: matchersUtil.contains(actual, expected)
};
}
};

View File

@@ -3,21 +3,20 @@ getJasmineRequireObj().toEqual = function(j$) {
* {@link expect} the actual value to be equal to the expected, using deep equality comparison.
* @function
* @name matchers#toEqual
* @since 1.3.0
* @param {Object} expected - Expected value
* @example
* expect(bigObject).toEqual({"foo": ['bar', 'baz']});
*/
function toEqual(util, customEqualityTesters) {
customEqualityTesters = customEqualityTesters || [];
function toEqual(matchersUtil) {
return {
compare: function(actual, expected) {
var result = {
pass: false
},
diffBuilder = j$.DiffBuilder();
diffBuilder = j$.DiffBuilder({ prettyPrinter: matchersUtil.pp });
result.pass = util.equals(actual, expected, customEqualityTesters, diffBuilder);
result.pass = matchersUtil.equals(actual, expected, diffBuilder);
// TODO: only set error message if test fails
result.message = diffBuilder.getMessage();

View File

@@ -1,33 +1,42 @@
getJasmineRequireObj().toHaveBeenCalled = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
var getErrorMsg = j$.formatErrorMsg(
'<toHaveBeenCalled>',
'expect(<spyObj>).toHaveBeenCalled()'
);
/**
* {@link expect} the actual (a {@link Spy}) to have been called.
* @function
* @name matchers#toHaveBeenCalled
* @since 1.3.0
* @example
* expect(mySpy).toHaveBeenCalled();
* expect(mySpy).not.toHaveBeenCalled();
*/
function toHaveBeenCalled() {
function toHaveBeenCalled(matchersUtil) {
return {
compare: function(actual) {
var result = {};
if (!j$.isSpy(actual)) {
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
throw new Error(
getErrorMsg(
'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
)
);
}
if (arguments.length > 1) {
throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
throw new Error(
getErrorMsg('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.';
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;
}

View File

@@ -1,33 +1,46 @@
getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledBefore>', 'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)');
var getErrorMsg = j$.formatErrorMsg(
'<toHaveBeenCalledBefore>',
'expect(<spyObj>).toHaveBeenCalledBefore(<spyObj>)'
);
/**
* {@link expect} the actual value (a {@link Spy}) to have been called before another {@link Spy}.
* @function
* @name matchers#toHaveBeenCalledBefore
* @since 2.6.0
* @param {Spy} expected - {@link Spy} that should have been called after the `actual` {@link Spy}.
* @example
* expect(mySpy).toHaveBeenCalledBefore(otherSpy);
*/
function toHaveBeenCalledBefore() {
function toHaveBeenCalledBefore(matchersUtil) {
return {
compare: function(firstSpy, latterSpy) {
if (!j$.isSpy(firstSpy)) {
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(firstSpy) + '.'));
throw new Error(
getErrorMsg(
'Expected a spy, but got ' + matchersUtil.pp(firstSpy) + '.'
)
);
}
if (!j$.isSpy(latterSpy)) {
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(latterSpy) + '.'));
throw new Error(
getErrorMsg(
'Expected a spy, but got ' + matchersUtil.pp(latterSpy) + '.'
)
);
}
var result = { pass: false };
if (!firstSpy.calls.count()) {
result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called.';
result.message =
'Expected spy ' + firstSpy.and.identity + ' to have been called.';
return result;
}
if (!latterSpy.calls.count()) {
result.message = 'Expected spy ' + latterSpy.and.identity + ' to have been called.';
result.message =
'Expected spy ' + latterSpy.and.identity + ' to have been called.';
return result;
}
@@ -37,17 +50,36 @@ getJasmineRequireObj().toHaveBeenCalledBefore = function(j$) {
result.pass = latest1stSpyCall < first2ndSpyCall;
if (result.pass) {
result.message = 'Expected spy ' + firstSpy.and.identity + ' to not have been called before spy ' + latterSpy.and.identity + ', but it was';
result.message =
'Expected spy ' +
firstSpy.and.identity +
' to not have been called before spy ' +
latterSpy.and.identity +
', but it was';
} else {
var first1stSpyCall = firstSpy.calls.first().invocationOrder;
var latest2ndSpyCall = latterSpy.calls.mostRecent().invocationOrder;
if(first1stSpyCall < first2ndSpyCall) {
result.message = 'Expected latest call to spy ' + firstSpy.and.identity + ' to have been called before first call to spy ' + latterSpy.and.identity + ' (no interleaved calls)';
if (first1stSpyCall < first2ndSpyCall) {
result.message =
'Expected latest call to spy ' +
firstSpy.and.identity +
' to have been called before first call to spy ' +
latterSpy.and.identity +
' (no interleaved calls)';
} else if (latest2ndSpyCall > latest1stSpyCall) {
result.message = 'Expected first call to spy ' + latterSpy.and.identity + ' to have been called after latest call to spy ' + firstSpy.and.identity + ' (no interleaved calls)';
result.message =
'Expected first call to spy ' +
latterSpy.and.identity +
' to have been called after latest call to spy ' +
firstSpy.and.identity +
' (no interleaved calls)';
} else {
result.message = 'Expected spy ' + firstSpy.and.identity + ' to have been called before spy ' + latterSpy.and.identity;
result.message =
'Expected spy ' +
firstSpy.and.identity +
' to have been called before spy ' +
latterSpy.and.identity;
}
}

View File

@@ -0,0 +1,99 @@
getJasmineRequireObj().toHaveBeenCalledOnceWith = function(j$) {
var getErrorMsg = j$.formatErrorMsg(
'<toHaveBeenCalledOnceWith>',
'expect(<spyObj>).toHaveBeenCalledOnceWith(...arguments)'
);
/**
* {@link expect} the actual (a {@link Spy}) to have been called exactly once, and exactly with the particular arguments.
* @function
* @name matchers#toHaveBeenCalledOnceWith
* @since 3.6.0
* @param {...Object} - The arguments to look for
* @example
* expect(mySpy).toHaveBeenCalledOnceWith('foo', 'bar', 2);
*/
function toHaveBeenCalledOnceWith(util) {
return {
compare: function() {
var args = Array.prototype.slice.call(arguments, 0),
actual = args[0],
expectedArgs = args.slice(1);
if (!j$.isSpy(actual)) {
throw new Error(
getErrorMsg('Expected a spy, but got ' + util.pp(actual) + '.')
);
}
var prettyPrintedCalls = actual.calls
.allArgs()
.map(function(argsForCall) {
return ' ' + util.pp(argsForCall);
});
if (
actual.calls.count() === 1 &&
util.contains(actual.calls.allArgs(), expectedArgs)
) {
return {
pass: true,
message:
'Expected spy ' +
actual.and.identity +
' to have been called 0 times, multiple times, or once, but with arguments different from:\n' +
' ' +
util.pp(expectedArgs) +
'\n' +
'But the actual call was:\n' +
prettyPrintedCalls.join(',\n') +
'.\n\n'
};
}
function getDiffs() {
return actual.calls.allArgs().map(function(argsForCall, callIx) {
var diffBuilder = new j$.DiffBuilder();
util.equals(argsForCall, expectedArgs, diffBuilder);
return diffBuilder.getMessage();
});
}
function butString() {
switch (actual.calls.count()) {
case 0:
return 'But it was never called.\n\n';
case 1:
return (
'But the actual call was:\n' +
prettyPrintedCalls.join(',\n') +
'.\n' +
getDiffs().join('\n') +
'\n\n'
);
default:
return (
'But the actual calls were:\n' +
prettyPrintedCalls.join(',\n') +
'.\n\n'
);
}
}
return {
pass: false,
message:
'Expected spy ' +
actual.and.identity +
' to have been called only once, and with given args:\n' +
' ' +
util.pp(expectedArgs) +
'\n' +
butString()
};
}
};
}
return toHaveBeenCalledOnceWith;
};

View File

@@ -1,36 +1,59 @@
getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
var getErrorMsg = j$.formatErrorMsg(
'<toHaveBeenCalledTimes>',
'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)'
);
/**
* {@link expect} the actual (a {@link Spy}) to have been called the specified number of times.
* @function
* @name matchers#toHaveBeenCalledTimes
* @since 2.4.0
* @param {Number} expected - The number of invocations to look for.
* @example
* expect(mySpy).toHaveBeenCalledTimes(3);
*/
function toHaveBeenCalledTimes() {
function toHaveBeenCalledTimes(matchersUtil) {
return {
compare: function(actual, expected) {
if (!j$.isSpy(actual)) {
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
throw new Error(
getErrorMsg(
'Expected a spy, but got ' + matchersUtil.pp(actual) + '.'
)
);
}
var args = Array.prototype.slice.call(arguments, 0),
result = { pass: false };
if (!j$.isNumber_(expected)){
throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
if (!j$.isNumber_(expected)) {
throw new Error(
getErrorMsg(
'The expected times failed is a required argument and must be a number.'
)
);
}
actual = args[0];
var calls = actual.calls.count();
var timesMessage = expected === 1 ? 'once' : expected + ' times';
result.pass = calls === expected;
result.message = result.pass ?
'Expected spy ' + actual.and.identity + ' not to have been called ' + timesMessage + '. It was called ' + calls + ' times.' :
'Expected spy ' + actual.and.identity + ' to have been called ' + timesMessage + '. It was called ' + calls + ' times.';
result.message = result.pass
? 'Expected spy ' +
actual.and.identity +
' not to have been called ' +
timesMessage +
'. It was called ' +
calls +
' times.'
: 'Expected spy ' +
actual.and.identity +
' to have been called ' +
timesMessage +
'. It was called ' +
calls +
' times.';
return result;
}
};

View File

@@ -1,16 +1,19 @@
getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
var getErrorMsg = j$.formatErrorMsg(
'<toHaveBeenCalledWith>',
'expect(<spyObj>).toHaveBeenCalledWith(...arguments)'
);
/**
* {@link expect} the actual (a {@link Spy}) to have been called with particular arguments at least once.
* @function
* @name matchers#toHaveBeenCalledWith
* @since 1.3.0
* @param {...Object} - The arguments to look for
* @example
* expect(mySpy).toHaveBeenCalledWith('foo', 'bar', 2);
*/
function toHaveBeenCalledWith(util, customEqualityTesters) {
function toHaveBeenCalledWith(matchersUtil) {
return {
compare: function() {
var args = Array.prototype.slice.call(arguments, 0),
@@ -19,19 +22,74 @@ getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
result = { pass: false };
if (!j$.isSpy(actual)) {
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
throw new Error(
getErrorMsg(
'Expected a spy, but got ' + matchersUtil.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.'; };
result.message = function() {
return (
'Expected spy ' +
actual.and.identity +
' to have been called with:\n' +
' ' +
matchersUtil.pp(expectedArgs) +
'\nbut it was never called.'
);
};
return result;
}
if (util.contains(actual.calls.allArgs(), expectedArgs, customEqualityTesters)) {
if (matchersUtil.contains(actual.calls.allArgs(), expectedArgs)) {
result.pass = true;
result.message = function() { return 'Expected spy ' + actual.and.identity + ' not to have been called with ' + j$.pp(expectedArgs) + ' but it was.'; };
result.message = function() {
return (
'Expected spy ' +
actual.and.identity +
' not to have been called with:\n' +
' ' +
matchersUtil.pp(expectedArgs) +
'\nbut 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, '') + '.'; };
result.message = function() {
var prettyPrintedCalls = actual.calls
.allArgs()
.map(function(argsForCall) {
return ' ' + matchersUtil.pp(argsForCall);
});
var diffs = actual.calls
.allArgs()
.map(function(argsForCall, callIx) {
var diffBuilder = new j$.DiffBuilder();
matchersUtil.equals(argsForCall, expectedArgs, diffBuilder);
return (
'Call ' +
callIx +
':\n' +
diffBuilder.getMessage().replace(/^/gm, ' ')
);
});
return (
'Expected spy ' +
actual.and.identity +
' to have been called with:\n' +
' ' +
matchersUtil.pp(expectedArgs) +
'\n' +
'' +
'but actual calls were:\n' +
prettyPrintedCalls.join(',\n') +
'.\n\n' +
diffs.join('\n')
);
};
}
return result;

View File

@@ -3,17 +3,18 @@ getJasmineRequireObj().toHaveClass = function(j$) {
* {@link expect} the actual value to be a DOM element that has the expected class
* @function
* @name matchers#toHaveClass
* @since 3.0.0
* @param {Object} expected - The class name to test for
* @example
* var el = document.createElement('div');
* el.className = 'foo bar baz';
* expect(el).toHaveClass('bar');
*/
function toHaveClass(util, customEqualityTesters) {
function toHaveClass(matchersUtil) {
return {
compare: function(actual, expected) {
if (!isElement(actual)) {
throw new Error(j$.pp(actual) + ' is not a DOM element');
throw new Error(matchersUtil.pp(actual) + ' is not a DOM element');
}
return {
@@ -24,9 +25,9 @@ getJasmineRequireObj().toHaveClass = function(j$) {
}
function isElement(maybeEl) {
return maybeEl &&
maybeEl.classList &&
j$.isFunction_(maybeEl.classList.contains);
return (
maybeEl && maybeEl.classList && j$.isFunction_(maybeEl.classList.contains)
);
}
return toHaveClass;

View File

@@ -0,0 +1,51 @@
getJasmineRequireObj().toHaveSize = function(j$) {
/**
* {@link expect} the actual size to be equal to the expected, using array-like length or object keys size.
* @function
* @name matchers#toHaveSize
* @since 3.6.0
* @param {Object} expected - Expected size
* @example
* array = [1,2];
* expect(array).toHaveSize(2);
*/
function toHaveSize() {
return {
compare: function(actual, expected) {
var result = {
pass: false
};
if (
j$.isA_('WeakSet', actual) ||
j$.isWeakMap(actual) ||
j$.isDataView(actual)
) {
throw new Error('Cannot get size of ' + actual + '.');
}
if (j$.isSet(actual) || j$.isMap(actual)) {
result.pass = actual.size === expected;
} else if (isLength(actual.length)) {
result.pass = actual.length === expected;
} else {
result.pass = Object.keys(actual).length === expected;
}
return result;
}
};
}
var MAX_SAFE_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; // eslint-disable-line compat/compat
function isLength(value) {
return (
typeof value == 'number' &&
value > -1 &&
value % 1 === 0 &&
value <= MAX_SAFE_INTEGER
);
}
return toHaveSize;
};

View File

@@ -1,11 +1,14 @@
getJasmineRequireObj().toMatch = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
var getErrorMsg = j$.formatErrorMsg(
'<toMatch>',
'expect(<expectation>).toMatch(<string> || <regexp>)'
);
/**
* {@link expect} the actual value to match a regular expression
* @function
* @name matchers#toMatch
* @since 1.3.0
* @param {RegExp|String} expected - Value to look for in the string.
* @example
* expect("my string").toMatch(/string$/);

View File

@@ -1,17 +1,20 @@
getJasmineRequireObj().toThrow = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toThrow>', 'expect(function() {<expectation>}).toThrow()');
var getErrorMsg = j$.formatErrorMsg(
'<toThrow>',
'expect(function() {<expectation>}).toThrow()'
);
/**
* {@link expect} a function to `throw` something.
* @function
* @name matchers#toThrow
* @since 2.0.0
* @param {Object} [expected] - Value that should be thrown. If not provided, simply the fact that something was thrown will be checked.
* @example
* expect(function() { return 'things'; }).toThrow('foo');
* expect(function() { return 'stuff'; }).toThrow();
*/
function toThrow(util) {
function toThrow(matchersUtil) {
return {
compare: function(actual, expected) {
var result = { pass: false },
@@ -36,16 +39,36 @@ getJasmineRequireObj().toThrow = function(j$) {
if (arguments.length == 1) {
result.pass = true;
result.message = function() { return 'Expected function not to throw, but it threw ' + j$.pp(thrown) + '.'; };
result.message = function() {
return (
'Expected function not to throw, but it threw ' +
matchersUtil.pp(thrown) +
'.'
);
};
return result;
}
if (util.equals(thrown, expected)) {
if (matchersUtil.equals(thrown, expected)) {
result.pass = true;
result.message = function() { return 'Expected function not to throw ' + j$.pp(expected) + '.'; };
result.message = function() {
return (
'Expected function not to throw ' +
matchersUtil.pp(expected) +
'.'
);
};
} else {
result.message = function() { return 'Expected function to throw ' + j$.pp(expected) + ', but it threw ' + j$.pp(thrown) + '.'; };
result.message = function() {
return (
'Expected function to throw ' +
matchersUtil.pp(expected) +
', but it threw ' +
matchersUtil.pp(thrown) +
'.'
);
};
}
return result;

View File

@@ -1,11 +1,14 @@
getJasmineRequireObj().toThrowError = function(j$) {
var getErrorMsg = j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
var getErrorMsg = j$.formatErrorMsg(
'<toThrowError>',
'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)'
);
/**
* {@link expect} a function to `throw` an `Error`.
* @function
* @name matchers#toThrowError
* @since 2.0.0
* @param {Error} [expected] - `Error` constructor the object that was thrown needs to be an instance of. If not provided, `Error` will be used.
* @param {RegExp|String} [message] - The message that should be set on the thrown `Error`
* @example
@@ -15,7 +18,7 @@ getJasmineRequireObj().toThrowError = function(j$) {
* expect(function() { return 'other'; }).toThrowError(/foo/);
* expect(function() { return 'other'; }).toThrowError();
*/
function toThrowError () {
function toThrowError(matchersUtil) {
return {
compare: function(actual) {
var errorMatcher = getMatcher.apply(null, arguments),
@@ -33,7 +36,13 @@ getJasmineRequireObj().toThrowError = function(j$) {
}
if (!j$.isError_(thrown)) {
return fail(function() { return 'Expected function to throw an Error, but it threw ' + j$.pp(thrown) + '.'; });
return fail(function() {
return (
'Expected function to throw an Error, but it threw ' +
matchersUtil.pp(thrown) +
'.'
);
});
}
return errorMatcher.match(thrown);
@@ -67,7 +76,11 @@ getJasmineRequireObj().toThrowError = function(j$) {
function anyMatcher() {
return {
match: function(error) {
return pass('Expected function not to throw an Error, but it threw ' + j$.fnNameFor(error) + '.');
return pass(
'Expected function not to throw an Error, but it threw ' +
j$.fnNameFor(error) +
'.'
);
}
};
}
@@ -75,9 +88,13 @@ getJasmineRequireObj().toThrowError = function(j$) {
function exactMatcher(expected, errorType) {
if (expected && !isStringOrRegExp(expected)) {
if (errorType) {
throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
throw new Error(
getErrorMsg('Expected error message is not a string or RegExp.')
);
} else {
throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));
throw new Error(
getErrorMsg('Expected is not an Error, string, or RegExp.')
);
}
}
@@ -89,14 +106,18 @@ getJasmineRequireObj().toThrowError = function(j$) {
}
}
var errorTypeDescription = errorType ? j$.fnNameFor(errorType) : 'an exception';
var errorTypeDescription = errorType
? j$.fnNameFor(errorType)
: 'an exception';
function thrownDescription(thrown) {
var thrownName = errorType ? j$.fnNameFor(thrown.constructor) : 'an exception',
thrownMessage = '';
var thrownName = errorType
? j$.fnNameFor(thrown.constructor)
: 'an exception',
thrownMessage = '';
if (expected) {
thrownMessage = ' with message ' + j$.pp(thrown.message);
thrownMessage = ' with message ' + matchersUtil.pp(thrown.message);
}
return thrownName + thrownMessage;
@@ -106,27 +127,40 @@ getJasmineRequireObj().toThrowError = function(j$) {
if (expected === null) {
return '';
} else if (expected instanceof RegExp) {
return ' with a message matching ' + j$.pp(expected);
return ' with a message matching ' + matchersUtil.pp(expected);
} else {
return ' with message ' + j$.pp(expected);
return ' with message ' + matchersUtil.pp(expected);
}
}
function matches(error) {
return (errorType === null || error instanceof errorType) &&
(expected === null || messageMatch(error.message));
return (
(errorType === null || error instanceof errorType) &&
(expected === null || messageMatch(error.message))
);
}
return {
match: function(thrown) {
if (matches(thrown)) {
return pass(function() {
return 'Expected function not to throw ' + errorTypeDescription + messageDescription() + '.';
return (
'Expected function not to throw ' +
errorTypeDescription +
messageDescription() +
'.'
);
});
} else {
return fail(function() {
return 'Expected function to throw ' + errorTypeDescription + messageDescription() +
', but it threw ' + thrownDescription(thrown) + '.';
return (
'Expected function to throw ' +
errorTypeDescription +
messageDescription() +
', but it threw ' +
thrownDescription(thrown) +
'.'
);
});
}
}
@@ -134,7 +168,7 @@ getJasmineRequireObj().toThrowError = function(j$) {
}
function isStringOrRegExp(potential) {
return potential instanceof RegExp || (typeof potential == 'string');
return potential instanceof RegExp || typeof potential == 'string';
}
function isAnErrorType(type) {

View File

@@ -1,15 +1,19 @@
getJasmineRequireObj().toThrowMatching = function(j$) {
var usageError = j$.formatErrorMsg('<toThrowMatching>', 'expect(function() {<expectation>}).toThrowMatching(<Predicate>)');
var usageError = j$.formatErrorMsg(
'<toThrowMatching>',
'expect(function() {<expectation>}).toThrowMatching(<Predicate>)'
);
/**
* {@link expect} a function to `throw` something matching a predicate.
* @function
* @name matchers#toThrowMatching
* @since 3.0.0
* @param {Function} predicate - A function that takes the thrown exception as its parameter and returns true if it matches.
* @example
* expect(function() { throw new Error('nope'); }).toThrowMatching(function(thrown) { return thrown.message === 'nope'; });
*/
function toThrowMatching() {
function toThrowMatching(matchersUtil) {
return {
compare: function(actual, predicate) {
var thrown;
@@ -30,23 +34,32 @@ getJasmineRequireObj().toThrowMatching = function(j$) {
}
if (predicate(thrown)) {
return pass('Expected function not to throw an exception matching a predicate.');
return pass(
'Expected function not to throw an exception matching a predicate.'
);
} else {
return fail(function() {
return 'Expected function to throw an exception matching a predicate, ' +
'but it threw ' + thrownDescription(thrown) + '.';
});
return fail(function() {
return (
'Expected function to throw an exception matching a predicate, ' +
'but it threw ' +
thrownDescription(thrown) +
'.'
);
});
}
}
};
}
function thrownDescription(thrown) {
if (thrown && thrown.constructor) {
return j$.fnNameFor(thrown.constructor) + ' with message ' +
j$.pp(thrown.message);
} else {
return j$.pp(thrown);
function thrownDescription(thrown) {
if (thrown && thrown.constructor) {
return (
j$.fnNameFor(thrown.constructor) +
' with message ' +
matchersUtil.pp(thrown.message)
);
} else {
return matchersUtil.pp(thrown);
}
}
}

View File

@@ -1,8 +1,12 @@
var getJasmineRequireObj = (function (jasmineGlobal) {
/* globals exports, global, module, window */
// eslint-disable-next-line no-unused-vars
var getJasmineRequireObj = (function(jasmineGlobal) {
var jasmineRequire;
if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
if (
typeof module !== 'undefined' &&
module.exports &&
typeof exports !== 'undefined'
) {
if (typeof global !== 'undefined') {
jasmineGlobal = global;
} else {
@@ -10,7 +14,11 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
}
jasmineRequire = exports;
} else {
if (typeof window !== 'undefined' && typeof window.toString === 'function' && window.toString() === '[object GjsGlobal]') {
if (
typeof window !== 'undefined' &&
typeof window.toString === 'function' &&
window.toString() === '[object GjsGlobal]'
) {
jasmineGlobal = window;
}
jasmineRequire = jasmineGlobal.jasmineRequire = {};
@@ -40,14 +48,24 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.ExpectationFilterChain = jRequire.ExpectationFilterChain();
j$.Expector = jRequire.Expector(j$);
j$.Expectation = jRequire.Expectation(j$);
j$.buildExpectationResult = jRequire.buildExpectationResult();
j$.noopTimer = jRequire.noopTimer();
j$.buildExpectationResult = jRequire.buildExpectationResult(j$);
j$.JsApiReporter = jRequire.JsApiReporter(j$);
j$.matchersUtil = jRequire.matchersUtil(j$);
j$.asymmetricEqualityTesterArgCompatShim = jRequire.asymmetricEqualityTesterArgCompatShim(
j$
);
j$.makePrettyPrinter = jRequire.makePrettyPrinter(j$);
j$.pp = j$.makePrettyPrinter();
j$.MatchersUtil = jRequire.MatchersUtil(j$);
j$.matchersUtil = new j$.MatchersUtil({
customTesters: [],
pp: j$.pp
});
j$.ObjectContaining = jRequire.ObjectContaining(j$);
j$.ArrayContaining = jRequire.ArrayContaining(j$);
j$.ArrayWithExactContents = jRequire.ArrayWithExactContents(j$);
j$.pp = jRequire.pp(j$);
j$.MapContaining = jRequire.MapContaining(j$);
j$.SetContaining = jRequire.SetContaining(j$);
j$.QueueRunner = jRequire.QueueRunner(j$);
j$.ReportDispatcher = jRequire.ReportDispatcher(j$);
j$.Spec = jRequire.Spec(j$);
@@ -65,6 +83,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.DiffBuilder = jRequire.DiffBuilder(j$);
j$.NullDiffBuilder = jRequire.NullDiffBuilder(j$);
j$.ObjectPath = jRequire.ObjectPath(j$);
j$.MismatchTree = jRequire.MismatchTree(j$);
j$.GlobalErrors = jRequire.GlobalErrors(j$);
j$.Truthy = jRequire.Truthy(j$);

View File

@@ -15,6 +15,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* Calls to `describe` can be nested within other calls to compose your suite as a tree.
* @name describe
* @since 1.3.0
* @function
* @global
* @param {String} description Textual description of the group
@@ -29,6 +30,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* Specs within an `xdescribe` will be marked pending and not executed
* @name xdescribe
* @since 1.3.0
* @function
* @global
* @param {String} description Textual description of the group
@@ -44,6 +46,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* If suites or specs are focused, only those that are focused will be executed
* @see fit
* @name fdescribe
* @since 2.1.0
* @function
* @global
* @param {String} description Textual description of the group
@@ -57,7 +60,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* Define a single spec. A spec should contain one or more {@link expect|expectations} that test the state of the code.
*
* A spec whose expectations all succeed will be passing and a spec with any failures will fail.
* The name `it` is a pronoun for the test target, not an abbreviation of anything. It makes the
* spec more readable by connecting the function name `it` and the argument `description` as a
* complete sentence.
* @name it
* @since 1.3.0
* @function
* @global
* @param {String} description Textual description of what this spec is checking
@@ -74,6 +81,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* The spec will report as `pending` and will not be executed.
* @name xit
* @since 1.3.0
* @function
* @global
* @param {String} description Textual description of what this spec is checking.
@@ -88,6 +96,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* If suites or specs are focused, only those that are focused will be executed.
* @name fit
* @since 2.1.0
* @function
* @global
* @param {String} description Textual description of what this spec is checking.
@@ -102,6 +111,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Run some shared setup before each of the specs in the {@link describe} in which it is called.
* @name beforeEach
* @since 1.3.0
* @function
* @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs.
@@ -115,6 +125,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Run some shared teardown after each of the specs in the {@link describe} in which it is called.
* @name afterEach
* @since 1.3.0
* @function
* @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs.
@@ -130,6 +141,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* _Note:_ Be careful, sharing the setup from a beforeAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
* @name beforeAll
* @since 2.1.0
* @function
* @global
* @param {implementationCallback} [function] Function that contains the code to setup your specs.
@@ -145,6 +157,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* _Note:_ Be careful, sharing the teardown from a afterAll makes it easy to accidentally leak state between your specs so that they erroneously pass or fail.
* @name afterAll
* @since 2.1.0
* @function
* @global
* @param {implementationCallback} [function] Function that contains the code to teardown your specs.
@@ -155,9 +168,34 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.afterAll.apply(env, arguments);
},
/**
* Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SpecResult}
* @name setSpecProperty
* @since 3.6.0
* @function
* @param {String} key The name of the property
* @param {*} value The value of the property
*/
setSpecProperty: function(key, value) {
return env.setSpecProperty(key, value);
},
/**
* Sets a user-defined property that will be provided to reporters as part of the properties field of {@link SuiteResult}
* @name setSuiteProperty
* @since 3.6.0
* @function
* @param {String} key The name of the property
* @param {*} value The value of the property
*/
setSuiteProperty: function(key, value) {
return env.setSuiteProperty(key, value);
},
/**
* Create an expectation for a spec.
* @name expect
* @since 1.3.0
* @function
* @global
* @param {Object} actual - Actual computed value to test expectations against.
@@ -173,6 +211,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
* which must be either returned from the spec or waited for using `await`
* in order for Jasmine to associate them with the correct spec.
* @name expectAsync
* @since 3.3.0
* @function
* @global
* @param {Object} actual - Actual computed value to test expectations against.
@@ -189,6 +228,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Mark a spec as pending, expectation results will be ignored.
* @name pending
* @since 2.0.0
* @function
* @global
* @param {String} [message] - Reason the spec is pending.
@@ -200,10 +240,11 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Explicitly mark a spec as failed.
* @name fail
* @since 2.1.0
* @function
* @global
* @param {String|Error} [error] - Reason for the failure.
*/
*/
fail: function() {
return env.fail.apply(env, arguments);
},
@@ -211,6 +252,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Install a spy onto an existing object.
* @name spyOn
* @since 1.3.0
* @function
* @global
* @param {Object} obj - The object upon which to install the {@link Spy}.
@@ -224,6 +266,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Install a spy on a property installed with `Object.defineProperty` onto an existing object.
* @name spyOnProperty
* @since 2.6.0
* @function
* @global
* @param {Object} obj - The object upon which to install the {@link Spy}
@@ -238,6 +281,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Installs spies on all writable and configurable properties of an object.
* @name spyOnAllFunctions
* @since 3.2.1
* @function
* @global
* @param {Object} obj - The object upon which to install the {@link Spy}s
@@ -262,6 +306,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.addCustomEqualityTester
* @since 2.0.0
* @function
* @param {Function} tester - A function which takes two arguments to compare and returns a `true` or `false` comparison result if it knows how to compare them, and `undefined` otherwise.
* @see custom_equality
@@ -275,6 +320,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.addMatchers
* @since 2.0.0
* @function
* @param {Object} matchers - Keys from this object will be the new matcher names.
* @see custom_matcher
@@ -283,9 +329,38 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.addMatchers(matchers);
};
/**
* Add custom async matchers for the current scope of specs.
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.addAsyncMatchers
* @since 3.5.0
* @function
* @param {Object} matchers - Keys from this object will be the new async matcher names.
* @see custom_matcher
*/
jasmine.addAsyncMatchers = function(matchers) {
return env.addAsyncMatchers(matchers);
};
/**
* Add a custom object formatter for the current scope of specs.
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.addCustomObjectFormatter
* @since 3.6.0
* @function
* @param {Function} formatter - A function which takes a value to format and returns a string if it knows how to format it, and `undefined` otherwise.
* @see custom_object_formatters
*/
jasmine.addCustomObjectFormatter = function(formatter) {
return env.addCustomObjectFormatter(formatter);
};
/**
* Get the currently booted mock {Clock} for this Jasmine environment.
* @name jasmine.clock
* @since 2.0.0
* @function
* @returns {Clock}
*/
@@ -296,6 +371,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Create a bare {@link Spy} object. This won't be installed anywhere and will not have any implementation behind it.
* @name jasmine.createSpy
* @since 1.3.0
* @function
* @param {String} [name] - Name to give the spy. This will be displayed in failure messages.
* @param {Function} [originalFn] - Function to act as the real implementation.
@@ -308,13 +384,15 @@ getJasmineRequireObj().interface = function(jasmine, env) {
/**
* Create an object with multiple {@link Spy}s as its members.
* @name jasmine.createSpyObj
* @since 1.3.0
* @function
* @param {String} [baseName] - Base name for the spies in the object.
* @param {String[]|Object} methodNames - Array of method names to create spies for, or Object whose keys will be method names and values the {@link Spy#and#returnValue|returnValue}.
* @param {String[]|Object} [propertyNames] - Array of property names to create spies for, or Object whose keys will be propertynames and values the {@link Spy#and#returnValue|returnValue}.
* @return {Object}
*/
jasmine.createSpyObj = function(baseName, methodNames) {
return env.createSpyObj(baseName, methodNames);
jasmine.createSpyObj = function(baseName, methodNames, propertyNames) {
return env.createSpyObj(baseName, methodNames, propertyNames);
};
/**
@@ -322,6 +400,7 @@ getJasmineRequireObj().interface = function(jasmine, env) {
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.addSpyStrategy
* @since 3.5.0
* @function
* @param {String} name - The name of the strategy (i.e. what you call from `and`)
* @param {Function} factory - Factory function that returns the plan to be executed.
@@ -330,5 +409,21 @@ getJasmineRequireObj().interface = function(jasmine, env) {
return env.addSpyStrategy(name, factory);
};
/**
* Set the default spy strategy for the current scope of specs.
*
* _Note:_ This is only callable from within a {@link beforeEach}, {@link it}, or {@link beforeAll}.
* @name jasmine.setDefaultSpyStrategy
* @function
* @param {Function} defaultStrategyFn - a function that assigns a strategy
* @example
* beforeEach(function() {
* jasmine.setDefaultSpyStrategy(and => and.returnValue(true));
* });
*/
jasmine.setDefaultSpyStrategy = function(defaultStrategyFn) {
return env.setDefaultSpyStrategy(defaultStrategyFn);
};
return jasmineInterface;
};

View File

@@ -1,23 +1,12 @@
getJasmineRequireObj().util = function(j$) {
var util = {};
util.inherit = function(childClass, parentClass) {
var Subclass = function() {
};
var Subclass = function() {};
Subclass.prototype = parentClass.prototype;
childClass.prototype = new Subclass();
};
util.htmlEscape = function(str) {
if (!str) {
return str;
}
return str.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
};
util.argsToArray = function(args) {
var arrayOfArgs = [];
for (var i = 0; i < args.length; i++) {
@@ -58,7 +47,7 @@ getJasmineRequireObj().util = function(j$) {
util.cloneArgs = function(args) {
var clonedArgs = [];
var argsAsArray = j$.util.argsToArray(args);
for(var i = 0; i < argsAsArray.length; i++) {
for (var i = 0; i < argsAsArray.length; i++) {
var str = Object.prototype.toString.apply(argsAsArray[i]),
primitives = /^\[object (Boolean|String|RegExp|Number)/;
@@ -100,19 +89,7 @@ getJasmineRequireObj().util = function(j$) {
return Object.prototype.hasOwnProperty.call(obj, key);
};
function anyMatch(pattern, lines) {
var i;
for (i = 0; i < lines.length; i++) {
if (lines[i].match(pattern)) {
return true;
}
}
return false;
}
util.errorWithStack = function errorWithStack () {
util.errorWithStack = function errorWithStack() {
// Don't throw and catch if we don't have to, because it makes it harder
// for users to debug their code with exception breakpoints.
var error = new Error();
@@ -138,15 +115,32 @@ getJasmineRequireObj().util = function(j$) {
var result;
return function() {
var trace;
if (!result) {
result = callerFile();
}
return result;
};
}());
})();
function StopIteration() {}
StopIteration.prototype = Object.create(Error.prototype);
StopIteration.prototype.constructor = StopIteration;
// useful for maps and sets since `forEach` is the only IE11-compatible way to iterate them
util.forEachBreakable = function(iterable, iteratee) {
function breakLoop() {
throw new StopIteration();
}
try {
iterable.forEach(function(value, key) {
iteratee(breakLoop, value, key, iterable);
});
} catch (error) {
if (!(error instanceof StopIteration)) throw error;
}
};
return util;
};

View File

@@ -23,8 +23,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
};
ResultsStateBuilder.prototype.specStarted = function(result) {
};
ResultsStateBuilder.prototype.specStarted = function(result) {};
ResultsStateBuilder.prototype.specDone = function(result) {
this.currentParent.addChild(result, 'spec');
@@ -42,32 +41,42 @@ jasmineRequire.HtmlReporter = function(j$) {
}
};
function HtmlReporter(options) {
var config = function() { return (options.env && options.env.configuration()) || {}; },
var config = function() {
return (options.env && options.env.configuration()) || {};
},
getContainer = options.getContainer,
createElement = options.createElement,
createTextNode = options.createTextNode,
navigateWithNewParam = options.navigateWithNewParam || function() {},
addToExistingQueryString = options.addToExistingQueryString || defaultQueryString,
addToExistingQueryString =
options.addToExistingQueryString || defaultQueryString,
filterSpecs = options.filterSpecs,
timer = options.timer || j$.noopTimer,
htmlReporterMain,
symbols,
deprecationWarnings = [];
this.initialize = function() {
clearPrior();
htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'},
createDom('div', {className: 'jasmine-banner'},
createDom('a', {className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank'}),
createDom('span', {className: 'jasmine-version'}, j$.version)
htmlReporterMain = createDom(
'div',
{ className: 'jasmine_html-reporter' },
createDom(
'div',
{ className: 'jasmine-banner' },
createDom('a', {
className: 'jasmine-title',
href: 'http://jasmine.github.io/',
target: '_blank'
}),
createDom('span', { className: 'jasmine-version' }, j$.version)
),
createDom('ul', {className: 'jasmine-symbol-summary'}),
createDom('div', {className: 'jasmine-alert'}),
createDom('div', {className: 'jasmine-results'},
createDom('div', {className: 'jasmine-failures'})
createDom('ul', { className: 'jasmine-symbol-summary' }),
createDom('div', { className: 'jasmine-alert' }),
createDom(
'div',
{ className: 'jasmine-results' },
createDom('div', { className: 'jasmine-failures' })
)
);
getContainer().appendChild(htmlReporterMain);
@@ -76,10 +85,9 @@ jasmineRequire.HtmlReporter = function(j$) {
var totalSpecsDefined;
this.jasmineStarted = function(options) {
totalSpecsDefined = options.totalSpecsDefined || 0;
timer.start();
};
var summary = createDom('div', {className: 'jasmine-summary'});
var summary = createDom('div', { className: 'jasmine-summary' });
var stateBuilder = new ResultsStateBuilder();
@@ -93,7 +101,7 @@ jasmineRequire.HtmlReporter = function(j$) {
if (result.status === 'failed') {
failures.push(failureDom(result));
}
addDeprecationWarnings(result);
addDeprecationWarnings(result, 'suite');
};
this.specStarted = function(result) {
@@ -104,35 +112,45 @@ jasmineRequire.HtmlReporter = function(j$) {
this.specDone = function(result) {
stateBuilder.specDone(result);
if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') {
console.error('Spec \'' + result.fullName + '\' has no expectations.');
if (noExpectations(result)) {
var noSpecMsg = "Spec '" + result.fullName + "' has no expectations.";
if (result.status === 'failed') {
console.error(noSpecMsg);
} else {
console.warn(noSpecMsg);
}
}
if (!symbols){
if (!symbols) {
symbols = find('.jasmine-symbol-summary');
}
symbols.appendChild(createDom('li', {
symbols.appendChild(
createDom('li', {
className: this.displaySpecInCorrectFormat(result),
id: 'spec_' + result.id,
title: result.fullName
}
));
})
);
if (result.status === 'failed') {
failures.push(failureDom(result));
}
addDeprecationWarnings(result);
addDeprecationWarnings(result, 'spec');
};
this.displaySpecInCorrectFormat = function(result) {
return noExpectations(result) ? 'jasmine-empty' : this.resultStatus(result.status);
return noExpectations(result) && result.status === 'passed'
? 'jasmine-empty'
: this.resultStatus(result.status);
};
this.resultStatus = function(status) {
if(status === 'excluded') {
return config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
if (status === 'excluded') {
return config().hideDisabled
? 'jasmine-excluded-no-display'
: 'jasmine-excluded';
}
return 'jasmine-' + status;
};
@@ -142,16 +160,33 @@ jasmineRequire.HtmlReporter = function(j$) {
var alert = find('.jasmine-alert');
var order = doneResult && doneResult.order;
var i;
alert.appendChild(createDom('span', {className: 'jasmine-duration'}, 'finished in ' + timer.elapsed() / 1000 + 's'));
alert.appendChild(
createDom(
'span',
{ className: 'jasmine-duration' },
'finished in ' + doneResult.totalTime / 1000 + 's'
)
);
banner.appendChild(optionsMenu(config()));
if (stateBuilder.specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + stateBuilder.specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedMessage =
'Ran ' +
stateBuilder.specsExecuted +
' of ' +
totalSpecsDefined +
' specs - run all';
var skippedLink = addToExistingQueryString('spec', '');
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)
createDom(
'span',
{ className: 'jasmine-bar jasmine-skipped' },
createDom(
'a',
{ href: skippedLink, title: 'Run all specs' },
skippedMessage
)
)
);
}
@@ -161,34 +196,66 @@ jasmineRequire.HtmlReporter = function(j$) {
var failed = stateBuilder.failureCount + globalFailures.length > 0;
if (totalSpecsDefined > 0 || failed) {
statusBarMessage += pluralize('spec', stateBuilder.specsExecuted) + ', ' + pluralize('failure', stateBuilder.failureCount);
if (stateBuilder.pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', stateBuilder.pendingSpecCount); }
statusBarMessage +=
pluralize('spec', stateBuilder.specsExecuted) +
', ' +
pluralize('failure', stateBuilder.failureCount);
if (stateBuilder.pendingSpecCount) {
statusBarMessage +=
', ' + pluralize('pending spec', stateBuilder.pendingSpecCount);
}
}
if (doneResult.overallStatus === 'passed') {
statusBarClassName += ' jasmine-passed ';
} else if (doneResult.overallStatus === 'incomplete') {
statusBarClassName += ' jasmine-incomplete ';
statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
statusBarMessage =
'Incomplete: ' +
doneResult.incompleteReason +
', ' +
statusBarMessage;
} else {
statusBarClassName += ' jasmine-failed ';
}
var seedBar;
if (order && order.random) {
seedBar = createDom('span', {className: 'jasmine-seed-bar'},
seedBar = createDom(
'span',
{ className: 'jasmine-seed-bar' },
', randomized with seed ',
createDom('a', {title: 'randomized with seed ' + order.seed, href: seedHref(order.seed)}, order.seed)
createDom(
'a',
{
title: 'randomized with seed ' + order.seed,
href: seedHref(order.seed)
},
order.seed
)
);
}
alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage, seedBar));
alert.appendChild(
createDom(
'span',
{ className: statusBarClassName },
statusBarMessage,
seedBar
)
);
var errorBarClassName = 'jasmine-bar jasmine-errored';
var afterAllMessagePrefix = 'AfterAll ';
for(i = 0; i < globalFailures.length; i++) {
alert.appendChild(createDom('span', {className: errorBarClassName}, globalFailureMessage(globalFailures[i])));
for (i = 0; i < globalFailures.length; i++) {
alert.appendChild(
createDom(
'span',
{ className: errorBarClassName },
globalFailureMessage(globalFailures[i])
)
);
}
function globalFailureMessage(failure) {
@@ -196,7 +263,9 @@ jasmineRequire.HtmlReporter = function(j$) {
var prefix = 'Error during loading: ' + failure.message;
if (failure.filename) {
return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
return (
prefix + ' in ' + failure.filename + ' line ' + failure.lineno
);
} else {
return prefix;
}
@@ -207,10 +276,29 @@ jasmineRequire.HtmlReporter = function(j$) {
addDeprecationWarnings(doneResult);
var warningBarClassName = 'jasmine-bar jasmine-warning';
for(i = 0; i < deprecationWarnings.length; i++) {
var warning = deprecationWarnings[i];
alert.appendChild(createDom('span', {className: warningBarClassName}, 'DEPRECATION: ' + warning));
for (i = 0; i < deprecationWarnings.length; i++) {
var context;
switch (deprecationWarnings[i].runnableType) {
case 'spec':
context = '(in spec: ' + deprecationWarnings[i].runnableName + ')';
break;
case 'suite':
context = '(in suite: ' + deprecationWarnings[i].runnableName + ')';
break;
default:
context = '';
}
alert.appendChild(
createDom(
'span',
{ className: 'jasmine-bar jasmine-warning' },
'DEPRECATION: ' + deprecationWarnings[i].message,
createDom('br'),
context
)
);
}
var results = find('.jasmine-results');
@@ -220,19 +308,37 @@ jasmineRequire.HtmlReporter = function(j$) {
if (failures.length) {
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-spec-list'},
createDom(
'span',
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
createDom('span', {}, 'Spec List | '),
createDom('a', {className: 'jasmine-failures-menu', href: '#'}, 'Failures')));
createDom(
'a',
{ className: 'jasmine-failures-menu', href: '#' },
'Failures'
)
)
);
alert.appendChild(
createDom('span', {className: 'jasmine-menu jasmine-bar jasmine-failure-list'},
createDom('a', {className: 'jasmine-spec-list-menu', href: '#'}, 'Spec List'),
createDom('span', {}, ' | Failures ')));
createDom(
'span',
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
createDom(
'a',
{ className: 'jasmine-spec-list-menu', href: '#' },
'Spec List'
),
createDom('span', {}, ' | Failures ')
)
);
find('.jasmine-failures-menu').onclick = function() {
setMenuModeTo('jasmine-failure-list');
return false;
};
find('.jasmine-spec-list-menu').onclick = function() {
setMenuModeTo('jasmine-spec-list');
return false;
};
setMenuModeTo('jasmine-failure-list');
@@ -247,17 +353,40 @@ jasmineRequire.HtmlReporter = function(j$) {
return this;
function failureDom(result) {
var failure =
createDom('div', {className: 'jasmine-spec-detail jasmine-failed'},
failureDescription(result, stateBuilder.currentParent),
createDom('div', {className: 'jasmine-messages'})
);
var failure = createDom(
'div',
{ className: 'jasmine-spec-detail jasmine-failed' },
failureDescription(result, stateBuilder.currentParent),
createDom('div', { className: 'jasmine-messages' })
);
var messages = failure.childNodes[1];
for (var i = 0; i < result.failedExpectations.length; i++) {
var expectation = result.failedExpectations[i];
messages.appendChild(createDom('div', {className: 'jasmine-result-message'}, expectation.message));
messages.appendChild(createDom('div', {className: 'jasmine-stack-trace'}, expectation.stack));
messages.appendChild(
createDom(
'div',
{ className: 'jasmine-result-message' },
expectation.message
)
);
messages.appendChild(
createDom(
'div',
{ className: 'jasmine-stack-trace' },
expectation.stack
)
);
}
if (result.failedExpectations.length === 0) {
messages.appendChild(
createDom(
'div',
{ className: 'jasmine-result-message' },
'Spec has no expectations'
)
);
}
return failure;
@@ -271,9 +400,20 @@ jasmineRequire.HtmlReporter = function(j$) {
continue;
}
if (resultNode.type === 'suite') {
var suiteListNode = createDom('ul', {className: 'jasmine-suite', id: 'suite-' + resultNode.result.id},
createDom('li', {className: 'jasmine-suite-detail jasmine-' + resultNode.result.status},
createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description)
var suiteListNode = createDom(
'ul',
{ className: 'jasmine-suite', id: 'suite-' + resultNode.result.id },
createDom(
'li',
{
className:
'jasmine-suite-detail jasmine-' + resultNode.result.status
},
createDom(
'a',
{ href: specHref(resultNode.result) },
resultNode.result.description
)
)
);
@@ -282,22 +422,34 @@ jasmineRequire.HtmlReporter = function(j$) {
}
if (resultNode.type === 'spec') {
if (domParent.getAttribute('class') !== 'jasmine-specs') {
specListNode = createDom('ul', {className: 'jasmine-specs'});
specListNode = createDom('ul', { className: 'jasmine-specs' });
domParent.appendChild(specListNode);
}
var specDescription = resultNode.result.description;
if(noExpectations(resultNode.result)) {
if (noExpectations(resultNode.result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if(resultNode.result.status === 'pending' && resultNode.result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + resultNode.result.pendingReason;
if (
resultNode.result.status === 'pending' &&
resultNode.result.pendingReason !== ''
) {
specDescription =
specDescription +
' PENDING WITH MESSAGE: ' +
resultNode.result.pendingReason;
}
specListNode.appendChild(
createDom('li', {
createDom(
'li',
{
className: 'jasmine-' + resultNode.result.status,
id: 'spec-' + resultNode.result.id
},
createDom('a', {href: specHref(resultNode.result)}, specDescription)
createDom(
'a',
{ href: specHref(resultNode.result) },
specDescription
)
)
);
}
@@ -305,37 +457,69 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function optionsMenu(config) {
var optionsMenuDom = createDom('div', { className: 'jasmine-run-options' },
var optionsMenuDom = createDom(
'div',
{ className: 'jasmine-run-options' },
createDom('span', { className: 'jasmine-trigger' }, 'Options'),
createDom('div', { className: 'jasmine-payload' },
createDom('div', { className: 'jasmine-stop-on-failure' },
createDom(
'div',
{ className: 'jasmine-payload' },
createDom(
'div',
{ className: 'jasmine-stop-on-failure' },
createDom('input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-fail-fast' }, 'stop execution on spec failure')),
createDom('div', { className: 'jasmine-throw-failures' },
createDom(
'label',
{ className: 'jasmine-label', for: 'jasmine-fail-fast' },
'stop execution on spec failure'
)
),
createDom(
'div',
{ className: 'jasmine-throw-failures' },
createDom('input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-throw-failures' }, 'stop spec on expectation failure')),
createDom('div', { className: 'jasmine-random-order' },
createDom(
'label',
{ className: 'jasmine-label', for: 'jasmine-throw-failures' },
'stop spec on expectation failure'
)
),
createDom(
'div',
{ className: 'jasmine-random-order' },
createDom('input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-random-order' }, 'run tests in random order')),
createDom('div', { className: 'jasmine-hide-disabled' },
createDom(
'label',
{ className: 'jasmine-label', for: 'jasmine-random-order' },
'run tests in random order'
)
),
createDom(
'div',
{ className: 'jasmine-hide-disabled' },
createDom('input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}),
createDom('label', { className: 'jasmine-label', 'for': 'jasmine-hide-disabled' }, 'hide disabled tests'))
createDom(
'label',
{ className: 'jasmine-label', for: 'jasmine-hide-disabled' },
'hide disabled tests'
)
)
)
);
@@ -345,13 +529,17 @@ jasmineRequire.HtmlReporter = function(j$) {
navigateWithNewParam('failFast', !config.failFast);
};
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
var throwCheckbox = optionsMenuDom.querySelector(
'#jasmine-throw-failures'
);
throwCheckbox.checked = config.oneFailurePerSpec;
throwCheckbox.onclick = function() {
navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
};
var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
var randomCheckbox = optionsMenuDom.querySelector(
'#jasmine-random-order'
);
randomCheckbox.checked = config.random;
randomCheckbox.onclick = function() {
navigateWithNewParam('random', !config.random);
@@ -369,7 +557,10 @@ jasmineRequire.HtmlReporter = function(j$) {
optionsTrigger.onclick = function() {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
optionsPayload.className = optionsPayload.className.replace(
isOpen,
''
);
} else {
optionsPayload.className += ' jasmine-open';
}
@@ -379,14 +570,24 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function failureDescription(result, suite) {
var wrapper = createDom('div', {className: 'jasmine-description'},
createDom('a', {title: result.description, href: specHref(result)}, result.description)
var wrapper = createDom(
'div',
{ className: 'jasmine-description' },
createDom(
'a',
{ title: result.description, href: specHref(result) },
result.description
)
);
var suiteLink;
while (suite && suite.parent) {
wrapper.insertBefore(createTextNode(' > '), wrapper.firstChild);
suiteLink = createDom('a', {href: suiteHref(suite)}, suite.result.description);
suiteLink = createDom(
'a',
{ href: suiteHref(suite) },
suite.result.description
);
wrapper.insertBefore(suiteLink, wrapper.firstChild);
suite = suite.parent;
@@ -406,12 +607,16 @@ jasmineRequire.HtmlReporter = function(j$) {
return addToExistingQueryString('spec', els.join(' '));
}
function addDeprecationWarnings(result) {
function addDeprecationWarnings(result, runnableType) {
if (result && result.deprecationWarnings) {
for(var i = 0; i < result.deprecationWarnings.length; i++) {
for (var i = 0; i < result.deprecationWarnings.length; i++) {
var warning = result.deprecationWarnings[i].message;
if (!j$.util.arrayContains(warning)) {
deprecationWarnings.push(warning);
deprecationWarnings.push({
message: warning,
runnableName: result.fullName,
runnableType: runnableType
});
}
}
}
@@ -425,7 +630,7 @@ jasmineRequire.HtmlReporter = function(j$) {
// return the reporter
var oldReporter = find('');
if(oldReporter) {
if (oldReporter) {
getContainer().removeChild(oldReporter);
}
}
@@ -457,7 +662,7 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function pluralize(singular, count) {
var word = (count == 1 ? singular : singular + 's');
var word = count == 1 ? singular : singular + 's';
return '' + count + ' ' + word;
}
@@ -479,8 +684,13 @@ jasmineRequire.HtmlReporter = function(j$) {
}
function noExpectations(result) {
return (result.failedExpectations.length + result.passedExpectations.length) === 0 &&
result.status === 'passed';
var allExpectations =
result.failedExpectations.length + result.passedExpectations.length;
return (
allExpectations === 0 &&
(result.status === 'passed' || result.status === 'failed')
);
}
function hasActiveSpec(resultNode) {

View File

@@ -1,6 +1,9 @@
jasmineRequire.HtmlSpecFilter = function() {
function HtmlSpecFilter(options) {
var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
var filterString =
options &&
options.filterString() &&
options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
var filterPattern = new RegExp(filterString);
this.matches = function(specName) {

View File

@@ -1,8 +1,10 @@
jasmineRequire.QueryString = function() {
function QueryString(options) {
this.navigateWithNewParam = function(key, value) {
options.getWindowLocation().search = this.fullStringWithNewParam(key, value);
options.getWindowLocation().search = this.fullStringWithNewParam(
key,
value
);
};
this.fullStringWithNewParam = function(key, value) {
@@ -20,7 +22,9 @@ jasmineRequire.QueryString = function() {
function toQueryString(paramMap) {
var qStrPairs = [];
for (var prop in paramMap) {
qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop]));
qStrPairs.push(
encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])
);
}
return '?' + qStrPairs.join('&');
}
@@ -44,7 +48,6 @@ jasmineRequire.QueryString = function() {
return paramMap;
}
}
return QueryString;

View File

@@ -27,6 +27,7 @@ body {
}
.jasmine_html-reporter {
width: 100%;
background-color: $page-background-color;
padding: 5px;
margin: -8px;
@@ -305,7 +306,7 @@ body {
&.jasmine-excluded a {
color: $neutral-color;
}
}
}
}
@@ -329,7 +330,7 @@ body {
&.jasmine-excluded a:before {
content: $passing-mark + $space;
}
}
}
}

View File

@@ -1,3 +1,5 @@
var jasmineRequire = window.jasmineRequire || require('./jasmine.js');
jasmineRequire.html = function(j$) {
j$.ResultsNode = jasmineRequire.ResultsNode();
j$.HtmlReporter = jasmineRequire.HtmlReporter(j$);