Compare commits

..

40 Commits

Author SHA1 Message Date
Gregg Van Hove
b256741bec bump version to 2.7.0 2017-07-27 17:47:20 -07:00
Gregg Van Hove
1d4a2b5c22 Merge branch 'user-context' of https://github.com/darthjee/jasmine into darthjee-user-context
- Merges #1400 from @darthjee
2017-07-26 17:18:02 -07:00
darthjee
b0aac6b852 Add class UserContext 2017-07-26 23:40:22 +02:00
Gregg Van Hove
543e056056 Merge branch 'jberney-master'
- Merges #1399 from @jberney
2017-07-24 17:13:21 -07:00
Jonathan
7dfc5f506c Send unfocused tests through the same queue as focused tests 2017-07-23 09:01:15 -07:00
Gregg Van Hove
4cce7263c4 Update github issue and PR templates 2017-07-22 09:34:58 -07:00
Gregg Van Hove
31164106e5 Get the casing right for IE8 2017-07-18 21:51:32 -07:00
Gregg Van Hove
f71218a44b Allow IE8 to be weird when pretty printing 2017-07-18 21:07:38 -07:00
Gregg Van Hove
22e9d6df20 PrettyPrinter allows an object to have a toString that isn't a function
- Fixes #1389
2017-07-17 22:01:06 -07:00
Alpha Chen
aa72b0b7cf Simplified rounding code in toBeCloseTo
Signed-off-by: Steve Gravrock <sgravrock@pivotal.io>
2017-06-26 10:22:54 -07:00
Alpha Chen
9f3952ff87 Merge branch 'vanduynslagerp-fix-tobecloseto'
- Fixes #1382

Signed-off-by: Alpha Chen <achen@pivotal.io>
2017-06-26 10:21:13 -07:00
Pierre Vanduynslager
c604012793 Fix rounding in toBeCloseTo 2017-06-25 16:59:24 -04:00
Gregg Van Hove
6aa069d586 IE 8&9 use setTimeout to clearStack so mock clock gets tricky 2017-06-20 10:29:19 -07:00
Steve Gravrock
585287b9d6 When stop on failure is enabled, skip subsequent it() and beforeEach().
Note: afterEach() functions are still run, because skipping them is
highly likely to pollute specs that run after the failure.

