Compare commits

..

7 Commits

Author SHA1 Message Date
Gregg Van Hove
5d1d19f494 Bump version to 2.6.2 2017-05-17 17:24:16 -07:00
Steve Gravrock
4f49288f31 Built distribution
- Fixes #1327
- Fixes jasmine/gulp-jasmine-browser#48
2017-05-16 14:36:35 -07:00
Steve Gravrock
b9adc76dc7 Clear the stack if onmessage is called before the previous invocation finishes 2017-05-16 14:08:58 -07:00
Gregg Van Hove
5ac3e21abb Merge branch 'interleaved-suites' of https://github.com/sgravrock/jasmine into sgravrock-interleaved-suites
- Merges #1352 from @sgravrock
- Fixes #1344
- Fixes #1349
2017-05-10 13:49:05 -07:00
Steve Gravrock
b1e97cfb09 Correctly route errors that occur while a QueueRunner is clearing stack
Besides surfacing the error in the hopefully-correct place, this also
prevents the queue runners for sibling suites from interleaving, which
in turn prevents all kinds of internal state corruption.

Signed-off-by: Gregg Van Hove <gvanhove@pivotal.io>
2017-05-09 15:01:18 -07:00
Gregg Van Hove
8e5823c0d2 Merge branch 'sgravrock-global-errors-rethrow'
- Merges #1347 from @sgravrock
2017-05-08 14:15:34 -07:00
Steve Gravrock
10f1220e55 Don't mask errors that occur when no handlers are installed
It's possible for async code to cause an error when Jasmine
doesn't have any listeners registered internally. This causes
Jasmine to crash (Node) or log to the console (browser)
because of trying to call the nonexistent handler. This change
doesn't fix the overall problem but it does ensure that the
original error is logged rather than Jasmine's internal error.
2017-05-08 11:09:32 -07:00
12 changed files with 187 additions and 11 deletions

View File

