3
Copyright (c) 2008-2015 Pivotal Labs
3
Copyright (c) 2008-2016 Pivotal Labs
5
5
Permission is hereby granted, free of charge, to any person obtaining
6
6
a copy of this software and associated documentation files (the
24
24
var getJasmineRequireObj = (function (jasmineGlobal) {
25
25
var jasmineRequire;
27
if (typeof module !== 'undefined' && module.exports) {
27
if (typeof module !== 'undefined' && module.exports && typeof exports !== 'undefined') {
28
28
if (typeof global !== 'undefined') {
29
29
jasmineGlobal = global;
48
48
jRequire.base(j$, jasmineGlobal);
49
49
j$.util = jRequire.util();
50
50
j$.errors = jRequire.errors();
51
j$.formatErrorMsg = jRequire.formatErrorMsg();
51
52
j$.Any = jRequire.Any(j$);
52
53
j$.Anything = jRequire.Anything(j$);
53
j$.CallTracker = jRequire.CallTracker();
54
j$.CallTracker = jRequire.CallTracker(j$);
54
55
j$.MockDate = jRequire.MockDate();
55
56
j$.Clock = jRequire.Clock();
56
57
j$.DelayedFunctionScheduler = jRequire.DelayedFunctionScheduler();
67
68
j$.ReportDispatcher = jRequire.ReportDispatcher();
68
69
j$.Spec = jRequire.Spec(j$);
69
70
j$.SpyRegistry = jRequire.SpyRegistry(j$);
70
j$.SpyStrategy = jRequire.SpyStrategy();
71
j$.SpyStrategy = jRequire.SpyStrategy(j$);
71
72
j$.StringMatching = jRequire.StringMatching(j$);
72
73
j$.Suite = jRequire.Suite(j$);
73
74
j$.Timer = jRequire.Timer();
145
148
return j$.isA_('Number', value);
151
j$.isFunction_ = function(value) {
152
return j$.isA_('Function', value);
148
155
j$.isA_ = function(typeName, value) {
149
156
return Object.prototype.toString.apply(value) === '[object ' + typeName + ']';
156
163
j$.fnNameFor = function(func) {
157
return func.name || func.toString().match(/^\s*function\s*(\w*)\s*\(/)[1];
168
var matches = func.toString().match(/^\s*function\s*(\w*)\s*\(/);
169
return matches ? matches[1] : '<anonymous>';
160
172
j$.any = function(clazz) {
516
528
var realClearTimeout = j$.getGlobal().clearTimeout;
517
529
this.clock = new j$.Clock(global, function () { return new j$.DelayedFunctionScheduler(); }, new j$.MockDate(global));
519
var runnableLookupTable = {};
520
531
var runnableResources = {};
522
533
var currentSpec = null;
628
639
var getSpecName = function(spec, suite) {
629
return suite.getFullName() + ' ' + spec.description;
640
var fullName = [spec.description],
641
suiteFullName = suite.getFullName();
643
if (suiteFullName !== '') {
644
fullName.unshift(suiteFullName);
646
return fullName.join(' ');
632
649
// TODO: we may just be able to pass in the fn instead of wrapping here
703
720
id: getNextSuiteId(),
704
721
description: 'Jasmine__TopLevel__Suite',
705
queueRunner: queueRunnerFactory
722
expectationFactory: expectationFactory,
723
expectationResultFactory: expectationResultFactory
707
runnableLookupTable[topSuite.id] = topSuite;
708
725
defaultResourcesForRunnable(topSuite.id);
709
726
currentDeclarationSuite = topSuite;
755
772
totalSpecsDefined: totalSpecsDefined
775
currentlyExecutingSuites.push(topSuite);
758
777
processor.execute(function() {
778
clearResourcesForRunnable(topSuite.id);
779
currentlyExecutingSuites.pop();
759
781
reporter.jasmineDone({
783
failedExpectations: topSuite.result.failedExpectations
766
789
reporter.addReporter(reporterToAdd);
792
this.provideFallbackReporter = function(reporterToAdd) {
793
reporter.provideFallbackReporter(reporterToAdd);
796
this.clearReporters = function() {
797
reporter.clearReporters();
769
800
var spyRegistry = new j$.SpyRegistry({currentSpies: function() {
770
801
if(!currentRunnable()) {
771
802
throw new Error('Spies must be created in a before function or a spec');
773
804
return runnableResources[currentRunnable().id].spies;
807
this.allowRespy = function(allow){
808
spyRegistry.allowRespy(allow);
776
811
this.spyOn = function() {
777
812
return spyRegistry.spyOn.apply(spyRegistry, arguments);
788
823
throwOnExpectationFailure: throwOnExpectationFailure
791
runnableLookupTable[suite.id] = suite;
795
829
this.describe = function(description, specDefinitions) {
796
830
var suite = suiteFactory(description);
797
831
if (specDefinitions.length > 0) {
798
throw new Error('describe does not expect a done parameter');
832
throw new Error('describe does not expect any arguments');
800
834
if (currentDeclarationSuite.markedPending) {
1080
1112
return JsApiReporter;
1083
getJasmineRequireObj().CallTracker = function() {
1115
getJasmineRequireObj().CallTracker = function(j$) {
1085
1117
function CallTracker() {
1086
1118
var calls = [];
1121
function argCloner(context) {
1122
var clonedArgs = [];
1123
var argsAsArray = j$.util.argsToArray(context.args);
1124
for(var i = 0; i < argsAsArray.length; i++) {
1125
if(Object.prototype.toString.apply(argsAsArray[i]).match(/^\[object/)) {
1126
clonedArgs.push(j$.util.clone(argsAsArray[i]));
1128
clonedArgs.push(argsAsArray[i]);
1131
context.args = clonedArgs;
1088
1134
this.track = function(context) {
1135
if(opts.cloneArgs) {
1089
1138
calls.push(context);
1216
1270
self.tick = function(millis) {
1217
1271
if (installed) {
1218
mockDate.tick(millis);
1219
delayedFunctionScheduler.tick(millis);
1272
delayedFunctionScheduler.tick(millis, function(millis) { mockDate.tick(millis); });
1221
1274
throw new Error('Mock clock is not installed, use jasmine.clock().install()');
1274
1327
var currentTime = 0;
1275
1328
var delayedFnCount = 0;
1277
self.tick = function(millis) {
1330
self.tick = function(millis, tickDate) {
1278
1331
millis = millis || 0;
1279
1332
var endTime = currentTime + millis;
1281
runScheduledFunctions(endTime);
1334
runScheduledFunctions(endTime, tickDate);
1282
1335
currentTime = endTime;
1384
function runScheduledFunctions(endTime) {
1437
function runScheduledFunctions(endTime, tickDate) {
1438
tickDate = tickDate || function() {};
1385
1439
if (scheduledLookup.length === 0 || scheduledLookup[0] > endTime) {
1440
tickDate(endTime - currentTime);
1390
currentTime = scheduledLookup.shift();
1445
var newCurrentTime = scheduledLookup.shift();
1446
tickDate(newCurrentTime - currentTime);
1448
currentTime = newCurrentTime;
1392
1450
var funcsToRun = scheduledFunctions[currentTime];
1393
1451
delete scheduledFunctions[currentTime];
1406
1464
// scheduled in a funcToRun from forcing an extra iteration
1407
1465
currentTime !== endTime &&
1408
1466
scheduledLookup[0] <= endTime);
1468
// ran out of functions to call, but still time left on the clock
1469
if (currentTime !== endTime) {
1470
tickDate(endTime - currentTime);
1955
2019
var reporters = [];
2020
var fallbackReporter = null;
1957
2022
this.addReporter = function(reporter) {
1958
2023
reporters.push(reporter);
2026
this.provideFallbackReporter = function(reporter) {
2027
fallbackReporter = reporter;
2030
this.clearReporters = function() {
1963
2036
function dispatch(method, args) {
2037
if (reporters.length === 0 && fallbackReporter !== null) {
2038
reporters.push(fallbackReporter);
1964
2040
for (var i = 0; i < reporters.length; i++) {
1965
2041
var reporter = reporters[i];
1966
2042
if (reporter[method]) {
1977
2053
getJasmineRequireObj().SpyRegistry = function(j$) {
2055
var getErrorMsg = j$.formatErrorMsg('<spyOn>', 'spyOn(<object>, <methodName>)');
1979
2057
function SpyRegistry(options) {
1980
2058
options = options || {};
1981
2059
var currentSpies = options.currentSpies || function() { return []; };
2061
this.allowRespy = function(allow){
1983
2065
this.spyOn = function(obj, methodName) {
1984
2067
if (j$.util.isUndefined(obj)) {
1985
throw new Error('spyOn could not find an object to spy upon for ' + methodName + '()');
2068
throw new Error(getErrorMsg('could not find an object to spy upon for ' + methodName + '()'));
1988
2071
if (j$.util.isUndefined(methodName)) {
1989
throw new Error('No method name supplied');
2072
throw new Error(getErrorMsg('No method name supplied'));
1992
2075
if (j$.util.isUndefined(obj[methodName])) {
1993
throw new Error(methodName + '() method does not exist');
2076
throw new Error(getErrorMsg(methodName + '() method does not exist'));
1996
if (obj[methodName] && j$.isSpy(obj[methodName])) {
1997
//TODO?: should this return the current spy? Downside: may cause user confusion about spy state
1998
throw new Error(methodName + ' has already been spied upon');
2079
if (obj[methodName] && j$.isSpy(obj[methodName]) ) {
2080
if ( !!this.respy ){
2081
return obj[methodName];
2083
throw new Error(getErrorMsg(methodName + ' has already been spied upon'));
2001
2087
var descriptor;
2008
2094
if (descriptor && !(descriptor.writable || descriptor.set)) {
2009
throw new Error(methodName + ' is not declared writable or has no setter');
2012
var spy = j$.createSpy(methodName, obj[methodName]);
2095
throw new Error(getErrorMsg(methodName + ' is not declared writable or has no setter'));
2098
var originalMethod = obj[methodName],
2099
spiedMethod = j$.createSpy(methodName, originalMethod),
2102
if (Object.prototype.hasOwnProperty.call(obj, methodName)) {
2103
restoreStrategy = function() {
2104
obj[methodName] = originalMethod;
2107
restoreStrategy = function() {
2108
if (!delete obj[methodName]) {
2109
obj[methodName] = originalMethod;
2014
2114
currentSpies().push({
2017
methodName: methodName,
2018
originalValue: obj[methodName]
2115
restoreObjectToOriginalState: restoreStrategy
2021
obj[methodName] = spy;
2118
obj[methodName] = spiedMethod;
2026
2123
this.clearSpies = function() {
2027
2124
var spies = currentSpies();
2028
for (var i = 0; i < spies.length; i++) {
2125
for (var i = spies.length - 1; i >= 0; i--) {
2029
2126
var spyEntry = spies[i];
2030
spyEntry.baseObj[spyEntry.methodName] = spyEntry.originalValue;
2127
spyEntry.restoreObjectToOriginalState();
2128
2228
Suite.prototype.getFullName = function() {
2129
var fullName = this.description;
2130
for (var parentSuite = this.parentSuite; parentSuite; parentSuite = parentSuite.parentSuite) {
2230
for (var parentSuite = this; parentSuite; parentSuite = parentSuite.parentSuite) {
2131
2231
if (parentSuite.parentSuite) {
2132
fullName = parentSuite.description + ' ' + fullName;
2232
fullName.unshift(parentSuite.description);
2235
return fullName.join(' ');
2138
2238
Suite.prototype.disable = function() {
2666
2766
ExpectationFailed: ExpectationFailed
2769
getJasmineRequireObj().formatErrorMsg = function() {
2770
function generateErrorMsg(domain, usage) {
2771
var usageDefinition = usage ? '\nUsage: ' + usage : '';
2773
return function errorMsg(msg) {
2774
return domain + ' : ' + msg + usageDefinition;
2778
return generateErrorMsg;
2669
2781
getJasmineRequireObj().matchersUtil = function(j$) {
2670
2782
// TODO: what to do about jasmine.pp not being inject? move to JSON.stringify? gut PrettyPrinter?
2830
2942
// Recursively compare objects and arrays.
2831
2943
// Compare array lengths to determine if a deep comparison is necessary.
2832
if (className == '[object Array]' && a.length !== b.length) {
2944
if (className == '[object Array]') {
2946
if (size !== b.length) {
2951
result = eq(a[size], b[size], aStack, bStack, customTesters);
2837
2958
// Objects with different constructors are not equivalent, but `Object`s
2838
2959
// or `Array`s from different frames are.
2839
if (className !== '[object Array]') {
2840
var aCtor = a.constructor, bCtor = b.constructor;
2841
if (aCtor !== bCtor && !(isFunction(aCtor) && aCtor instanceof aCtor &&
2842
isFunction(bCtor) && bCtor instanceof bCtor)) {
2846
// Deep compare objects.
2847
for (var key in a) {
2849
// Count the expected number of properties.
2851
// Deep compare each member.
2852
if (!(result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters))) { break; }
2855
// Ensure that both objects contain the same number of properties.
2858
if (has(b, key) && !(size--)) { break; }
2960
var aCtor = a.constructor, bCtor = b.constructor;
2961
if (aCtor !== bCtor && !(isObjectConstructor(aCtor) &&
2962
isObjectConstructor(bCtor))) {
2967
// Deep compare objects.
2968
var aKeys = keys(a, className == '[object Array]'), key;
2969
size = aKeys.length;
2971
// Ensure that both objects contain the same number of properties before comparing deep equality.
2972
if (keys(b, className == '[object Array]').length !== size) { return false; }
2976
// Deep compare each member
2977
result = has(b, key) && eq(a[key], b[key], aStack, bStack, customTesters);
2863
2983
// Remove the first object from the stack of traversed objects.
2869
function has(obj, key) {
2870
return Object.prototype.hasOwnProperty.call(obj, key);
2873
function isFunction(obj) {
2874
return typeof obj === 'function';
2989
function keys(obj, isArray) {
2990
var allKeys = Object.keys ? Object.keys(obj) :
2993
for (var key in o) {
3006
if (allKeys.length === 0) {
3010
for (var x = 0; x < allKeys.length; x++) {
3011
if (!allKeys[x].match(/^[0-9]+$/)) {
3012
extraKeys.push(allKeys[x]);
3020
function has(obj, key) {
3021
return Object.prototype.hasOwnProperty.call(obj, key);
3024
function isFunction(obj) {
3025
return typeof obj === 'function';
3028
function isObjectConstructor(ctor) {
3029
// aCtor instanceof aCtor is true for the Object and Function
3030
// constructors (since a constructor is-a Function and a function is-a
3031
// Object). We don't just compare ctor === Object because the constructor
3032
// might come from a different frame with different globals.
3033
return isFunction(ctor) && ctor instanceof ctor;
3114
getJasmineRequireObj().toBeGreaterThanOrEqual = function() {
3116
function toBeGreaterThanOrEqual() {
3118
compare: function(actual, expected) {
3120
pass: actual >= expected
3126
return toBeGreaterThanOrEqual;
2956
3129
getJasmineRequireObj().toBeLessThan = function() {
2957
3130
function toBeLessThan() {
2968
3141
return toBeLessThan;
3143
getJasmineRequireObj().toBeLessThanOrEqual = function() {
3144
function toBeLessThanOrEqual() {
3147
compare: function(actual, expected) {
3149
pass: actual <= expected
3155
return toBeLessThanOrEqual;
2970
3158
getJasmineRequireObj().toBeNaN = function(j$) {
2972
3160
function toBeNaN() {
3076
3264
getJasmineRequireObj().toHaveBeenCalled = function(j$) {
3266
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalled>', 'expect(<spyObj>).toHaveBeenCalled()');
3078
3268
function toHaveBeenCalled() {
3080
3270
compare: function(actual) {
3081
3271
var result = {};
3083
3273
if (!j$.isSpy(actual)) {
3084
throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
3274
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
3087
3277
if (arguments.length > 1) {
3088
throw new Error('toHaveBeenCalled does not take arguments, use toHaveBeenCalledWith');
3278
throw new Error(getErrorMsg('Does not take arguments, use toHaveBeenCalledWith'));
3091
3281
result.pass = actual.calls.any();
3105
3295
getJasmineRequireObj().toHaveBeenCalledTimes = function(j$) {
3297
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledTimes>', 'expect(<spyObj>).toHaveBeenCalledTimes(<Number>)');
3107
3299
function toHaveBeenCalledTimes() {
3109
3301
compare: function(actual, expected) {
3110
3302
if (!j$.isSpy(actual)) {
3111
throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
3303
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
3114
3306
var args = Array.prototype.slice.call(arguments, 0),
3115
3307
result = { pass: false };
3118
throw new Error('Expected times failed is required as an argument.');
3309
if (!j$.isNumber_(expected)){
3310
throw new Error(getErrorMsg('The expected times failed is a required argument and must be a number.'));
3121
3313
actual = args[0];
3136
3328
getJasmineRequireObj().toHaveBeenCalledWith = function(j$) {
3330
var getErrorMsg = j$.formatErrorMsg('<toHaveBeenCalledWith>', 'expect(<spyObj>).toHaveBeenCalledWith(...arguments)');
3138
3332
function toHaveBeenCalledWith(util, customEqualityTesters) {
3140
3334
compare: function() {
3144
3338
result = { pass: false };
3146
3340
if (!j$.isSpy(actual)) {
3147
throw new Error('Expected a spy, but got ' + j$.pp(actual) + '.');
3341
throw new Error(getErrorMsg('Expected a spy, but got ' + j$.pp(actual) + '.'));
3150
3344
if (!actual.calls.any()) {
3170
3364
getJasmineRequireObj().toMatch = function(j$) {
3366
var getErrorMsg = j$.formatErrorMsg('<toMatch>', 'expect(<expectation>).toMatch(<string> || <regexp>)');
3172
3368
function toMatch() {
3174
3370
compare: function(actual, expected) {
3175
3371
if (!j$.isString_(expected) && !j$.isA_('RegExp', expected)) {
3176
throw new Error('Expected is not a String or a RegExp');
3372
throw new Error(getErrorMsg('Expected is not a String or a RegExp'));
3179
3375
var regexp = new RegExp(expected);
3238
3436
getJasmineRequireObj().toThrowError = function(j$) {
3438
var getErrorMsg = j$.formatErrorMsg('<toThrowError>', 'expect(function() {<expectation>}).toThrowError(<ErrorConstructor>, <message>)');
3239
3440
function toThrowError () {
3241
3442
compare: function(actual) {
3247
3448
if (typeof actual != 'function') {
3248
throw new Error('Actual is not a Function');
3449
throw new Error(getErrorMsg('Actual is not a Function'));
3251
3452
var errorMatcher = getMatcher.apply(null, arguments);
3301
3502
errorType = arguments[1];
3302
3503
expected = arguments[2];
3303
3504
if (!isAnErrorType(errorType)) {
3304
throw new Error('Expected error type is not an Error.');
3505
throw new Error(getErrorMsg('Expected error type is not an Error.'));
3308
3509
if (expected && !isStringOrRegExp(expected)) {
3309
3510
if (errorType) {
3310
throw new Error('Expected error message is not a string or RegExp.');
3511
throw new Error(getErrorMsg('Expected error message is not a string or RegExp.'));
3312
throw new Error('Expected is not an Error, string, or RegExp.');
3513
throw new Error(getErrorMsg('Expected is not an Error, string, or RegExp.'));