[Finishes #92252330]

- Fixes #577
- Fixes #807
2017-06-19 13:48:43 -07:00
Gregg Van Hove
de862f8133 Only clear out the spec param for Run all link
- Fixes #1369
2017-06-16 14:07:40 -07:00
Gregg Van Hove
4e3ae726aa Bump version to 2.6.4 2017-06-16 13:44:43 -07:00
Steve Gravrock
9ee7b4ee0b Don't setTimeout() every time the stack is cleared via MessageChannel() 2017-06-16 09:58:41 -07:00
Gregg Van Hove
2e737f50ca Don't use window 2017-06-15 14:32:18 -07:00
Gregg Van Hove
c60d669940 Break into a setTimeout every once in a while
- Allows the CPU to run other things that used the real `setTimeout`

- Fixes #1327
- See #1334
- Fixes jasmine/gulp-jasmine-browser#48
2017-06-15 14:24:40 -07:00
Gregg Van Hove
4c491b2dc0 Pretty printer will now use MAX_PRETTY_PRINT_ARRAY_LENGTH for objects
- Fixes #1291
- Fixes #1360
2017-06-14 13:36:35 -07:00
Gregg Van Hove
f9d1e2f280 Merge branch 'EsrefDurna-master'
- Merges #1368 from @EsrefDurna
2017-06-12 14:03:11 -07:00
Esref Durna
270475bc61 updated package glob from 7.0.5 to 7.1.2
Npm link :  https://www.npmjs.com/package/glob
 Repository link : https://github.com/isaacs/node-glob/releases
2017-06-12 00:35:07 +00:00
Gregg Van Hove
acb9989178 Merge branch 'patch-1' of https://github.com/kant/jasmine into kant-patch-1
- Fix bower.json url to be https instead of http
- Merges #1365 from @kant
2017-06-07 14:22:24 -07:00
Gregg Van Hove
1fe1bbb6ed Merge branch 'master' of https://github.com/beatrichartz/jasmine into beatrichartz-master
- Merges #1362 from @beatrichartz
2017-06-07 14:16:48 -07:00
Gregg Van Hove
994878e6f6 bump version to 2.6.3
- cherry-pick release notes, etc.
2017-06-07 14:15:21 -07:00
Steve Gravrock
f7c160d716 Fixed HTML snippet in README
Closes #1366.
2017-06-06 15:57:45 -07:00
Gregg Van Hove
578f63b9bd Make sure the queue runner goes async for async specs
- Even if `done` is called synchronously.

See #1327 #1334 jasmine/gulp-jasmine-browser#48
2017-06-06 14:29:02 -07:00
Darío Hereñú
b1190eefb9 Minor fix 2017-06-04 00:40:53 -03:00
Beat Richartz
271908a2c4 Fail when one of the arguments passed into toBeCloseTo matcher is null 2017-06-02 15:36:39 +01:00
Gregg Van Hove
3372af1cf1 Merge branch 'seed-reporting' of https://github.com/sgravrock/jasmine into sgravrock-seed-reporting
- Merges #1348 from @sgravrock
2017-05-23 14:12:49 -07:00
Gregg Van Hove
d355fa0806 Don't tick extra. It's breaking IE 8 & 9 2017-05-22 14:27:08 -07:00
Steve Gravrock
56a79bef98 Use a less ancient Node on Travis CI 2017-05-19 15:47:54 -07:00
Gregg Van Hove
2ea4e9507c Merge branch 'map-support' of https://github.com/rmehlinger/jasmine into rmehlinger-map-support
- Merges #1340 from @rmehlinger
- Fixes #1257
2017-05-19 14:19:14 -07:00
Gregg Van Hove
c848a66faa Merge branch 'promises' of https://github.com/sgravrock/jasmine into sgravrock-promises
- Merges #1356 from @sgravrock
- Fixes #1336
- Fixes #1270
- Fixes #1350
- Fixes #1320
2017-05-19 14:03:21 -07:00
Gregg Van Hove
99fd7ddb88 Update python release instructions
- so I don't have search my bash history
2017-05-17 17:35:23 -07:00
Steve Gravrock
9672689d40 Added support for ES2017 async functions 2017-05-12 14:42:14 -07:00
Steve Gravrock
a237ac5386 Added support for async before/it/after functions that return promises 2017-05-11 14:31:09 -07:00
Steve Gravrock
88763012e4 Unified async and async queueable function running code 2017-05-10 10:14:47 -07:00
Steve Gravrock
e6a7932ec1 Report the random seed at the beginning and end of execution
This allows reporters to provide the seed to the user even in cases
where Jasmine crashes before completing.
2017-05-08 12:09:17 -07:00
rmehlinger
5ee03f02ed Add ES6 map support to Jasmine 2017-05-01 00:12:48 -07:00
42 changed files with 1573 additions and 300 deletions

View File

@@ -1,17 +1,44 @@
### Are you creating an issue in the correct repository?
## Are you creating an issue in the correct repository?
- When in doubt, create an issue here.
- If you have an issue with the Jasmine docs, file an issue in the docs repo
here: https://github.com/jasmine/jasmine.github.io
- This repository is for the core Jasmine framework
- If you are using a test runner that wraps Jasmine (Jasmine npm, karma, etc),
consider filing an issue with that library if appropriate
- If you are using a test runner that wraps Jasmine, consider filing an issue with that library if appropriate:
- [Jasmine npm](https://github.com/jasmine/jasmine-npm/issues)
- [Jasmine gem](https://github.com/jasmine/jasmine-gem/issues)
- [Jasmine py](https://github.com/jasmine/jasmine-py/issues)
- [Gulp Jasmine Browser](https://github.com/jasmine/gulp-jasmine-browser/issues)
- [Karma](https://github.com/karma-runner/karma/issues)
- [Grunt Contrib Jasmine](https://github.com/gruntjs/grunt-contrib-jasmine/issues)
### When submitting an issue, please answer the following:
<!--- Provide a general summary of the issue in the Title above -->
- What version are you using?
- What environment are you running Jasmine in (node, browser, etc)?
- How are you running Jasmine (standalone, npm, karma, etc)?
- If possible, include an example spec that demonstrates your issue.
## Expected Behavior
<!--- If you're describing a bug, tell us what should happen -->
<!--- If you're suggesting a change/improvement, tell us how it should work -->
Thanks for using Jasmine!
## Current Behavior
<!--- If describing a bug, tell us what happens instead of the expected behavior -->
<!--- If suggesting a change/improvement, explain the difference from current behavior -->
## Possible Solution
<!--- Not obligatory, but suggest a fix/reason for the bug, -->
<!--- or ideas how to implement the addition or change -->
## Suite that reproduces the behavior (for bugs)
<!--- Provide a sample suite that reproduces the bug. -->
```javascript
describe("sample", function() {
});
```
## Context
<!--- How has this issue affected you? What are you trying to accomplish? -->
<!--- Providing context helps us come up with a solution that is most useful in the real world -->
## Your Environment
<!--- Include as many relevant details about the environment you experienced the bug in -->
* Version used:
* Environment name and version (e.g. Chrome 39, node.js 5.4):
* Operating System and version (desktop or mobile):
* Link to your project:

30
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,30 @@
<!--- Provide a general summary of your changes in the Title above -->
## Description
<!--- Describe your changes in detail -->
## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
<!--- If it fixes an open issue, please link to the issue here. -->
## How Has This Been Tested?
<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran to -->
<!--- see how your change affects other areas of the code, etc. -->
## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

View File

@@ -43,12 +43,12 @@ To install Jasmine standalone on your local box (where **_{#.#.#}_** below is su
Add the following to your HTML file:
```html
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-core/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-core/jasmine.css">
<link rel="shortcut icon" type="image/png" href="jasmine/lib/jasmine-{#.#.#}/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="jasmine/lib/jasmine-{#.#.#}/jasmine.css">
<script type="text/javascript" src="jasmine/lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-core/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-core/boot.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/jasmine-html.js"></script>
<script type="text/javascript" src="jasmine/lib/jasmine-{#.#.#}/boot.js"></script>
```
## Supported environments

View File

@@ -40,7 +40,10 @@ When ready to release - specs are all green and the stories are done:
### Release the Python egg
1. `python setup.py register sdist upload` You will need pypi credentials to upload the egg.
Install [twine](https://github.com/pypa/twine)
1. `python setup.py sdist`
1. `twine upload dist/jasmine-core-<version>.tar.gz` You will need pypi credentials to upload the egg.
### Release the Ruby gem

View File

@@ -1,6 +1,6 @@
{
"name": "jasmine-core",
"homepage": "http://jasmine.github.io",
"homepage": "https://jasmine.github.io",
"authors": [
"slackersoft <gregg@slackersoft.net>"
],

View File

@@ -210,7 +210,7 @@ jasmineRequire.HtmlReporter = function(j$) {
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = order && order.random ? '?random=true' : '?';
var skippedLink = addToExistingQueryString('spec', '');
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)

View File

@@ -71,6 +71,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(j$);
j$.StringMatching = jRequire.StringMatching(j$);
j$.UserContext = jRequire.UserContext(j$);
j$.Suite = jRequire.Suite(j$);
j$.Timer = jRequire.Timer();
j$.TreeProcessor = jRequire.TreeProcessor();
@@ -138,6 +139,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
j$.MAX_PRETTY_PRINT_DEPTH = 40;
/**
* Maximum number of array elements to display when pretty printing objects.
* 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
*/
@@ -185,6 +187,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return j$.isA_('Function', value);
};
j$.isAsyncFunction_ = function(value) {
return j$.isA_('AsyncFunction', value);
};
j$.isA_ = function(typeName, value) {
return j$.getType_(value) === '[object ' + typeName + ']';
};
@@ -462,20 +468,25 @@ getJasmineRequireObj().Spec = function(j$) {
this.onStart(this);
if (!this.isExecutable() || this.markedPending || enabled === false) {
complete(enabled);
return;
}
var fns = this.beforeAndAfterFns();
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
var regularFns = fns.befores.concat(this.queueableFn);
this.queueRunnerFactory({
queueableFns: allFns,
var runnerConfig = {
isLeaf: true,
queueableFns: regularFns,
cleanupFns: fns.afters,
onException: function() { self.onException.apply(self, arguments); },
onComplete: complete,
userContext: this.userContext()
});
};
if (!this.isExecutable() || this.markedPending || enabled === false) {
runnerConfig.queueableFns = [];
runnerConfig.cleanupFns = [];
runnerConfig.onComplete = function() { complete(enabled); };
}
this.queueRunnerFactory(runnerConfig);
function complete(enabledAgain) {
self.result.status = self.status(enabledAgain);
@@ -812,6 +823,7 @@ getJasmineRequireObj().Env = function(j$) {
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
options.globalErrors = globalErrors;
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
new j$.QueueRunner(options).execute();
};
@@ -874,7 +886,8 @@ getJasmineRequireObj().Env = function(j$) {
}
reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined
totalSpecsDefined: totalSpecsDefined,
order: order
});
currentlyExecutingSuites.push(topSuite);
@@ -935,6 +948,12 @@ getJasmineRequireObj().Env = function(j$) {
}
};
var ensureIsFunctionOrAsync = function(fn, caller) {
if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
}
};
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
@@ -1073,7 +1092,7 @@ getJasmineRequireObj().Env = function(j$) {
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunction(fn, 'it');
ensureIsFunctionOrAsync(fn, 'it');
}
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
if (currentDeclarationSuite.markedPending) {
@@ -1087,7 +1106,7 @@ getJasmineRequireObj().Env = function(j$) {
// xit(), like it(), doesn't always have a fn argument, so only check the
// type when needed.
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunction(fn, 'xit');
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
@@ -1095,7 +1114,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.fit = function(description, fn, timeout){
ensureIsFunction(fn, 'fit');
ensureIsFunctionOrAsync(fn, 'fit');
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
@@ -1112,7 +1131,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsFunction(beforeEachFunction, 'beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -1120,7 +1139,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeAll = function(beforeAllFunction, timeout) {
ensureIsFunction(beforeAllFunction, 'beforeAll');
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -1128,7 +1147,8 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterEach = function(afterEachFunction, timeout) {
ensureIsFunction(afterEachFunction, 'afterEach');
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -1136,7 +1156,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterAll = function(afterAllFunction, timeout) {
ensureIsFunction(afterAllFunction, 'afterAll');
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -1177,6 +1197,10 @@ getJasmineRequireObj().Env = function(j$) {
message: message,
error: error && error.message ? error : null
});
if (self.throwingExpectationFailures()) {
throw new Error(message);
}
};
}
@@ -1600,7 +1624,9 @@ getJasmineRequireObj().CallTracker = function(j$) {
};
getJasmineRequireObj().clearStack = function(j$) {
function messageChannelImpl(global) {
var maxInlineCallCount = 10;
function messageChannelImpl(global, setTimeout) {
var channel = new global.MessageChannel(),
head = {},
tail = head;
@@ -1623,25 +1649,44 @@ getJasmineRequireObj().clearStack = function(j$) {
}
};
var currentCallCount = 0;
return function clearStack(fn) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
} else {
currentCallCount = 0;
setTimeout(fn);
}
};
}
function getClearStack(global) {
var currentCallCount = 0;
var realSetTimeout = global.setTimeout;
var setTimeoutImpl = function clearStack(fn) {
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
};
if (j$.isFunction_(global.setImmediate)) {
var realSetImmediate = global.setImmediate;
return function(fn) {
realSetImmediate(fn);
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
realSetImmediate(fn);
} else {
currentCallCount = 0;
setTimeoutImpl(fn);
}
};
} else if (!j$.util.isUndefined(global.MessageChannel)) {
return messageChannelImpl(global);
return messageChannelImpl(global, setTimeoutImpl);
} else {
var realSetTimeout = global.setTimeout;
return function clearStack(fn) {
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
};
return setTimeoutImpl;
}
}
@@ -2502,12 +2547,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (!result) {
return false;
}
} else if (className == '[object Set]') {
} else if (className == '[object Set]' || className == '[object Map]') {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
var iterA = a.values(), iterB = b.values();
var iterA = a.entries(), iterB = b.entries();
var valA, valB;
do {
valA = iterA.next();
@@ -2747,8 +2792,18 @@ getJasmineRequireObj().toBeCloseTo = function() {
precision = precision || 2;
}
if (expected === null || actual === null) {
throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
'expect(' + actual + ').toBeCloseTo(' + expected + ').'
);
}
var pow = Math.pow(10, precision + 1);
var delta = Math.abs(expected - actual);
var maxDelta = Math.pow(10, -precision) / 2;
return {
pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
pass: Math.round(delta * pow) / pow <= maxDelta
};
}
};
@@ -3629,7 +3684,7 @@ getJasmineRequireObj().pp = function(j$) {
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 value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
}
PrettyPrinter.prototype.format = function(value) {
@@ -3657,8 +3712,10 @@ getJasmineRequireObj().pp = function(j$) {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (value.toString && value.toString() == '[object Set]') {
} else if (j$.getType_(value) == '[object Set]') {
this.emitSet(value);
} else if (j$.getType_(value) == '[object Map]') {
this.emitMap(value);
} else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
this.emitScalar(value.toString());
} else if (j$.util.arrayContains(this.seen, value)) {
@@ -3680,15 +3737,28 @@ getJasmineRequireObj().pp = function(j$) {
};
PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
obj.__lookupGetter__(property) !== null) : false);
var objKeys = keys(obj, j$.isArray_(obj));
var isGetter = function isGetter(prop) {};
if (obj.__lookupGetter__) {
isGetter = function isGetter(prop) {
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++) {
var property = objKeys[i];
fn(property, isGetter(property));
}
return objKeys.length > length;
};
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitMap = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
@@ -3696,7 +3766,7 @@ getJasmineRequireObj().pp = function(j$) {
function StringPrettyPrinter() {
PrettyPrinter.call(this);
this.string = '';
this.stringParts = [];
}
j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
@@ -3728,11 +3798,7 @@ getJasmineRequireObj().pp = function(j$) {
var self = this;
var first = array.length === 0;
this.iterateObject(array, function(property, isGetter) {
if (property.match(/^\d+$/)) {
return;
}
var truncated = this.iterateObject(array, function(property, isGetter) {
if (first) {
first = false;
} else {
@@ -3742,6 +3808,8 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(array, property, isGetter);
});
if (truncated) { this.append(', ...'); }
this.append(' ]');
};
@@ -3765,6 +3833,26 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' )');
};
StringPrettyPrinter.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = map.entries();
for (var i = 0; i < size; i++) {
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
if (map.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
@@ -3783,7 +3871,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append('({ ');
var first = true;
this.iterateObject(obj, function(property, isGetter) {
var truncated = this.iterateObject(obj, function(property, isGetter) {
if (first) {
first = false;
} else {
@@ -3793,6 +3881,8 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(obj, property, isGetter);
});
if (truncated) { this.append(', ...'); }
this.append(' })');
};
@@ -3807,13 +3897,42 @@ getJasmineRequireObj().pp = function(j$) {
};
StringPrettyPrinter.prototype.append = function(value) {
this.string += value;
this.stringParts.push(value);
};
function keys(obj, isArray) {
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);
}
}
return keys;
})(obj);
if (!isArray) {
return allKeys;
}
if (allKeys.length === 0) {
return allKeys;
}
var extraKeys = [];
for (var i = 0; i < allKeys.length; i++) {
if (!/^[0-9]+$/.test(allKeys[i])) {
extraKeys.push(allKeys[i]);
}
}
return extraKeys;
}
return function(value) {
var stringPrettyPrinter = new StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.string;
return stringPrettyPrinter.stringParts.join('');
};
};
@@ -3831,15 +3950,18 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
function QueueRunner(attrs) {
this.queueableFns = attrs.queueableFns || [];
var queueableFns = attrs.queueableFns || [];
this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
this.firstCleanupIx = queueableFns.length;
this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; };
this.userContext = attrs.userContext || {};
this.userContext = attrs.userContext || new j$.UserContext();
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
this.completeOnFirstError = !!attrs.completeOnFirstError;
}
QueueRunner.prototype.execute = function() {
@@ -3848,22 +3970,33 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onException(error);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(this.queueableFns, 0);
this.run(0);
};
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = queueableFns.length,
QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
if (lastRanIndex < this.firstCleanupIx) {
this.run(this.firstCleanupIx);
} else {
this.run(lastRanIndex + 1);
}
};
QueueRunner.prototype.run = function(recursiveIndex) {
var length = this.queueableFns.length,
self = this,
iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var queueableFn = queueableFns[iterativeIndex];
if (queueableFn.fn.length > 0) {
attemptAsync(queueableFn);
var result = attempt(iterativeIndex);
if (!result.completedSynchronously) {
return;
}
if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex);
return;
} else {
attemptSync(queueableFn);
}
}
@@ -3872,62 +4005,93 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onComplete();
});
function attemptSync(queueableFn) {
try {
queueableFn.fn.call(self.userContext);
} catch (e) {
handleException(e, queueableFn);
}
}
function attemptAsync(queueableFn) {
function attempt() {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
setTimeout = function(delayedFn, delay) {
return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
},
completedSynchronously = true,
handleError = function(error) {
onException(error);
next();
},
next = once(function () {
cleanup = once(function() {
clearTimeout(timeoutId);
self.globalErrors.popListener(handleError);
self.run(queueableFns, iterativeIndex + 1);
}),
next = once(function () {
cleanup();
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
} else {
self.run(iterativeIndex + 1);
}
}
if (completedSynchronously) {
setTimeout(runNext);
} else {
runNext();
}
}),
errored = false,
queueableFn = self.queueableFns[iterativeIndex],
timeoutId;
next.fail = function() {
self.fail.apply(null, arguments);
errored = true;
next();
};
self.globalErrors.pushListener(handleError);
if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
timeoutId = setTimeout(function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
onException(error);
next();
}, queueableFn.timeout()]]);
}, queueableFn.timeout());
}
try {
queueableFn.fn.call(self.userContext, next);
if (queueableFn.fn.length === 0) {
var maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, next.fail);
completedSynchronously = false;
return { completedSynchronously: false };
}
} else {
queueableFn.fn.call(self.userContext, next);
completedSynchronously = false;
return { completedSynchronously: false };
}
} catch (e) {
handleException(e, queueableFn);
next();
errored = true;
}
}
function onException(e) {
self.onException(e);
}
cleanup();
return { completedSynchronously: true, errored: errored };
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
function onException(e) {
self.onException(e);
errored = true;
}
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
}
}
}
};
@@ -4657,14 +4821,14 @@ getJasmineRequireObj().Suite = function(j$) {
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
}
return this.sharedContext;
};
Suite.prototype.clonedSharedUserContext = function() {
return clone(this.sharedUserContext());
return j$.UserContext.fromExisting(this.sharedUserContext());
};
Suite.prototype.onException = function() {
@@ -4716,17 +4880,6 @@ getJasmineRequireObj().Suite = function(j$) {
return !args[0];
}
function clone(obj) {
var clonedObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
clonedObj[prop] = obj[prop];
}
}
return clonedObj;
}
return Suite;
};
@@ -4964,6 +5117,25 @@ getJasmineRequireObj().TreeProcessor = function() {
return TreeProcessor;
};
getJasmineRequireObj().version = function() {
return '2.6.2';
getJasmineRequireObj().UserContext = function(j$) {
function UserContext() {
}
UserContext.fromExisting = function(oldContext) {
var context = new UserContext();
for (var prop in oldContext) {
if (oldContext.hasOwnProperty(prop)) {
context[prop] = oldContext[prop];
}
}
return context;
};
return UserContext;
};
getJasmineRequireObj().version = function() {
return '2.7.0';
};

View File

@@ -4,6 +4,6 @@
#
module Jasmine
module Core
VERSION = "2.6.2"
VERSION = "2.7.0"
end
end

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "2.6.2",
"version": "2.7.0",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"
@@ -19,7 +19,7 @@
"homepage": "http://jasmine.github.io",
"main": "./lib/jasmine-core.js",
"devDependencies": {
"glob": "~7.0.5",
"glob": "~7.1.2",
"grunt": "^1.0.1",
"grunt-cli": "^1.2.0",
"grunt-contrib-compass": "^1.1.1",

17
release_notes/2.6.3.md Normal file
View File

@@ -0,0 +1,17 @@
# Jasmine 2.6.3 Release Notes
## Summary
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
## Changes
* Make sure the queue runner goes async for async specs
- Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327)
- Fixes [#1334](https://github.com/jasmine/jasmine/issues/1334)
- Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48)
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

17
release_notes/2.6.4.md Normal file
View File

@@ -0,0 +1,17 @@
# Jasmine 2.6.4 Release Notes
## Summary
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
## Changes
* Break into a `setTimeout` every once in a while allowing the CPU to run other things that used the real `setTimeout`
- Fixes [#1327](https://github.com/jasmine/jasmine/issues/1327)
- See [#1334](https://github.com/jasmine/jasmine/issues/1334)
- Fixes [jasmine/gulp-jasmine-browser#48](https://github.com/jasmine/gulp-jasmine-browser/issues/48)
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

61
release_notes/2.7.0.md Normal file
View File

@@ -0,0 +1,61 @@
# Jasmine 2.7.0 Release Notes
## Summary
This release contains a number of fixes and pull requests.
## Pull Requests & Issues
* Add class UserContext
- Merges [#1400](https://github.com/jasmine/jasmine/issues/1400) from @darthjee
* Send unfocused tests through the same queue as focused tests
- Merges [#1399](https://github.com/jasmine/jasmine/issues/1399) from @jberney
* PrettyPrinter allows an object to have a `toString` that isn't a function
- Fixes [#1389](https://github.com/jasmine/jasmine/issues/1389)
* Fix rounding in toBeCloseTo
- Fixes [#1382](https://github.com/jasmine/jasmine/issues/1382)
* When stop on failure is enabled, skip subsequent it() and beforeEach(). Note: afterEach() functions are still run, because skipping them is highly likely to pollute specs that run after the failure.
- Fixes [#577](https://github.com/jasmine/jasmine/issues/577)
- Fixes [#807](https://github.com/jasmine/jasmine/issues/807)
* Only clear out the `spec` param for Run all link
- Fixes [#1369](https://github.com/jasmine/jasmine/issues/1369)
* Pretty printer will now use MAX_PRETTY_PRINT_ARRAY_LENGTH for objects
- Fixes [#1291](https://github.com/jasmine/jasmine/issues/1291)
- Fixes [#1360](https://github.com/jasmine/jasmine/issues/1360)
* updated package glob from 7.0.5 to 7.1.2
- Merges [#1368](https://github.com/jasmine/jasmine/issues/1368) from @EsrefDurna
* Fix bower.json url to be https instead of http
- Merges [#1365](https://github.com/jasmine/jasmine/issues/1365) from @kant
* Fail when one of the arguments passed into toBeCloseTo matcher is null
- Merges [#1362](https://github.com/jasmine/jasmine/issues/1362) from @beatrichartz
* Fixed HTML snippet in README
- Closes [#1366](https://github.com/jasmine/jasmine/issues/1366).
* Report the random seed at the beginning and end of execution. This allows reporters to provide the seed to the user even in cases where Jasmine crashes before completing.
- Merges [#1348](https://github.com/jasmine/jasmine/issues/1348) from @sgravrock
* Add ES6 map support to Jasmine
- Merges [#1340](https://github.com/jasmine/jasmine/issues/1340) from @rmehlinger
- Fixes [#1257](https://github.com/jasmine/jasmine/issues/1257)
* Added support for async before/it/after functions that return promises and added support for ES2017 async functions
- Merges [#1356](https://github.com/jasmine/jasmine/issues/1356) from @sgravrock
- Fixes [#1336](https://github.com/jasmine/jasmine/issues/1336)
- Fixes [#1270](https://github.com/jasmine/jasmine/issues/1270)
- Fixes [#1350](https://github.com/jasmine/jasmine/issues/1350)
- Fixes [#1320](https://github.com/jasmine/jasmine/issues/1320)
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -21,6 +21,34 @@ describe("ClearStack", function() {
expect(setImmediate).toHaveBeenCalled();
});
it("uses setTimeout instead of setImmediate every 10 calls to make sure we release the CPU", function() {
var setImmediate = jasmine.createSpy('setImmediate'),
setTimeout = jasmine.createSpy('setTimeout'),
global = { setImmediate: setImmediate, setTimeout: setTimeout },
clearStack = jasmineUnderTest.getClearStack(global);
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
expect(setImmediate).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
clearStack(function() { });
expect(setImmediate.calls.count()).toEqual(9);
expect(setTimeout.calls.count()).toEqual(1);
clearStack(function() { });
expect(setImmediate.calls.count()).toEqual(10);
expect(setTimeout.calls.count()).toEqual(1);
});
it("uses MessageChannels when available", function() {
var fakeChannel = {
port1: {},
@@ -37,6 +65,41 @@ describe("ClearStack", function() {
expect(called).toBe(true);
});
it("uses setTimeout instead of MessageChannel every 10 calls to make sure we release the CPU", function() {
var fakeChannel = {
port1: {},
port2: {
postMessage: jasmine.createSpy('postMessage').and.callFake(function() {
fakeChannel.port1.onmessage();
})
}
},
setTimeout = jasmine.createSpy('setTimeout'),
global = { MessageChannel: function() { return fakeChannel; }, setTimeout: setTimeout },
clearStack = jasmineUnderTest.getClearStack(global);
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
clearStack(function() { });
expect(fakeChannel.port2.postMessage).toHaveBeenCalled();
expect(setTimeout).not.toHaveBeenCalled();
clearStack(function() { });
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(9);
expect(setTimeout.calls.count()).toEqual(1);
clearStack(function() { });
expect(fakeChannel.port2.postMessage.calls.count()).toEqual(10);
expect(setTimeout.calls.count()).toEqual(1);
});
it("calls setTimeout when onmessage is called recursively", function() {
var fakeChannel = {
port1: {},

View File

@@ -91,6 +91,13 @@ describe("Env", function() {
env.it('pending spec');
}).not.toThrow();
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.it('async', jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
describe('#xit', function() {
@@ -114,6 +121,13 @@ describe("Env", function() {
env.xit('pending spec');
}).not.toThrow();
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.xit('async', jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
describe('#fit', function () {
@@ -130,6 +144,13 @@ describe("Env", function() {
env.beforeEach(undefined);
}).toThrowError(/beforeEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.beforeEach(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
describe('#beforeAll', function () {
@@ -138,6 +159,13 @@ describe("Env", function() {
env.beforeAll(undefined);
}).toThrowError(/beforeAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.beforeAll(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
describe('#afterEach', function () {
@@ -146,6 +174,13 @@ describe("Env", function() {
env.afterEach(undefined);
}).toThrowError(/afterEach expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.afterEach(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
describe('#afterAll', function () {
@@ -154,5 +189,12 @@ describe("Env", function() {
env.afterAll(undefined);
}).toThrowError(/afterAll expects a function argument; received \[object (Undefined|DOMWindow|Object)\]/);
});
it('accepts an async function', function() {
jasmine.getEnv().requireAsyncAwait();
expect(function() {
env.afterAll(jasmine.getEnv().makeAsyncAwaitFunction());
}).not.toThrow();
});
});
});

View File

@@ -33,6 +33,26 @@ describe("jasmineUnderTest.pp", function () {
})
});
describe('stringify maps', function() {
it("should stringify maps properly", function() {
jasmine.getEnv().requireFunctioningMaps();
expect(jasmineUnderTest.pp(new Map([[1, 2]]))).toEqual("Map( [ 1, 2 ] )");
});
it("should truncate maps with more elments than jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH", function() {
jasmine.getEnv().requireFunctioningMaps();
var originalMaxSize = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(new Map([["a", 1], ["b", 2], ["c", 3]]))).toEqual("Map( [ 'a', 1 ], [ 'b', 2 ], ... )");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxSize;
}
})
});
describe('stringify arrays', function() {
it("should stringify arrays properly", function() {
expect(jasmineUnderTest.pp([1, 2])).toEqual("[ 1, 2 ]");
@@ -99,6 +119,18 @@ describe("jasmineUnderTest.pp", function () {
}, bar: [1, 2, 3]})).toEqual("Object({ foo: Function, bar: [ 1, 2, 3 ] })");
});
it("should truncate objects with too many keys", function () {
var originalMaxLength = jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH;
var long = {a: 1, b: 2, c: 3};
try {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = 2;
expect(jasmineUnderTest.pp(long)).toEqual("Object({ a: 1, b: 2, ... })");
} finally {
jasmineUnderTest.MAX_PRETTY_PRINT_ARRAY_LENGTH = originalMaxLength;
}
});
it("should print 'null' as the constructor of an object with its own constructor property", function() {
expect(jasmineUnderTest.pp({constructor: function() {}})).toContain("null({");
expect(jasmineUnderTest.pp({constructor: 'foo'})).toContain("null({");
@@ -225,6 +257,18 @@ describe("jasmineUnderTest.pp", function () {
}
});
it("should stringify objects have have a toString that isn't a function", function() {
var obj = {
toString: "foo"
};
if (jasmine.getEnv().ieVersion < 9) {
expect(jasmineUnderTest.pp(obj)).toEqual("Object({ })");
} else {
expect(jasmineUnderTest.pp(obj)).toEqual("Object({ toString: 'foo' })");
}
});
it("should stringify objects from anonymous constructors with custom toString", function () {
var MyAnonymousConstructor = (function() { return function () {}; })();
MyAnonymousConstructor.toString = function () { return ''; };

View File

@@ -19,6 +19,26 @@ describe("QueueRunner", function() {
expect(calls).toEqual(['fn1', 'fn2']);
});
it("runs cleanup functions after the others", function() {
var calls = [],
queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1],
cleanupFns: [queueableFn2]
});
queueableFn1.fn.and.callFake(function() {
calls.push('fn1');
});
queueableFn2.fn.and.callFake(function() {
calls.push('fn2');
});
queueRunner.execute();
expect(calls).toEqual(['fn1', 'fn2']);
});
it("calls each function with a consistent 'this'-- an empty object", function() {
var queueableFn1 = { fn: jasmine.createSpy('fn1') },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
@@ -31,7 +51,7 @@ describe("QueueRunner", function() {
queueRunner.execute();
var context = queueableFn1.fn.calls.first().object;
expect(context).toEqual({});
expect(context).toEqual(new jasmineUnderTest.UserContext());
expect(queueableFn2.fn.calls.first().object).toBe(context);
expect(asyncContext).toBe(context);
});
@@ -189,6 +209,7 @@ describe("QueueRunner", function() {
queueRunner.execute();
jasmine.clock().tick(1);
expect(onComplete).toHaveBeenCalled();
jasmine.clock().tick(jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL);
@@ -197,12 +218,13 @@ describe("QueueRunner", function() {
it("only moves to the next spec the first time you call done", function() {
var queueableFn = { fn: function(done) {done(); done();} },
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
});
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
jasmine.clock().tick(1);
expect(nextQueueableFn.fn.calls.count()).toEqual(1);
});
@@ -211,10 +233,10 @@ describe("QueueRunner", function() {
setTimeout(done, 1);
throw new Error('error!');
} },
nextQueueableFn = { fn: jasmine.createSpy('nextFn') };
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
});
nextQueueableFn = { fn: jasmine.createSpy('nextFn') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn]
});
queueRunner.execute();
jasmine.clock().tick(1);
@@ -271,6 +293,111 @@ describe("QueueRunner", function() {
expect(onException).toHaveBeenCalledWith(errorWithMessage(/^foo$/));
expect(nextQueueableFn.fn).toHaveBeenCalled();
});
it("handles exceptions thrown while waiting for the stack to clear", function() {
var queueableFn = { fn: function(done) { done() } },
global = {},
errorListeners = [],
globalErrors = {
pushListener: function(f) { errorListeners.push(f); },
popListener: function() { errorListeners.pop(); }
},
clearStack = jasmine.createSpy('clearStack'),
onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
globalErrors: globalErrors,
clearStack: clearStack,
onException: onException
}),
error = new Error('nope');
queueRunner.execute();
jasmine.clock().tick();
expect(clearStack).toHaveBeenCalled();
expect(errorListeners.length).toEqual(1);
errorListeners[0](error);
clearStack.calls.argsFor(0)[0]();
expect(onException).toHaveBeenCalledWith(error);
});
});
describe("with a function that returns a promise", function() {
function StubPromise() {}
StubPromise.prototype.then = function(resolve, reject) {
this.resolveHandler = resolve;
this.rejectHandler = reject;
};
beforeEach(function() {
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("runs the function asynchronously, advancing once the promise is settled", function() {
var onComplete = jasmine.createSpy('onComplete'),
fnCallback = jasmine.createSpy('fnCallback'),
p1 = new StubPromise(),
p2 = new StubPromise(),
queueableFn1 = { fn: function() {
setTimeout(function() {
p1.resolveHandler();
}, 100);
return p1;
} };
queueableFn2 = { fn: function() {
fnCallback();
setTimeout(function() {
p2.resolveHandler();
}, 100);
return p2;
} },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
onComplete: onComplete
});
queueRunner.execute();
expect(fnCallback).not.toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(fnCallback).toHaveBeenCalled();
expect(onComplete).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(onComplete).toHaveBeenCalled();
});
it("fails the function when the promise is rejected", function() {
var promise = new StubPromise(),
queueableFn1 = { fn: function() {
setTimeout(function() { promise.rejectHandler('foo'); }, 100);
return promise;
} },
queueableFn2 = { fn: jasmine.createSpy('fn2') },
failFn = jasmine.createSpy('fail'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn1, queueableFn2],
fail: failFn
});
queueRunner.execute();
expect(failFn).not.toHaveBeenCalled();
expect(queueableFn2.fn).not.toHaveBeenCalled();
jasmine.clock().tick(100);
expect(failFn).toHaveBeenCalledWith('foo');
expect(queueableFn2.fn).toHaveBeenCalled();
});
});
it("calls exception handlers when an exception is thrown in a fn", function() {
@@ -314,30 +441,85 @@ describe("QueueRunner", function() {
expect(nextQueueableFn.fn).toHaveBeenCalled();
});
it("handles exceptions thrown while waiting for the stack to clear", function() {
var queueableFn = { fn: function(done) { done() } },
global = {},
errorListeners = [],
globalErrors = {
pushListener: function(f) { errorListeners.push(f); },
popListener: function() { errorListeners.pop(); }
},
clearStack = jasmine.createSpy('clearStack'),
onException = jasmine.createSpy('onException'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
globalErrors: globalErrors,
clearStack: clearStack,
onException: onException
}),
error = new Error('nope');
describe("When configured to complete on first error", function() {
it("skips to cleanup functions on the first exception", function() {
var queueableFn = { fn: function() { throw new Error("error"); } },
nextQueueableFn = { fn: jasmine.createSpy("nextFunction") },
cleanupFn = { fn: jasmine.createSpy("cleanup") },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true
});
queueRunner.execute();
expect(clearStack).toHaveBeenCalled();
expect(errorListeners.length).toEqual(1);
errorListeners[0](error);
clearStack.calls.argsFor(0)[0]();
expect(onException).toHaveBeenCalledWith(error);
queueRunner.execute();
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
expect(cleanupFn.fn).toHaveBeenCalled();
});
it("does not skip when a cleanup function throws", function() {
var queueableFn = { fn: function() { } },
cleanupFn1 = { fn: function() { throw new Error("error"); } },
cleanupFn2 = { fn: jasmine.createSpy("cleanupFn2") },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn],
cleanupFns: [cleanupFn1, cleanupFn2],
completeOnFirstError: true
});
queueRunner.execute();
expect(cleanupFn2.fn).toHaveBeenCalled();
});
describe("with an asynchronous function", function() {
beforeEach(function() {
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
});
it("skips to cleanup functions on the first exception", function() {
var errorListeners = [],
queueableFn = { fn: function(done) {} },
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
queueRunner = new jasmineUnderTest.QueueRunner({
globalErrors: {
pushListener: function(f) { errorListeners.push(f); },
popListener: function() { errorListeners.pop(); },
},
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true,
});
queueRunner.execute();
errorListeners[errorListeners.length - 1](new Error('error'));
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
expect(cleanupFn.fn).toHaveBeenCalled();
});
it("skips to cleanup functions when next.fail is called", function() {
var queueableFn = { fn: function(done) {
done.fail('nope');
} },
nextQueueableFn = { fn: jasmine.createSpy('nextFunction') },
cleanupFn = { fn: jasmine.createSpy('cleanup') },
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [queueableFn, nextQueueableFn],
cleanupFns: [cleanupFn],
completeOnFirstError: true,
});
queueRunner.execute();
jasmine.clock().tick();
expect(nextQueueableFn.fn).not.toHaveBeenCalled();
expect(cleanupFn.fn).toHaveBeenCalled();
});
});
});
it("calls a provided complete callback when done", function() {
@@ -353,23 +535,83 @@ describe("QueueRunner", function() {
expect(completeCallback).toHaveBeenCalled();
});
it("calls a provided stack clearing function when done", function() {
var asyncFn = { fn: function(done) { done() } },
afterFn = { fn: jasmine.createSpy('afterFn') },
completeCallback = jasmine.createSpy('completeCallback'),
clearStack = jasmine.createSpy('clearStack'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [asyncFn, afterFn],
clearStack: clearStack,
onComplete: completeCallback
});
describe("clearing the stack", function() {
beforeEach(function() {
jasmine.clock().install();
});
clearStack.and.callFake(function(fn) { fn(); });
afterEach(function() {
jasmine.clock().uninstall();
});
queueRunner.execute();
expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalled();
clearStack.calls.argsFor(0)[0]();
expect(completeCallback).toHaveBeenCalled();
it("calls a provided stack clearing function when done", function() {
var asyncFn = { fn: function(done) { done() } },
afterFn = { fn: jasmine.createSpy('afterFn') },
completeCallback = jasmine.createSpy('completeCallback'),
clearStack = jasmine.createSpy('clearStack'),
queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [asyncFn, afterFn],
clearStack: clearStack,
onComplete: completeCallback
});
clearStack.and.callFake(function(fn) { fn(); });
queueRunner.execute();
jasmine.clock().tick();
expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalled();
clearStack.calls.argsFor(0)[0]();
expect(completeCallback).toHaveBeenCalled();
});
});
describe('when user context has not been defined', function() {
beforeEach(function() {
var fn;
this.fn = fn = jasmine.createSpy('fn1');
this.queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }]
});
});
it('runs the functions on the scope of a UserContext', function() {
var calls = [],
context;
this.fn.and.callFake(function() {
context = this;
});
this.queueRunner.execute();
expect(context.constructor).toBe(jasmineUnderTest.UserContext);
});
});
describe('when user context has been defined', function() {
beforeEach(function() {
var fn, context;
this.fn = fn = jasmine.createSpy('fn1');
this.context = context = new jasmineUnderTest.UserContext();
this.queueRunner = new jasmineUnderTest.QueueRunner({
queueableFns: [{ fn: fn }],
userContext: context
});
});
it('runs the functions on the scope of a UserContext', function() {
var calls = [],
context;
this.fn.and.callFake(function() {
context = this;
});
this.queueRunner.execute();
expect(context).toBe(this.context);
});
});
});

View File

@@ -103,8 +103,26 @@ describe("Spec", function() {
spec.execute();
var allSpecFns = fakeQueueRunner.calls.mostRecent().args[0].queueableFns;
expect(allSpecFns).toEqual([before, queueableFn, after]);
var options = fakeQueueRunner.calls.mostRecent().args[0];
expect(options.queueableFns).toEqual([before, queueableFn]);
expect(options.cleanupFns).toEqual([after]);
});
it("tells the queue runner that it's a leaf node", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
spec = new jasmineUnderTest.Spec({
queueableFn: { fn: function() {} },
beforeAndAfterFns: function() {
return {befores: [], afters: []}
},
queueRunnerFactory: fakeQueueRunner
});
spec.execute();
expect(fakeQueueRunner).toHaveBeenCalledWith(jasmine.objectContaining({
isLeaf: true
}));
});
it("is marked pending if created without a function body", function() {
@@ -123,7 +141,8 @@ describe("Spec", function() {
});
it("can be disabled, but still calls callbacks", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
.and.callFake(function(attrs) { attrs.onComplete(); }),
startCallback = jasmine.createSpy('startCallback'),
specBody = jasmine.createSpy('specBody'),
resultCallback = jasmine.createSpy('resultCallback'),
@@ -140,7 +159,7 @@ describe("Spec", function() {
spec.execute();
expect(fakeQueueRunner).not.toHaveBeenCalled();
expect(fakeQueueRunner).toHaveBeenCalled();
expect(specBody).not.toHaveBeenCalled();
expect(startCallback).toHaveBeenCalled();
@@ -148,7 +167,8 @@ describe("Spec", function() {
});
it("can be disabled at execution time by a parent", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
.and.callFake(function(attrs) { attrs.onComplete(); }),
startCallback = jasmine.createSpy('startCallback'),
specBody = jasmine.createSpy('specBody'),
resultCallback = jasmine.createSpy('resultCallback'),
@@ -163,7 +183,7 @@ describe("Spec", function() {
expect(spec.result.status).toBe('disabled');
expect(fakeQueueRunner).not.toHaveBeenCalled();
expect(fakeQueueRunner).toHaveBeenCalled();
expect(specBody).not.toHaveBeenCalled();
expect(startCallback).toHaveBeenCalled();
@@ -171,7 +191,8 @@ describe("Spec", function() {
});
it("can be marked pending, but still calls callbacks when executed", function() {
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner'),
var fakeQueueRunner = jasmine.createSpy('fakeQueueRunner')
.and.callFake(function(attrs) { attrs.onComplete(); }),
startCallback = jasmine.createSpy('startCallback'),
resultCallback = jasmine.createSpy('resultCallback'),
spec = new jasmineUnderTest.Spec({
@@ -191,7 +212,7 @@ describe("Spec", function() {
spec.execute();
expect(fakeQueueRunner).not.toHaveBeenCalled();
expect(fakeQueueRunner).toHaveBeenCalled();
expect(startCallback).toHaveBeenCalled();
expect(resultCallback).toHaveBeenCalledWith({

View File

@@ -141,5 +141,15 @@ describe("Suite", function() {
suite.onException(new jasmineUnderTest.errors.ExpectationFailed());
expect(suite.getResult().failedExpectations).toEqual([]);
})
});
describe('#sharedUserContext', function() {
beforeEach(function() {
this.suite = new jasmineUnderTest.Suite({});
});
it('returns a UserContext', function() {
expect(this.suite.sharedUserContext().constructor).toBe(jasmineUnderTest.UserContext);
});
});
});

View File

@@ -0,0 +1,54 @@
describe("UserContext", function() {
it("Behaves just like an plain object", function() {
var context = new jasmineUnderTest.UserContext(),
properties = [];
for (var prop in context) {
if (obj.hasOwnProperty(prop)) {
properties.push(prop);
}
}
expect(properties).toEqual([]);
});
describe('.fromExisting', function() {
describe('when using an already built context as model', function() {
beforeEach(function() {
this.context = new jasmineUnderTest.UserContext();
this.context.key = 'value';
this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context);
});
it('returns a cloned object', function() {
expect(this.cloned).toEqual(this.context);
});
it('does not return the same object', function() {
expect(this.cloned).not.toBe(this.context);
});
});
describe('when using a regular object as parameter', function() {
beforeEach(function() {
this.context = {};
this.value = 'value'
this.context.key = this.value;
this.cloned = jasmineUnderTest.UserContext.fromExisting(this.context);
});
it('returns an object with the same attributes', function() {
expect(this.cloned.key).toEqual(this.value);
});
it('does not return the same object', function() {
expect(this.cloned).not.toBe(this.context);
});
it('returns an UserContext', function() {
expect(this.cloned.constructor).toBe(jasmineUnderTest.UserContext);
});
});
});
});

View File

@@ -243,7 +243,7 @@ describe("Env integration", function() {
} else {
secondSpecContext = this;
}
expect(this).toEqual({});
expect(this).toEqual(new jasmineUnderTest.UserContext());
});
env.it("sync spec", function() {
@@ -277,7 +277,7 @@ describe("Env integration", function() {
env.beforeEach(function() {
specContext = this;
expect(this).toEqual({});
expect(this).toEqual(new jasmineUnderTest.UserContext());
});
env.it("sync spec", function(underTestCallback) {
@@ -456,7 +456,7 @@ describe("Env integration", function() {
env.execute();
});
it("copes with late async failures", function(done) {
it("copes with async failures after done has been called", function(done) {
var global = {
setTimeout: function(fn, delay) { setTimeout(fn, delay) },
clearTimeout: function(fn, delay) { clearTimeout(fn, delay) },
@@ -466,6 +466,7 @@ describe("Env integration", function() {
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone", "suiteDone" ]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.specDone).not.toHaveFailedExpecationsForRunnable('A suite fails', ['fail thrown']);
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('A suite', ['fail thrown']);
done();
});
@@ -474,9 +475,11 @@ describe("Env integration", function() {
env.fdescribe('A suite', function() {
env.it('fails', function(specDone) {
specDone();
setTimeout(function() {
global.onerror('fail');
specDone();
setTimeout(function() {
global.onerror('fail');
});
});
});
});
@@ -949,16 +952,15 @@ describe("Env integration", function() {
});
describe("with a mock clock", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
this.originalTimeout = jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL;
this.realSetTimeout = setTimeout;
jasmine.clock().install();
});
afterEach(function() {
jasmine.clock().uninstall();
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = this.originalTimeout;
});
it("should wait a specified interval before failing specs haven't called done yet", function(done) {
@@ -1067,7 +1069,6 @@ describe("Env integration", function() {
env.afterAll(function(innerDone) {
jasmine.clock().tick(3001);
innerDone();
jasmine.clock().tick(1);
});
});
@@ -1077,7 +1078,8 @@ describe("Env integration", function() {
it('should wait a custom interval before reporting async functions that fail to call done', function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']);
reporter = jasmine.createSpyObj('fakeReport', ['jasmineDone', 'suiteDone', 'specDone']),
realSetTimeout = this.realSetTimeout;
reporter.jasmineDone.and.callFake(function() {
expect(reporter.specDone).toHaveFailedExpecationsForRunnable('suite beforeAll times out', [
@@ -1107,6 +1109,11 @@ describe("Env integration", function() {
jasmineUnderTest.DEFAULT_TIMEOUT_INTERVAL = 10000;
env.describe('suite', function() {
env.afterAll(function() {
realSetTimeout(function() {
jasmine.clock().tick(10);
}, 100);
});
env.describe('beforeAll', function() {
env.beforeAll(function(innerDone) {
jasmine.clock().tick(5001);
@@ -1292,7 +1299,8 @@ describe("Env integration", function() {
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1
totalSpecsDefined: 1,
order: jasmine.any(jasmineUnderTest.Order)
});
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({
@@ -1327,7 +1335,8 @@ describe("Env integration", function() {
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1
totalSpecsDefined: 1,
order: jasmine.any(jasmineUnderTest.Order)
});
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({
@@ -1365,7 +1374,8 @@ describe("Env integration", function() {
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 5
totalSpecsDefined: 5,
order: jasmine.any(jasmineUnderTest.Order)
});
expect(reporter.specDone.calls.count()).toBe(5);
@@ -1422,6 +1432,34 @@ describe("Env integration", function() {
env.execute();
});
it("should report the random seed at the beginning and end of execution", function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
"jasmineStarted",
"jasmineDone",
"suiteStarted",
"suiteDone",
"specStarted",
"specDone"
]);
env.randomizeTests(true);
env.seed('123456');
reporter.jasmineDone.and.callFake(function(doneArg) {
expect(reporter.jasmineStarted).toHaveBeenCalled();
var startedArg = reporter.jasmineStarted.calls.argsFor(0)[0];
expect(startedArg.order.random).toEqual(true);
expect(startedArg.order.seed).toEqual('123456');
expect(doneArg.order.random).toEqual(true);
expect(doneArg.order.seed).toEqual('123456');
done();
});
env.addReporter(reporter);
env.execute();
});
it('should report pending spec messages', function(done) {
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [
@@ -1481,7 +1519,8 @@ describe("Env integration", function() {
reporter.jasmineDone.and.callFake(function() {
expect(reporter.jasmineStarted).toHaveBeenCalledWith({
totalSpecsDefined: 1
totalSpecsDefined: 1,
order: jasmine.any(jasmineUnderTest.Order)
});
expect(reporter.specDone).toHaveBeenCalledWith(jasmine.objectContaining({ status: 'disabled' }));

View File

@@ -836,4 +836,115 @@ describe("jasmine spec running", function () {
env.execute();
});
describe("When throwOnExpectationFailure is set", function() {
it("skips to cleanup functions after an error", function(done) {
var actions = [];
env.describe('Something', function() {
env.beforeEach(function() {
actions.push('outer beforeEach');
throw new Error("error");
});
env.afterEach(function() {
actions.push('outer afterEach');
});
env.describe('Inner', function() {
env.beforeEach(function() {
actions.push('inner beforeEach');
});
env.afterEach(function() {
actions.push('inner afterEach');
});
env.it('does it' , function() {
actions.push('inner it');
});
});
});
env.throwOnExpectationFailure(true);
var assertions = function() {
expect(actions).toEqual([
'outer beforeEach',
'inner afterEach',
'outer afterEach'
]);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it("skips to cleanup functions after done.fail is called", function(done) {
var actions = [];
env.describe('Something', function() {
env.beforeEach(function(done) {
actions.push('beforeEach');
done.fail('error');
actions.push('after done.fail');
});
env.afterEach(function() {
actions.push('afterEach');
});
env.it('does it' , function() {
actions.push('it');
});
});
env.throwOnExpectationFailure(true);
var assertions = function() {
expect(actions).toEqual([
'beforeEach',
'afterEach'
]);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
it("skips to cleanup functions when an async function times out", function(done) {
var actions = [];
env.describe('Something', function() {
env.beforeEach(function(innerDone) {
actions.push('beforeEach');
}, 1);
env.afterEach(function() {
actions.push('afterEach');
});
env.it('does it' , function() {
actions.push('it');
});
});
env.throwOnExpectationFailure(true);
var assertions = function() {
expect(actions).toEqual([
'beforeEach',
'afterEach'
]);
done();
};
env.addReporter({jasmineDone: assertions});
env.execute();
});
});
});

View File

@@ -414,6 +414,40 @@ describe("matchersUtil", function() {
expect(jasmineUnderTest.matchersUtil.equals(setA, setB)).toBe(false);
});
it("passes when comparing two empty maps", function() {
jasmine.getEnv().requireFunctioningMaps();
expect(jasmineUnderTest.matchersUtil.equals(new Map(), new Map())).toBe(true);
});
it("passes when comparing identical maps", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 5]]);
var mapB = new Map();
mapB.set(6, 5);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(true);
});
it("fails for maps with different elements", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 3], [5, 1]]);
var mapB = new Map([[6, 4], [5, 1]]);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
});
it("fails for maps of different size", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([[6, 3]]);
var mapB = new Map([[6, 4], [5, 1]]);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
});
it("fails for maps with different insertion order", function() {
jasmine.getEnv().requireFunctioningMaps();
var mapA = new Map([['a', 3], [6, 1]]);
var mapB = new Map([[6, 1], ['a', 3]]);
expect(jasmineUnderTest.matchersUtil.equals(mapA, mapB)).toBe(false);
});
describe("when running in an environment with array polyfills", function() {
// IE 8 doesn't support `definePropery` on non-DOM nodes
if (jasmine.getEnv().ieVersion < 9) { return; }

View File

@@ -8,6 +8,9 @@ describe("toBeCloseTo", function() {
result = matcher.compare(0, 0.001);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.005);
expect(result.pass).toBe(true);
});
it("fails when not within two decimal places by default", function() {
@@ -16,6 +19,9 @@ describe("toBeCloseTo", function() {
result = matcher.compare(0, 0.01);
expect(result.pass).toBe(false);
result = matcher.compare(0, 0.05);
expect(result.pass).toBe(false);
});
it("accepts an optional precision argument", function() {
@@ -25,8 +31,36 @@ describe("toBeCloseTo", function() {
result = matcher.compare(0, 0.1, 0);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.5, 0);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.0001, 3);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.0005, 3);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.00001, 4);
expect(result.pass).toBe(true);
result = matcher.compare(0, 0.00005, 4);
expect(result.pass).toBe(true);
});
it("fails when one of the arguments is null", function() {
var matcher = jasmineUnderTest.matchers.toBeCloseTo();
expect(function() {
matcher.compare(null, null);
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(null).');
expect(function() {
matcher.compare(0, null);
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(0).toBeCloseTo(null).');
expect(function() {
matcher.compare(null, 0);
}).toThrowError('Cannot use toBeCloseTo with null. Arguments evaluated to: expect(null).toBeCloseTo(0).');
});
it("rounds expected values", function() {
@@ -42,7 +76,15 @@ describe("toBeCloseTo", function() {
result = matcher.compare(1.23, 1.225);
expect(result.pass).toBe(true);
result = matcher.compare(1.23, 1.235);
expect(result.pass).toBe(true);
// 1.2249999 will be rounded to 1.225
result = matcher.compare(1.23, 1.2249999);
expect(result.pass).toBe(true);
// 1.2249999 will be rounded to 1.224
result = matcher.compare(1.23, 1.2244999);
expect(result.pass).toBe(false);
result = matcher.compare(1.23, 1.234);

View File

@@ -390,6 +390,37 @@ describe("toEqual", function() {
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("does not report deep mismatches within Maps", function() {
// TODO: implement deep comparison of Map elements
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([['a', 1]]),
expected = new Map([['a', 2]]),
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("reports mismatches between Maps nested in objects", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = {Maps: [new Map([['a', 1]])]},
expected = {Maps: [new Map([['a', 2], ['b', 1]])]},
message = "Expected $.Maps[0] = Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ], [ 'b', 1 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
it("reports mismatches between Maps of different lengths", function() {
jasmine.getEnv().requireFunctioningMaps();
var actual = new Map([['a', 1]]),
expected = new Map([['a', 2]]),
message = "Expected Map( [ 'a', 1 ] ) to equal Map( [ 'a', 2 ] ).";
expect(compareEquals(actual, expected).message).toEqual(message);
});
function isNotRunningInBrowser() {
return typeof document === 'undefined'
}

View File

@@ -0,0 +1,27 @@
(function(env) {
function getAsyncCtor() {
try {
eval("var func = async function(){};");
} catch (e) {
return null;
}
return Object.getPrototypeOf(func).constructor;
}
function hasAsyncAwaitSupport() {
return getAsyncCtor() !== null;
}
env.makeAsyncAwaitFunction = function() {
var AsyncFunction = getAsyncCtor();
return new AsyncFunction("");
};
env.requireAsyncAwait = function() {
if (!hasAsyncAwaitSupport()) {
env.pending("Environment does not support async/await functions");
}
};
})(jasmine.getEnv());

View File

@@ -0,0 +1,22 @@
(function(env) {
function hasFunctioningMaps() {
if (typeof Map === 'undefined') { return false; }
try {
var s = new Map([['a', 4]]);
if (s.size !== 1) { return false; }
if (s.keys().next().value !== 'a') { return false; }
if (s.values().next().value !== 4) { return false; }
return true;
} catch(e) {
return false;
}
}
env.requireFunctioningMaps = function() {
if (!hasFunctioningMaps()) {
env.pending("Browser has incomplete or missing support for Maps");
}
};
})(jasmine.getEnv());

View File

@@ -691,14 +691,15 @@ describe("New HtmlReporter", function() {
expect(seedBar).toBeNull();
});
it("should include the random query param in the jasmine-skipped link when randomizing", function(){
it("should include non-spec query params in the jasmine-skipped link when present", function(){
var env = new jasmineUnderTest.Env(),
container = document.createElement("div"),
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: function() { return container; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
createTextNode: function() { return document.createTextNode.apply(document, arguments); },
addToExistingQueryString: function(key, value) { return "?foo=bar&" + key + "=" + value; }
});
reporter.initialize();
@@ -706,25 +707,7 @@ describe("New HtmlReporter", function() {
reporter.jasmineDone({ order: { random: true } });
var skippedLink = container.querySelector(".jasmine-skipped a");
expect(skippedLink.getAttribute('href')).toEqual('?random=true');
});
it("should not include the random query param in the jasmine-skipped link when not randomizing", function(){
var env = new jasmineUnderTest.Env(),
container = document.createElement("div"),
reporter = new jasmineUnderTest.HtmlReporter({
env: env,
getContainer: function() { return container; },
createElement: function() { return document.createElement.apply(document, arguments); },
createTextNode: function() { return document.createTextNode.apply(document, arguments); }
});
reporter.initialize();
reporter.jasmineStarted({ totalSpecsDefined: 1 });
reporter.jasmineDone();
var skippedLink = container.querySelector(".jasmine-skipped a");
expect(skippedLink.getAttribute('href')).toEqual('?');
expect(skippedLink.getAttribute('href')).toEqual('?foo=bar&spec=');
});
});

View File

@@ -6,7 +6,9 @@
"npmPackage/**/*.js"
],
"helpers": [
"helpers/asyncAwait.js",
"helpers/checkForSet.js",
"helpers/checkForMap.js",
"helpers/nodeDefineJasmineUnderTest.js"
],
"random": true

View File

@@ -16,8 +16,10 @@ src_files:
- '**/*.js'
stylesheets:
helpers:
- 'helpers/asyncAwait.js'
- 'helpers/BrowserFlags.js'
- 'helpers/checkForSet.js'
- 'helpers/checkForMap.js'
- 'helpers/defineJasmineUnderTest.js'
spec_files:
- '**/*[Ss]pec.js'

View File

@@ -1,5 +1,7 @@
getJasmineRequireObj().clearStack = function(j$) {
function messageChannelImpl(global) {
var maxInlineCallCount = 10;
function messageChannelImpl(global, setTimeout) {
var channel = new global.MessageChannel(),
head = {},
tail = head;
@@ -22,25 +24,44 @@ getJasmineRequireObj().clearStack = function(j$) {
}
};
var currentCallCount = 0;
return function clearStack(fn) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
tail = tail.next = { task: fn };
channel.port2.postMessage(0);
} else {
currentCallCount = 0;
setTimeout(fn);
}
};
}
function getClearStack(global) {
var currentCallCount = 0;
var realSetTimeout = global.setTimeout;
var setTimeoutImpl = function clearStack(fn) {
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
};
if (j$.isFunction_(global.setImmediate)) {
var realSetImmediate = global.setImmediate;
return function(fn) {
realSetImmediate(fn);
currentCallCount++;
if (currentCallCount < maxInlineCallCount) {
realSetImmediate(fn);
} else {
currentCallCount = 0;
setTimeoutImpl(fn);
}
};
} else if (!j$.util.isUndefined(global.MessageChannel)) {
return messageChannelImpl(global);
return messageChannelImpl(global, setTimeoutImpl);
} else {
var realSetTimeout = global.setTimeout;
return function clearStack(fn) {
Function.prototype.apply.apply(realSetTimeout, [global, [fn, 0]]);
};
return setTimeoutImpl;
}
}

View File

@@ -196,6 +196,7 @@ getJasmineRequireObj().Env = function(j$) {
options.timeout = {setTimeout: realSetTimeout, clearTimeout: realClearTimeout};
options.fail = self.fail;
options.globalErrors = globalErrors;
options.completeOnFirstError = throwOnExpectationFailure && options.isLeaf;
new j$.QueueRunner(options).execute();
};
@@ -258,7 +259,8 @@ getJasmineRequireObj().Env = function(j$) {
}
reporter.jasmineStarted({
totalSpecsDefined: totalSpecsDefined
totalSpecsDefined: totalSpecsDefined,
order: order
});
currentlyExecutingSuites.push(topSuite);
@@ -319,6 +321,12 @@ getJasmineRequireObj().Env = function(j$) {
}
};
var ensureIsFunctionOrAsync = function(fn, caller) {
if (!j$.isFunction_(fn) && !j$.isAsyncFunction_(fn)) {
throw new Error(caller + ' expects a function argument; received ' + j$.getType_(fn));
}
};
var suiteFactory = function(description) {
var suite = new j$.Suite({
env: self,
@@ -457,7 +465,7 @@ getJasmineRequireObj().Env = function(j$) {
// it() sometimes doesn't have a fn argument, so only check the type if
// it's given.
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunction(fn, 'it');
ensureIsFunctionOrAsync(fn, 'it');
}
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
if (currentDeclarationSuite.markedPending) {
@@ -471,7 +479,7 @@ getJasmineRequireObj().Env = function(j$) {
// xit(), like it(), doesn't always have a fn argument, so only check the
// type when needed.
if (arguments.length > 1 && typeof fn !== 'undefined') {
ensureIsFunction(fn, 'xit');
ensureIsFunctionOrAsync(fn, 'xit');
}
var spec = this.it.apply(this, arguments);
spec.pend('Temporarily disabled with xit');
@@ -479,7 +487,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.fit = function(description, fn, timeout){
ensureIsFunction(fn, 'fit');
ensureIsFunctionOrAsync(fn, 'fit');
var spec = specFactory(description, fn, currentDeclarationSuite, timeout);
currentDeclarationSuite.addChild(spec);
focusedRunnables.push(spec.id);
@@ -496,7 +504,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeEach = function(beforeEachFunction, timeout) {
ensureIsFunction(beforeEachFunction, 'beforeEach');
ensureIsFunctionOrAsync(beforeEachFunction, 'beforeEach');
currentDeclarationSuite.beforeEach({
fn: beforeEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -504,7 +512,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.beforeAll = function(beforeAllFunction, timeout) {
ensureIsFunction(beforeAllFunction, 'beforeAll');
ensureIsFunctionOrAsync(beforeAllFunction, 'beforeAll');
currentDeclarationSuite.beforeAll({
fn: beforeAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -512,7 +520,8 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterEach = function(afterEachFunction, timeout) {
ensureIsFunction(afterEachFunction, 'afterEach');
ensureIsFunctionOrAsync(afterEachFunction, 'afterEach');
afterEachFunction.isCleanup = true;
currentDeclarationSuite.afterEach({
fn: afterEachFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -520,7 +529,7 @@ getJasmineRequireObj().Env = function(j$) {
};
this.afterAll = function(afterAllFunction, timeout) {
ensureIsFunction(afterAllFunction, 'afterAll');
ensureIsFunctionOrAsync(afterAllFunction, 'afterAll');
currentDeclarationSuite.afterAll({
fn: afterAllFunction,
timeout: function() { return timeout || j$.DEFAULT_TIMEOUT_INTERVAL; }
@@ -561,6 +570,10 @@ getJasmineRequireObj().Env = function(j$) {
message: message,
error: error && error.message ? error : null
});
if (self.throwingExpectationFailures()) {
throw new Error(message);
}
};
}

View File

@@ -8,7 +8,7 @@ getJasmineRequireObj().pp = function(j$) {
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 value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
return j$.isFunction_(value.toString) && value.toString !== Object.prototype.toString && (value.toString() !== Object.prototype.toString.call(value));
}
PrettyPrinter.prototype.format = function(value) {
@@ -36,8 +36,10 @@ getJasmineRequireObj().pp = function(j$) {
this.emitScalar('HTMLNode');
} else if (value instanceof Date) {
this.emitScalar('Date(' + value + ')');
} else if (value.toString && value.toString() == '[object Set]') {
} else if (j$.getType_(value) == '[object Set]') {
this.emitSet(value);
} else if (j$.getType_(value) == '[object Map]') {
this.emitMap(value);
} else if (value.toString && typeof value === 'object' && !j$.isArray_(value) && hasCustomToString(value)) {
this.emitScalar(value.toString());
} else if (j$.util.arrayContains(this.seen, value)) {
@@ -59,15 +61,28 @@ getJasmineRequireObj().pp = function(j$) {
};
PrettyPrinter.prototype.iterateObject = function(obj, fn) {
for (var property in obj) {
if (!Object.prototype.hasOwnProperty.call(obj, property)) { continue; }
fn(property, obj.__lookupGetter__ ? (!j$.util.isUndefined(obj.__lookupGetter__(property)) &&
obj.__lookupGetter__(property) !== null) : false);
var objKeys = keys(obj, j$.isArray_(obj));
var isGetter = function isGetter(prop) {};
if (obj.__lookupGetter__) {
isGetter = function isGetter(prop) {
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++) {
var property = objKeys[i];
fn(property, isGetter(property));
}
return objKeys.length > length;
};
PrettyPrinter.prototype.emitArray = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitSet = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitMap = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitObject = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitScalar = j$.unimplementedMethod_;
PrettyPrinter.prototype.emitString = j$.unimplementedMethod_;
@@ -75,7 +90,7 @@ getJasmineRequireObj().pp = function(j$) {
function StringPrettyPrinter() {
PrettyPrinter.call(this);
this.string = '';
this.stringParts = [];
}
j$.util.inherit(StringPrettyPrinter, PrettyPrinter);
@@ -107,11 +122,7 @@ getJasmineRequireObj().pp = function(j$) {
var self = this;
var first = array.length === 0;
this.iterateObject(array, function(property, isGetter) {
if (property.match(/^\d+$/)) {
return;
}
var truncated = this.iterateObject(array, function(property, isGetter) {
if (first) {
first = false;
} else {
@@ -121,6 +132,8 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(array, property, isGetter);
});
if (truncated) { this.append(', ...'); }
this.append(' ]');
};
@@ -144,6 +157,26 @@ getJasmineRequireObj().pp = function(j$) {
this.append(' )');
};
StringPrettyPrinter.prototype.emitMap = function(map) {
if (this.ppNestLevel_ > j$.MAX_PRETTY_PRINT_DEPTH) {
this.append('Map');
return;
}
this.append('Map( ');
var size = Math.min(map.size, j$.MAX_PRETTY_PRINT_ARRAY_LENGTH);
var iter = map.entries();
for (var i = 0; i < size; i++) {
if (i > 0) {
this.append(', ');
}
this.format(iter.next().value);
}
if (map.size > size){
this.append(', ...');
}
this.append(' )');
};
StringPrettyPrinter.prototype.emitObject = function(obj) {
var ctor = obj.constructor,
constructorName;
@@ -162,7 +195,7 @@ getJasmineRequireObj().pp = function(j$) {
this.append('({ ');
var first = true;
this.iterateObject(obj, function(property, isGetter) {
var truncated = this.iterateObject(obj, function(property, isGetter) {
if (first) {
first = false;
} else {
@@ -172,6 +205,8 @@ getJasmineRequireObj().pp = function(j$) {
self.formatProperty(obj, property, isGetter);
});
if (truncated) { this.append(', ...'); }
this.append(' })');
};
@@ -186,12 +221,41 @@ getJasmineRequireObj().pp = function(j$) {
};
StringPrettyPrinter.prototype.append = function(value) {
this.string += value;
this.stringParts.push(value);
};
function keys(obj, isArray) {
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);
}
}
return keys;
})(obj);
if (!isArray) {
return allKeys;
}
if (allKeys.length === 0) {
return allKeys;
}
var extraKeys = [];
for (var i = 0; i < allKeys.length; i++) {
if (!/^[0-9]+$/.test(allKeys[i])) {
extraKeys.push(allKeys[i]);
}
}
return extraKeys;
}
return function(value) {
var stringPrettyPrinter = new StringPrettyPrinter();
stringPrettyPrinter.format(value);
return stringPrettyPrinter.string;
return stringPrettyPrinter.stringParts.join('');
};
};

View File

@@ -12,15 +12,18 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
function QueueRunner(attrs) {
this.queueableFns = attrs.queueableFns || [];
var queueableFns = attrs.queueableFns || [];
this.queueableFns = queueableFns.concat(attrs.cleanupFns || []);
this.firstCleanupIx = queueableFns.length;
this.onComplete = attrs.onComplete || function() {};
this.clearStack = attrs.clearStack || function(fn) {fn();};
this.onException = attrs.onException || function() {};
this.catchException = attrs.catchException || function() { return true; };
this.userContext = attrs.userContext || {};
this.userContext = attrs.userContext || new j$.UserContext();
this.timeout = attrs.timeout || {setTimeout: setTimeout, clearTimeout: clearTimeout};
this.fail = attrs.fail || function() {};
this.globalErrors = attrs.globalErrors || { pushListener: function() {}, popListener: function() {} };
this.completeOnFirstError = !!attrs.completeOnFirstError;
}
QueueRunner.prototype.execute = function() {
@@ -29,22 +32,33 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onException(error);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(this.queueableFns, 0);
this.run(0);
};
QueueRunner.prototype.run = function(queueableFns, recursiveIndex) {
var length = queueableFns.length,
QueueRunner.prototype.skipToCleanup = function(lastRanIndex) {
if (lastRanIndex < this.firstCleanupIx) {
this.run(this.firstCleanupIx);
} else {
this.run(lastRanIndex + 1);
}
};
QueueRunner.prototype.run = function(recursiveIndex) {
var length = this.queueableFns.length,
self = this,
iterativeIndex;
for(iterativeIndex = recursiveIndex; iterativeIndex < length; iterativeIndex++) {
var queueableFn = queueableFns[iterativeIndex];
if (queueableFn.fn.length > 0) {
attemptAsync(queueableFn);
var result = attempt(iterativeIndex);
if (!result.completedSynchronously) {
return;
}
if (this.completeOnFirstError && result.errored) {
this.skipToCleanup(iterativeIndex);
return;
} else {
attemptSync(queueableFn);
}
}
@@ -53,62 +67,93 @@ getJasmineRequireObj().QueueRunner = function(j$) {
self.onComplete();
});
function attemptSync(queueableFn) {
try {
queueableFn.fn.call(self.userContext);
} catch (e) {
handleException(e, queueableFn);
}
}
function attemptAsync(queueableFn) {
function attempt() {
var clearTimeout = function () {
Function.prototype.apply.apply(self.timeout.clearTimeout, [j$.getGlobal(), [timeoutId]]);
},
setTimeout = function(delayedFn, delay) {
return Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [delayedFn, delay]]);
},
completedSynchronously = true,
handleError = function(error) {
onException(error);
next();
},
next = once(function () {
cleanup = once(function() {
clearTimeout(timeoutId);
self.globalErrors.popListener(handleError);
self.run(queueableFns, iterativeIndex + 1);
}),
next = once(function () {
cleanup();
function runNext() {
if (self.completeOnFirstError && errored) {
self.skipToCleanup(iterativeIndex);
} else {
self.run(iterativeIndex + 1);
}
}
if (completedSynchronously) {
setTimeout(runNext);
} else {
runNext();
}
}),
errored = false,
queueableFn = self.queueableFns[iterativeIndex],
timeoutId;
next.fail = function() {
self.fail.apply(null, arguments);
errored = true;
next();
};
self.globalErrors.pushListener(handleError);
if (queueableFn.timeout) {
timeoutId = Function.prototype.apply.apply(self.timeout.setTimeout, [j$.getGlobal(), [function() {
timeoutId = setTimeout(function() {
var error = new Error('Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.');
onException(error);
next();
}, queueableFn.timeout()]]);
}, queueableFn.timeout());
}
try {
queueableFn.fn.call(self.userContext, next);
if (queueableFn.fn.length === 0) {
var maybeThenable = queueableFn.fn.call(self.userContext);
if (maybeThenable && j$.isFunction_(maybeThenable.then)) {
maybeThenable.then(next, next.fail);
completedSynchronously = false;
return { completedSynchronously: false };
}
} else {
queueableFn.fn.call(self.userContext, next);
completedSynchronously = false;
return { completedSynchronously: false };
}
} catch (e) {
handleException(e, queueableFn);
next();
errored = true;
}
}
function onException(e) {
self.onException(e);
}
cleanup();
return { completedSynchronously: true, errored: errored };
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
function onException(e) {
self.onException(e);
errored = true;
}
function handleException(e, queueableFn) {
onException(e);
if (!self.catchException(e)) {
//TODO: set a var when we catch an exception and
//use a finally block to close the loop in a nice way..
throw e;
}
}
}
};

View File

@@ -50,20 +50,25 @@ getJasmineRequireObj().Spec = function(j$) {
this.onStart(this);
if (!this.isExecutable() || this.markedPending || enabled === false) {
complete(enabled);
return;
}
var fns = this.beforeAndAfterFns();
var allFns = fns.befores.concat(this.queueableFn).concat(fns.afters);
var regularFns = fns.befores.concat(this.queueableFn);
this.queueRunnerFactory({
queueableFns: allFns,
var runnerConfig = {
isLeaf: true,
queueableFns: regularFns,
cleanupFns: fns.afters,
onException: function() { self.onException.apply(self, arguments); },
onComplete: complete,
userContext: this.userContext()
});
};
if (!this.isExecutable() || this.markedPending || enabled === false) {
runnerConfig.queueableFns = [];
runnerConfig.cleanupFns = [];
runnerConfig.onComplete = function() { complete(enabled); };
}
this.queueRunnerFactory(runnerConfig);
function complete(enabledAgain) {
self.result.status = self.status(enabledAgain);

View File

@@ -88,14 +88,14 @@ getJasmineRequireObj().Suite = function(j$) {
Suite.prototype.sharedUserContext = function() {
if (!this.sharedContext) {
this.sharedContext = this.parentSuite ? clone(this.parentSuite.sharedUserContext()) : {};
this.sharedContext = this.parentSuite ? this.parentSuite.clonedSharedUserContext() : new j$.UserContext();
}
return this.sharedContext;
};
Suite.prototype.clonedSharedUserContext = function() {
return clone(this.sharedUserContext());
return j$.UserContext.fromExisting(this.sharedUserContext());
};
Suite.prototype.onException = function() {
@@ -147,17 +147,6 @@ getJasmineRequireObj().Suite = function(j$) {
return !args[0];
}
function clone(obj) {
var clonedObj = {};
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
clonedObj[prop] = obj[prop];
}
}
return clonedObj;
}
return Suite;
};

18
src/core/UserContext.js Normal file
View File

@@ -0,0 +1,18 @@
getJasmineRequireObj().UserContext = function(j$) {
function UserContext() {
}
UserContext.fromExisting = function(oldContext) {
var context = new UserContext();
for (var prop in oldContext) {
if (oldContext.hasOwnProperty(prop)) {
context[prop] = oldContext[prop];
}
}
return context;
};
return UserContext;
};

View File

@@ -11,6 +11,7 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
j$.MAX_PRETTY_PRINT_DEPTH = 40;
/**
* Maximum number of array elements to display when pretty printing objects.
* 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
*/
@@ -58,6 +59,10 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
return j$.isA_('Function', value);
};
j$.isAsyncFunction_ = function(value) {
return j$.isA_('AsyncFunction', value);
};
j$.isA_ = function(typeName, value) {
return j$.getType_(value) === '[object ' + typeName + ']';
};

View File

@@ -239,12 +239,12 @@ getJasmineRequireObj().matchersUtil = function(j$) {
if (!result) {
return false;
}
} else if (className == '[object Set]') {
} else if (className == '[object Set]' || className == '[object Map]') {
if (a.size != b.size) {
diffBuilder.record(a, b);
return false;
}
var iterA = a.values(), iterB = b.values();
var iterA = a.entries(), iterB = b.entries();
var valA, valB;
do {
valA = iterA.next();

View File

@@ -15,8 +15,18 @@ getJasmineRequireObj().toBeCloseTo = function() {
precision = precision || 2;
}
if (expected === null || actual === null) {
throw new Error('Cannot use toBeCloseTo with null. Arguments evaluated to: ' +
'expect(' + actual + ').toBeCloseTo(' + expected + ').'
);
}
var pow = Math.pow(10, precision + 1);
var delta = Math.abs(expected - actual);
var maxDelta = Math.pow(10, -precision) / 2;
return {
pass: Math.abs(expected - actual) < (Math.pow(10, -precision) / 2)
pass: Math.round(delta * pow) / pow <= maxDelta
};
}
};

View File

@@ -49,6 +49,7 @@ var getJasmineRequireObj = (function (jasmineGlobal) {
j$.SpyRegistry = jRequire.SpyRegistry(j$);
j$.SpyStrategy = jRequire.SpyStrategy(j$);
j$.StringMatching = jRequire.StringMatching(j$);
j$.UserContext = jRequire.UserContext(j$);
j$.Suite = jRequire.Suite(j$);
j$.Timer = jRequire.Timer();
j$.TreeProcessor = jRequire.TreeProcessor();

View File

@@ -181,7 +181,7 @@ jasmineRequire.HtmlReporter = function(j$) {
if (specsExecuted < totalSpecsDefined) {
var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all';
var skippedLink = order && order.random ? '?random=true' : '?';
var skippedLink = addToExistingQueryString('spec', '');
alert.appendChild(
createDom('span', {className: 'jasmine-bar jasmine-skipped'},
createDom('a', {href: skippedLink, title: 'Run all specs'}, skippedMessage)

View File

@@ -1,4 +1,10 @@
#!/bin/bash -e
rm -rf ~/.nvm
git clone https://github.com/creationix/nvm.git ~/.nvm
(cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`)
source ~/.nvm/nvm.sh
nvm install v0.12.18
npm install
npm test