@@ -854,6 +854,10 @@ getJasmineRequireObj().Env = function(j$) {
reporter.suiteStarted(suite.result);
},
nodeComplete: function(suite, result) {
if (suite !== currentSuite()) {
throw new Error('Tried to complete the wrong suite');
}
if (!suite.markedPending) {
clearResourcesForRunnable(suite.id);
}
@@ -1601,11 +1605,22 @@ getJasmineRequireObj().clearStack = function(j$) {
head = {},
tail = head;
var taskRunning = false;
channel.port1.onmessage = function() {
head = head.next;
var task = head.task;
delete head.task;
task();
if (taskRunning) {
global.setTimeout(task, 0);
} else {
try {
taskRunning = true;
task();
} finally {
taskRunning = false;
}
}
};
return function clearStack(fn) {
@@ -2168,7 +2183,12 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
var onerror = function onerror() {
var handler = handlers[handlers.length - 1];
handler.apply(null, Array.prototype.slice.call(arguments, 0));
if (handler) {
handler.apply(null, Array.prototype.slice.call(arguments, 0));
} else {
throw arguments[0];
}
};
this.uninstall = function noop() {};
@@ -3823,6 +3843,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
QueueRunner.prototype.execute = function() {
var self = this;
this.handleFinalError = function(error) {
self.onException(error);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(this.queueableFns, 0);
};
@@ -3842,7 +3867,10 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
}
this.clearStack(this.onComplete);
this.clearStack(function() {
self.globalErrors.popListener(self.handleFinalError);
self.onComplete();
});
function attemptSync(queueableFn) {
try {
@@ -4937,5 +4965,5 @@ getJasmineRequireObj().TreeProcessor = function() {
};
getJasmineRequireObj().version = function() {
return '2.6.1';
return '2.6.2';
};

View File

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

View File

@@ -1,7 +1,7 @@
{
"name": "jasmine-core",
"license": "MIT",
"version": "2.6.1",
"version": "2.6.2",
"repository": {
"type": "git",
"url": "https://github.com/jasmine/jasmine.git"

23
release_notes/2.6.2.md Normal file
View File

@@ -0,0 +1,23 @@
# Jasmine 2.6.2 Release Notes
## Summary
This is a patch release to fix some regressions and performance problems in the 2.6.0 release
## Changes
* Clear the stack if onmessage is called before the previous invocation finishes
- Fixes #1327
- Fixes jasmine/gulp-jasmine-browser#48
* Correctly route errors that occur while a QueueRunner is clearing stack
- Merges #1352 from @sgravrock
- Fixes #1344
- Fixes #1349
* Don't mask errors that occur when no handlers are installed
- Merges #1347 from @sgravrock
------
_Release Notes generated with _[Anchorman](http://github.com/infews/anchorman)_

View File

@@ -37,6 +37,27 @@ describe("ClearStack", function() {
expect(called).toBe(true);
});
it("calls setTimeout when onmessage is called recursively", function() {
var fakeChannel = {
port1: {},
port2: { postMessage: function() { fakeChannel.port1.onmessage(); } }
},
setTimeout = jasmine.createSpy('setTimeout'),
global = {
MessageChannel: function() { return fakeChannel; },
setTimeout: setTimeout,
},
clearStack = jasmineUnderTest.getClearStack(global),
fn = jasmine.createSpy("second clearStack function");
clearStack(function() {
clearStack(fn);
});
expect(fn).not.toHaveBeenCalled();
expect(setTimeout).toHaveBeenCalledWith(fn, 0);
});
it("falls back to setTimeout", function() {
var setTimeout = jasmine.createSpy('setTimeout').and.callFake(function(fn) { fn() }),
global = { setTimeout: setTimeout },

View File

@@ -62,6 +62,22 @@ describe("GlobalErrors", function() {
expect(fakeGlobal.onerror).toBe(originalCallback);
});
it("rethrows the original error when there is no handler", function() {
var fakeGlobal = { },
errors = new jasmineUnderTest.GlobalErrors(fakeGlobal),
originalError = new Error('nope');
errors.install();
try {
fakeGlobal.onerror(originalError);
} catch (e) {
expect(e).toBe(originalError);
}
errors.uninstall();
});
it("works in node.js", function() {
var fakeGlobal = {
process: {

View File

@@ -252,7 +252,7 @@ describe("QueueRunner", function() {
nextQueueableFn.fn.and.callFake(function() {
// should remove the same function that was added
expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(0)[0]);
expect(globalErrors.popListener).toHaveBeenCalledWith(globalErrors.pushListener.calls.argsFor(1)[0]);
});
queueRunner.execute();
@@ -314,6 +314,32 @@ 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');
queueRunner.execute();
expect(clearStack).toHaveBeenCalled();
expect(errorListeners.length).toEqual(1);
errorListeners[0](error);
clearStack.calls.argsFor(0)[0]();
expect(onException).toHaveBeenCalledWith(error);
});
it("calls a provided complete callback when done", function() {
var queueableFn = { fn: jasmine.createSpy('fn') },
completeCallback = jasmine.createSpy('completeCallback'),
@@ -342,6 +368,8 @@ describe("QueueRunner", function() {
queueRunner.execute();
expect(afterFn.fn).toHaveBeenCalled();
expect(clearStack).toHaveBeenCalledWith(completeCallback);
expect(clearStack).toHaveBeenCalled();
clearStack.calls.argsFor(0)[0]();
expect(completeCallback).toHaveBeenCalled();
});
});

View File

@@ -456,6 +456,38 @@ describe("Env integration", function() {
env.execute();
});
it("copes with late async failures", function(done) {
var global = {
setTimeout: function(fn, delay) { setTimeout(fn, delay) },
clearTimeout: function(fn, delay) { clearTimeout(fn, delay) },
};
spyOn(jasmineUnderTest, 'getGlobal').and.returnValue(global);
var env = new jasmineUnderTest.Env(),
reporter = jasmine.createSpyObj('fakeReporter', [ "specDone", "jasmineDone", "suiteDone" ]);
reporter.jasmineDone.and.callFake(function() {
expect(reporter.suiteDone).toHaveFailedExpecationsForRunnable('A suite', ['fail thrown']);
done();
});
env.addReporter(reporter);
env.fdescribe('A suite', function() {
env.it('fails', function(specDone) {
specDone();
setTimeout(function() {
global.onerror('fail');
});
});
});
env.describe('Ignored', function() {
env.it('is not run', function() {});
});
env.execute();
});
describe('suiteDone reporting', function(){
it("reports when an afterAll fails an expectation", function(done) {
var env = new jasmineUnderTest.Env(),

View File

@@ -4,11 +4,22 @@ getJasmineRequireObj().clearStack = function(j$) {
head = {},
tail = head;
var taskRunning = false;
channel.port1.onmessage = function() {
head = head.next;
var task = head.task;
delete head.task;
task();
if (taskRunning) {
global.setTimeout(task, 0);
} else {
try {
taskRunning = true;
task();
} finally {
taskRunning = false;
}
}
};
return function clearStack(fn) {

View File

@@ -238,6 +238,10 @@ getJasmineRequireObj().Env = function(j$) {
reporter.suiteStarted(suite.result);
},
nodeComplete: function(suite, result) {
if (suite !== currentSuite()) {
throw new Error('Tried to complete the wrong suite');
}
if (!suite.markedPending) {
clearResourcesForRunnable(suite.id);
}

View File

@@ -5,7 +5,12 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
var onerror = function onerror() {
var handler = handlers[handlers.length - 1];
handler.apply(null, Array.prototype.slice.call(arguments, 0));
if (handler) {
handler.apply(null, Array.prototype.slice.call(arguments, 0));
} else {
throw arguments[0];
}
};
this.uninstall = function noop() {};

View File

@@ -24,6 +24,11 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
QueueRunner.prototype.execute = function() {
var self = this;
this.handleFinalError = function(error) {
self.onException(error);
};
this.globalErrors.pushListener(this.handleFinalError);
this.run(this.queueableFns, 0);
};
@@ -43,7 +48,10 @@ getJasmineRequireObj().QueueRunner = function(j$) {
}
}
this.clearStack(this.onComplete);
this.clearStack(function() {
self.globalErrors.popListener(self.handleFinalError);
self.onComplete();
});
function attemptSync(queueableFn) {
try {