Added jasmine.spyOnGlobalErrorsAsync
* Allows testing code that's expected to prodeuce global errors or unhandled promise rejections * Fixes #1843 * Fixes #1453
This commit is contained in:
+151
-20
@@ -594,6 +594,49 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
j$.debugLog = function(msg) {
|
j$.debugLog = function(msg) {
|
||||||
j$.getEnv().debugLog(msg);
|
j$.getEnv().debugLog(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces Jasmine's global error handling with a spy. This prevents Jasmine
|
||||||
|
* from treating uncaught exceptions and unhandled promise rejections
|
||||||
|
* as spec failures and allows them to be inspected using the spy's
|
||||||
|
* {@link Spy#calls|calls property} and related matchers such as
|
||||||
|
* {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}.
|
||||||
|
*
|
||||||
|
* After installing the spy, spyOnGlobalErrorsAsync immediately calls its
|
||||||
|
* argument, which must be an async or promise-returning function. The spy
|
||||||
|
* will be passed as the first argument to that callback. Normal error
|
||||||
|
* handling will be restored when the promise returned from the callback is
|
||||||
|
* settled.
|
||||||
|
*
|
||||||
|
* Note: The JavaScript runtime may deliver uncaught error events and unhandled
|
||||||
|
* rejection events asynchronously, especially in browsers. If the event
|
||||||
|
* occurs after the promise returned from the callback is settled, it won't
|
||||||
|
* be routed to the spy even if the underlying error occurred previously.
|
||||||
|
* It's up to you to ensure that the returned promise isn't resolved until
|
||||||
|
* all of the error/rejection events that you want to handle have occurred.
|
||||||
|
*
|
||||||
|
* You must await the return value of spyOnGlobalErrorsAsync.
|
||||||
|
* @name jasmine.spyOnGlobalErrorsAsync
|
||||||
|
* @function
|
||||||
|
* @async
|
||||||
|
* @param {AsyncFunction} fn - A function to run, during which the global error spy will be effective
|
||||||
|
* @example
|
||||||
|
* it('demonstrates global error spies', async function() {
|
||||||
|
* await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
||||||
|
* setTimeout(function() {
|
||||||
|
* throw new Error('the expected error');
|
||||||
|
* });
|
||||||
|
* await new Promise(function(resolve) {
|
||||||
|
* setTimeout(resolve);
|
||||||
|
* });
|
||||||
|
* const expected = new Error('the expected error');
|
||||||
|
* expect(globalErrorSpy).toHaveBeenCalledWith(expected);
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
j$.spyOnGlobalErrorsAsync = async function(fn) {
|
||||||
|
await jasmine.getEnv().spyOnGlobalErrorsAsync(fn);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
getJasmineRequireObj().util = function(j$) {
|
getJasmineRequireObj().util = function(j$) {
|
||||||
@@ -764,6 +807,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
|
|
||||||
Spec.prototype.addExpectationResult = function(passed, data, isError) {
|
Spec.prototype.addExpectationResult = function(passed, data, isError) {
|
||||||
const expectationResult = j$.buildExpectationResult(data);
|
const expectationResult = j$.buildExpectationResult(data);
|
||||||
|
|
||||||
if (passed) {
|
if (passed) {
|
||||||
this.result.passedExpectations.push(expectationResult);
|
this.result.passedExpectations.push(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
@@ -771,6 +815,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
this.onLateError(expectationResult);
|
this.onLateError(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
this.result.failedExpectations.push(expectationResult);
|
this.result.failedExpectations.push(expectationResult);
|
||||||
|
|
||||||
|
// TODO: refactor so that we don't need to override cached status
|
||||||
|
if (this.result.status) {
|
||||||
|
this.result.status = 'failed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.throwOnExpectationFailure && !isError) {
|
if (this.throwOnExpectationFailure && !isError) {
|
||||||
@@ -1117,9 +1166,23 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
new j$.MockDate(global)
|
new j$.MockDate(global)
|
||||||
);
|
);
|
||||||
|
|
||||||
const runableResources = new j$.RunableResources(function() {
|
const globalErrors = new j$.GlobalErrors();
|
||||||
const r = runner.currentRunable();
|
const installGlobalErrors = (function() {
|
||||||
return r ? r.id : null;
|
let installed = false;
|
||||||
|
return function() {
|
||||||
|
if (!installed) {
|
||||||
|
globalErrors.install();
|
||||||
|
installed = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
const runableResources = new j$.RunableResources({
|
||||||
|
getCurrentRunableId: function() {
|
||||||
|
const r = runner.currentRunable();
|
||||||
|
return r ? r.id : null;
|
||||||
|
},
|
||||||
|
globalErrors
|
||||||
});
|
});
|
||||||
|
|
||||||
let reporter;
|
let reporter;
|
||||||
@@ -1226,20 +1289,9 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
verboseDeprecations: false
|
verboseDeprecations: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let globalErrors = null;
|
|
||||||
|
|
||||||
function installGlobalErrors() {
|
|
||||||
if (globalErrors) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalErrors = new j$.GlobalErrors();
|
|
||||||
globalErrors.install();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.suppressLoadErrors) {
|
if (!options.suppressLoadErrors) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
globalErrors.pushListener(function(
|
globalErrors.pushListener(function loadtimeErrorHandler(
|
||||||
message,
|
message,
|
||||||
filename,
|
filename,
|
||||||
lineno,
|
lineno,
|
||||||
@@ -1712,6 +1764,47 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.spyOnGlobalErrorsAsync = async function(fn) {
|
||||||
|
const spy = this.createSpy('global error handler');
|
||||||
|
const associatedRunable = runner.currentRunable();
|
||||||
|
let cleanedUp = false;
|
||||||
|
|
||||||
|
globalErrors.setOverrideListener(spy, () => {
|
||||||
|
if (!cleanedUp) {
|
||||||
|
const message =
|
||||||
|
'Global error spy was not uninstalled. (Did you ' +
|
||||||
|
'forget to await the return value of spyOnGlobalErrorsAsync?)';
|
||||||
|
associatedRunable.addExpectationResult(false, {
|
||||||
|
matcherName: '',
|
||||||
|
passed: false,
|
||||||
|
expected: '',
|
||||||
|
actual: '',
|
||||||
|
message,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanedUp = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const maybePromise = fn(spy);
|
||||||
|
|
||||||
|
if (!j$.isPromiseLike(maybePromise)) {
|
||||||
|
throw new Error(
|
||||||
|
'The callback to spyOnGlobalErrorsAsync must be an async or promise-returning function'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await maybePromise;
|
||||||
|
} finally {
|
||||||
|
if (!cleanedUp) {
|
||||||
|
cleanedUp = true;
|
||||||
|
globalErrors.removeOverrideListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function ensureIsNotNested(method) {
|
function ensureIsNotNested(method) {
|
||||||
const runable = runner.currentRunable();
|
const runable = runner.currentRunable();
|
||||||
if (runable !== null && runable !== undefined) {
|
if (runable !== null && runable !== undefined) {
|
||||||
@@ -3853,10 +3946,18 @@ getJasmineRequireObj().formatErrorMsg = function() {
|
|||||||
|
|
||||||
getJasmineRequireObj().GlobalErrors = function(j$) {
|
getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||||
function GlobalErrors(global) {
|
function GlobalErrors(global) {
|
||||||
const handlers = [];
|
|
||||||
global = global || j$.getGlobal();
|
global = global || j$.getGlobal();
|
||||||
|
|
||||||
const onerror = function onerror() {
|
const handlers = [];
|
||||||
|
let overrideHandler = null,
|
||||||
|
onRemoveOverrideHandler = null;
|
||||||
|
|
||||||
|
function onerror(message, source, lineno, colno, error) {
|
||||||
|
if (overrideHandler) {
|
||||||
|
overrideHandler(error || message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
@@ -3864,7 +3965,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
} else {
|
} else {
|
||||||
throw arguments[0];
|
throw arguments[0];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
this.originalHandlers = {};
|
this.originalHandlers = {};
|
||||||
this.jasmineHandlers = {};
|
this.jasmineHandlers = {};
|
||||||
@@ -3895,6 +3996,11 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
|
if (overrideHandler) {
|
||||||
|
overrideHandler(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(error);
|
handler(error);
|
||||||
} else {
|
} else {
|
||||||
@@ -3979,6 +4085,24 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
|
|
||||||
handlers.pop();
|
handlers.pop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.setOverrideListener = function(listener, onRemove) {
|
||||||
|
if (overrideHandler) {
|
||||||
|
throw new Error("Can't set more than one override listener at a time");
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideHandler = listener;
|
||||||
|
onRemoveOverrideHandler = onRemove;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.removeOverrideListener = function() {
|
||||||
|
if (onRemoveOverrideHandler) {
|
||||||
|
onRemoveOverrideHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideHandler = null;
|
||||||
|
onRemoveOverrideHandler = null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return GlobalErrors;
|
return GlobalErrors;
|
||||||
@@ -8083,9 +8207,10 @@ getJasmineRequireObj().interface = function(jasmine, env) {
|
|||||||
|
|
||||||
getJasmineRequireObj().RunableResources = function(j$) {
|
getJasmineRequireObj().RunableResources = function(j$) {
|
||||||
class RunableResources {
|
class RunableResources {
|
||||||
constructor(getCurrentRunableId) {
|
constructor(options) {
|
||||||
this.byRunableId_ = {};
|
this.byRunableId_ = {};
|
||||||
this.getCurrentRunableId_ = getCurrentRunableId;
|
this.getCurrentRunableId_ = options.getCurrentRunableId;
|
||||||
|
this.globalErrors_ = options.globalErrors;
|
||||||
|
|
||||||
this.spyFactory = new j$.SpyFactory(
|
this.spyFactory = new j$.SpyFactory(
|
||||||
() => {
|
() => {
|
||||||
@@ -8136,6 +8261,7 @@ getJasmineRequireObj().RunableResources = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearForRunable(runableId) {
|
clearForRunable(runableId) {
|
||||||
|
this.globalErrors_.removeOverrideListener();
|
||||||
this.spyRegistry.clearSpies();
|
this.spyRegistry.clearSpies();
|
||||||
delete this.byRunableId_[runableId];
|
delete this.byRunableId_[runableId];
|
||||||
}
|
}
|
||||||
@@ -9597,6 +9723,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.onLateError(expectationResult);
|
this.onLateError(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
this.result.failedExpectations.push(expectationResult);
|
this.result.failedExpectations.push(expectationResult);
|
||||||
|
|
||||||
|
// TODO: refactor so that we don't need to override cached status
|
||||||
|
if (this.result.status) {
|
||||||
|
this.result.status = 'failed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.throwOnExpectationFailure) {
|
if (this.throwOnExpectationFailure) {
|
||||||
|
|||||||
+19
-2
@@ -468,7 +468,8 @@ describe('Env', function() {
|
|||||||
'install',
|
'install',
|
||||||
'uninstall',
|
'uninstall',
|
||||||
'pushListener',
|
'pushListener',
|
||||||
'popListener'
|
'popListener',
|
||||||
|
'removeOverrideListener'
|
||||||
]);
|
]);
|
||||||
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
@@ -483,7 +484,8 @@ describe('Env', function() {
|
|||||||
'install',
|
'install',
|
||||||
'uninstall',
|
'uninstall',
|
||||||
'pushListener',
|
'pushListener',
|
||||||
'popListener'
|
'popListener',
|
||||||
|
'removeOverrideListener'
|
||||||
]);
|
]);
|
||||||
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
spyOn(jasmineUnderTest, 'GlobalErrors').and.returnValue(globalErrors);
|
||||||
env.cleanup_();
|
env.cleanup_();
|
||||||
@@ -591,4 +593,19 @@ describe('Env', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#spyOnGlobalErrorsAsync', function() {
|
||||||
|
it('throws if the callback does not return a promise', async function() {
|
||||||
|
const msg =
|
||||||
|
'The callback to spyOnGlobalErrorsAsync must be an async or ' +
|
||||||
|
'promise-returning function';
|
||||||
|
|
||||||
|
await expectAsync(
|
||||||
|
env.spyOnGlobalErrorsAsync(() => undefined)
|
||||||
|
).toBeRejectedWithError(msg);
|
||||||
|
await expectAsync(
|
||||||
|
env.spyOnGlobalErrorsAsync(() => 'not a promise')
|
||||||
|
).toBeRejectedWithError(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -404,4 +404,158 @@ describe('GlobalErrors', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#setOverrideListener', function() {
|
||||||
|
it('overrides the existing handlers in browsers until removed', function() {
|
||||||
|
const fakeGlobal = { onerror: null };
|
||||||
|
const handler0 = jasmine.createSpy('handler0');
|
||||||
|
const handler1 = jasmine.createSpy('handler1');
|
||||||
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler0);
|
||||||
|
errors.setOverrideListener(overrideHandler, () => {});
|
||||||
|
errors.pushListener(handler1);
|
||||||
|
fakeGlobal.onerror('foo');
|
||||||
|
fakeGlobal.onerror(null, null, null, null, new Error('bar'));
|
||||||
|
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith('foo');
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('bar'));
|
||||||
|
expect(handler0).not.toHaveBeenCalled();
|
||||||
|
expect(handler1).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
errors.removeOverrideListener();
|
||||||
|
|
||||||
|
fakeGlobal.onerror('baz');
|
||||||
|
expect(overrideHandler).not.toHaveBeenCalledWith('baz');
|
||||||
|
expect(handler1).toHaveBeenCalledWith('baz');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('overrides the existing handlers in Node until removed', function() {
|
||||||
|
const globalEventListeners = {};
|
||||||
|
const fakeGlobal = {
|
||||||
|
process: {
|
||||||
|
on: (name, listener) => (globalEventListeners[name] = listener),
|
||||||
|
removeListener: () => {},
|
||||||
|
listeners: name => globalEventListeners[name],
|
||||||
|
removeAllListeners: name => (globalEventListeners[name] = [])
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handler0 = jasmine.createSpy('handler0');
|
||||||
|
const handler1 = jasmine.createSpy('handler1');
|
||||||
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler0);
|
||||||
|
errors.setOverrideListener(overrideHandler);
|
||||||
|
errors.pushListener(handler1);
|
||||||
|
|
||||||
|
globalEventListeners['uncaughtException'](new Error('foo'));
|
||||||
|
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('foo'));
|
||||||
|
expect(handler0).not.toHaveBeenCalled();
|
||||||
|
expect(handler1).not.toHaveBeenCalled();
|
||||||
|
|
||||||
|
errors.removeOverrideListener();
|
||||||
|
|
||||||
|
globalEventListeners['uncaughtException'](new Error('bar'));
|
||||||
|
expect(overrideHandler).not.toHaveBeenCalledWith(new Error('bar'));
|
||||||
|
expect(handler1).toHaveBeenCalledWith(new Error('bar'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unhandled promise rejections in browsers', function() {
|
||||||
|
const globalEventListeners = {};
|
||||||
|
const fakeGlobal = {
|
||||||
|
addEventListener(name, listener) {
|
||||||
|
globalEventListeners[name] = listener;
|
||||||
|
},
|
||||||
|
removeEventListener() {}
|
||||||
|
};
|
||||||
|
const handler = jasmine.createSpy('handler');
|
||||||
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler);
|
||||||
|
errors.setOverrideListener(overrideHandler, () => {});
|
||||||
|
|
||||||
|
const reason = new Error('bar');
|
||||||
|
|
||||||
|
globalEventListeners['unhandledrejection']({ reason: reason });
|
||||||
|
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith(
|
||||||
|
jasmine.objectContaining({
|
||||||
|
jasmineMessage: 'Unhandled promise rejection: Error: bar',
|
||||||
|
message: reason.message,
|
||||||
|
stack: reason.stack
|
||||||
|
})
|
||||||
|
);
|
||||||
|
expect(handler).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('handles unhandled promise rejections in Node', function() {
|
||||||
|
const globalEventListeners = {};
|
||||||
|
const fakeGlobal = {
|
||||||
|
process: {
|
||||||
|
on(name, listener) {
|
||||||
|
globalEventListeners[name] = listener;
|
||||||
|
},
|
||||||
|
removeListener() {},
|
||||||
|
listeners(name) {
|
||||||
|
return globalEventListeners[name];
|
||||||
|
},
|
||||||
|
removeAllListeners(name) {
|
||||||
|
globalEventListeners[name] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handler0 = jasmine.createSpy('handler0');
|
||||||
|
const handler1 = jasmine.createSpy('handler1');
|
||||||
|
const overrideHandler = jasmine.createSpy('overrideHandler');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.install();
|
||||||
|
errors.pushListener(handler0);
|
||||||
|
errors.setOverrideListener(overrideHandler, () => {});
|
||||||
|
errors.pushListener(handler1);
|
||||||
|
|
||||||
|
globalEventListeners['unhandledRejection'](new Error('nope'));
|
||||||
|
|
||||||
|
expect(overrideHandler).toHaveBeenCalledWith(new Error('nope'));
|
||||||
|
expect(handler0).not.toHaveBeenCalled();
|
||||||
|
expect(handler1).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if there is already an override handler', function() {
|
||||||
|
const fakeGlobal = { onerror: null };
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.setOverrideListener(() => {}, () => {});
|
||||||
|
expect(function() {
|
||||||
|
errors.setOverrideListener(() => {}, () => {});
|
||||||
|
}).toThrowError("Can't set more than one override listener at a time");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('#removeOverrideListener', function() {
|
||||||
|
it("calls the handler's onRemove callback", function() {
|
||||||
|
const fakeGlobal = { onerror: null };
|
||||||
|
const onRemove = jasmine.createSpy('onRemove');
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
errors.setOverrideListener(() => {}, onRemove);
|
||||||
|
errors.removeOverrideListener();
|
||||||
|
|
||||||
|
expect(onRemove).toHaveBeenCalledWith();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not throw if there is no handler', function() {
|
||||||
|
const fakeGlobal = { onerror: null };
|
||||||
|
const errors = new jasmineUnderTest.GlobalErrors(fakeGlobal);
|
||||||
|
|
||||||
|
expect(() => errors.removeOverrideListener()).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ describe('RunableResources', function() {
|
|||||||
describe('#addCustomMatchers', function() {
|
describe('#addCustomMatchers', function() {
|
||||||
it("adds all properties to the current runable's matchers", function() {
|
it("adds all properties to the current runable's matchers", function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
function toBeFoo() {}
|
function toBeFoo() {}
|
||||||
@@ -69,9 +70,10 @@ describe('RunableResources', function() {
|
|||||||
describe('#addCustomAsyncMatchers', function() {
|
describe('#addCustomAsyncMatchers', function() {
|
||||||
it("adds all properties to the current runable's matchers", function() {
|
it("adds all properties to the current runable's matchers", function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
function toBeFoo() {}
|
function toBeFoo() {}
|
||||||
@@ -93,9 +95,10 @@ describe('RunableResources', function() {
|
|||||||
describe('#defaultSpyStrategy', function() {
|
describe('#defaultSpyStrategy', function() {
|
||||||
it('returns undefined for a newly initialized resource', function() {
|
it('returns undefined for a newly initialized resource', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
|
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
|
||||||
@@ -103,9 +106,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('returns the value previously set by #setDefaultSpyStrategy', function() {
|
it('returns the value previously set by #setDefaultSpyStrategy', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
const fn = () => {};
|
const fn = () => {};
|
||||||
runableResources.setDefaultSpyStrategy(fn);
|
runableResources.setDefaultSpyStrategy(fn);
|
||||||
@@ -115,9 +119,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('is per-runable', function() {
|
it('is per-runable', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
runableResources.setDefaultSpyStrategy(() => {});
|
runableResources.setDefaultSpyStrategy(() => {});
|
||||||
currentRunableId = 2;
|
currentRunableId = 2;
|
||||||
@@ -127,17 +132,19 @@ describe('RunableResources', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('does not require a current runable', function() {
|
it('does not require a current runable', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
|
expect(runableResources.defaultSpyStrategy()).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("inherits the parent runable's value", function() {
|
it("inherits the parent runable's value", function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
const fn = () => {};
|
const fn = () => {};
|
||||||
runableResources.setDefaultSpyStrategy(fn);
|
runableResources.setDefaultSpyStrategy(fn);
|
||||||
@@ -150,9 +157,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('#setDefaultSpyStrategy', function() {
|
describe('#setDefaultSpyStrategy', function() {
|
||||||
it('throws a user-facing error when there is no current runable', function() {
|
it('throws a user-facing error when there is no current runable', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
runableResources.setDefaultSpyStrategy();
|
runableResources.setDefaultSpyStrategy();
|
||||||
}).toThrowError(
|
}).toThrowError(
|
||||||
@@ -163,7 +171,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('#makePrettyPrinter', function() {
|
describe('#makePrettyPrinter', function() {
|
||||||
it('returns a pretty printer configured with the current customObjectFormatters', function() {
|
it('returns a pretty printer configured with the current customObjectFormatters', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function cof() {}
|
function cof() {}
|
||||||
runableResources.customObjectFormatters().push(cof);
|
runableResources.customObjectFormatters().push(cof);
|
||||||
@@ -182,7 +193,10 @@ describe('RunableResources', function() {
|
|||||||
describe('#makeMatchersUtil', function() {
|
describe('#makeMatchersUtil', function() {
|
||||||
describe('When there is a current runable', function() {
|
describe('When there is a current runable', function() {
|
||||||
it('returns a MatchersUtil configured with the current resources', function() {
|
it('returns a MatchersUtil configured with the current resources', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function cof() {}
|
function cof() {}
|
||||||
runableResources.customObjectFormatters().push(cof);
|
runableResources.customObjectFormatters().push(cof);
|
||||||
@@ -217,9 +231,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('When there is no current runable', function() {
|
describe('When there is no current runable', function() {
|
||||||
it('returns a MatchersUtil configured with defaults', function() {
|
it('returns a MatchersUtil configured with defaults', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
const expectedMatchersUtil = {};
|
const expectedMatchersUtil = {};
|
||||||
spyOn(jasmineUnderTest, 'MatchersUtil').and.returnValue(
|
spyOn(jasmineUnderTest, 'MatchersUtil').and.returnValue(
|
||||||
expectedMatchersUtil
|
expectedMatchersUtil
|
||||||
@@ -243,9 +258,10 @@ describe('RunableResources', function() {
|
|||||||
describe('.spyFactory', function() {
|
describe('.spyFactory', function() {
|
||||||
describe('When there is no current runable', function() {
|
describe('When there is no current runable', function() {
|
||||||
it('is configured with default strategies and matchersUtil', function() {
|
it('is configured with default strategies and matchersUtil', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
spyOn(jasmineUnderTest, 'Spy');
|
spyOn(jasmineUnderTest, 'Spy');
|
||||||
const matchersUtil = {};
|
const matchersUtil = {};
|
||||||
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
|
spyOn(runableResources, 'makeMatchersUtil').and.returnValue(
|
||||||
@@ -267,7 +283,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('When there is a current runable', function() {
|
describe('When there is a current runable', function() {
|
||||||
it("is configured with the current runable's strategies and matchersUtil", function() {
|
it("is configured with the current runable's strategies and matchersUtil", function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function customStrategy() {}
|
function customStrategy() {}
|
||||||
function defaultStrategy() {}
|
function defaultStrategy() {}
|
||||||
@@ -306,7 +325,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('.spyRegistry', function() {
|
describe('.spyRegistry', function() {
|
||||||
it("writes to the current runable's spies", function() {
|
it("writes to the current runable's spies", function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function foo() {}
|
function foo() {}
|
||||||
const spyObj = { foo };
|
const spyObj = { foo };
|
||||||
@@ -326,7 +348,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
describe('#clearForRunable', function() {
|
describe('#clearForRunable', function() {
|
||||||
it('removes resources for the specified runable', function() {
|
it('removes resources for the specified runable', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
runableResources.spies();
|
runableResources.spies();
|
||||||
@@ -338,7 +363,10 @@ describe('RunableResources', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('clears spies', function() {
|
it('clears spies', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function foo() {}
|
function foo() {}
|
||||||
const spyObj = { foo };
|
const spyObj = { foo };
|
||||||
@@ -349,8 +377,25 @@ describe('RunableResources', function() {
|
|||||||
expect(spyObj.foo).toBe(foo);
|
expect(spyObj.foo).toBe(foo);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('clears the global error spy', function() {
|
||||||
|
const globalErrors = jasmine.createSpyObj('globalErrors', [
|
||||||
|
'removeOverrideListener'
|
||||||
|
]);
|
||||||
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
getCurrentRunableId: () => 1,
|
||||||
|
globalErrors
|
||||||
|
});
|
||||||
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
|
runableResources.clearForRunable(1);
|
||||||
|
expect(globalErrors.removeOverrideListener).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('does not remove resources for other runables', function() {
|
it('does not remove resources for other runables', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(() => 1);
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
|
globalErrors: stubGlobalErrors(),
|
||||||
|
getCurrentRunableId: () => 1
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function cof() {}
|
function cof() {}
|
||||||
runableResources.customObjectFormatters().push(cof);
|
runableResources.customObjectFormatters().push(cof);
|
||||||
@@ -366,9 +411,10 @@ describe('RunableResources', function() {
|
|||||||
) {
|
) {
|
||||||
it('is initially empty', function() {
|
it('is initially empty', function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
expect(runableResources[methodName]()).toEqual([]);
|
expect(runableResources[methodName]()).toEqual([]);
|
||||||
@@ -376,9 +422,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('is mutable', function() {
|
it('is mutable', function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function newItem() {}
|
function newItem() {}
|
||||||
runableResources[methodName]().push(newItem);
|
runableResources[methodName]().push(newItem);
|
||||||
@@ -387,9 +434,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('is per-runable', function() {
|
it('is per-runable', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
runableResources[methodName]().push(() => {});
|
runableResources[methodName]().push(() => {});
|
||||||
runableResources.initForRunable(2);
|
runableResources.initForRunable(2);
|
||||||
@@ -398,9 +446,10 @@ describe('RunableResources', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws a user-facing error when there is no current runable', function() {
|
it('throws a user-facing error when there is no current runable', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
runableResources[methodName]();
|
runableResources[methodName]();
|
||||||
}).toThrowError(errorMsg);
|
}).toThrowError(errorMsg);
|
||||||
@@ -409,9 +458,10 @@ describe('RunableResources', function() {
|
|||||||
if (inherits) {
|
if (inherits) {
|
||||||
it('inherits from the parent runable', function() {
|
it('inherits from the parent runable', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function parentItem() {}
|
function parentItem() {}
|
||||||
runableResources[methodName]().push(parentItem);
|
runableResources[methodName]().push(parentItem);
|
||||||
@@ -430,9 +480,10 @@ describe('RunableResources', function() {
|
|||||||
function behavesLikeAPerRunableMutableObject(methodName, errorMsg) {
|
function behavesLikeAPerRunableMutableObject(methodName, errorMsg) {
|
||||||
it('is initially empty', function() {
|
it('is initially empty', function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
|
|
||||||
expect(runableResources[methodName]()).toEqual({});
|
expect(runableResources[methodName]()).toEqual({});
|
||||||
@@ -440,9 +491,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('is mutable', function() {
|
it('is mutable', function() {
|
||||||
const currentRunableId = 1;
|
const currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function newItem() {}
|
function newItem() {}
|
||||||
runableResources[methodName]().foo = newItem;
|
runableResources[methodName]().foo = newItem;
|
||||||
@@ -451,9 +503,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('is per-runable', function() {
|
it('is per-runable', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
runableResources[methodName]().foo = function() {};
|
runableResources[methodName]().foo = function() {};
|
||||||
runableResources.initForRunable(2);
|
runableResources.initForRunable(2);
|
||||||
@@ -462,9 +515,10 @@ describe('RunableResources', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('throws a user-facing error when there is no current runable', function() {
|
it('throws a user-facing error when there is no current runable', function() {
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => null
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => null
|
||||||
|
});
|
||||||
expect(function() {
|
expect(function() {
|
||||||
runableResources[methodName]();
|
runableResources[methodName]();
|
||||||
}).toThrowError(errorMsg);
|
}).toThrowError(errorMsg);
|
||||||
@@ -472,9 +526,10 @@ describe('RunableResources', function() {
|
|||||||
|
|
||||||
it('inherits from the parent runable', function() {
|
it('inherits from the parent runable', function() {
|
||||||
let currentRunableId = 1;
|
let currentRunableId = 1;
|
||||||
const runableResources = new jasmineUnderTest.RunableResources(
|
const runableResources = new jasmineUnderTest.RunableResources({
|
||||||
() => currentRunableId
|
globalErrors: stubGlobalErrors(),
|
||||||
);
|
getCurrentRunableId: () => currentRunableId
|
||||||
|
});
|
||||||
runableResources.initForRunable(1);
|
runableResources.initForRunable(1);
|
||||||
function parentItem() {}
|
function parentItem() {}
|
||||||
runableResources[methodName]().parentName = parentItem;
|
runableResources[methodName]().parentName = parentItem;
|
||||||
@@ -493,4 +548,10 @@ describe('RunableResources', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stubGlobalErrors() {
|
||||||
|
return {
|
||||||
|
removeOverrideListener() {}
|
||||||
|
};
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -3625,4 +3625,285 @@ describe('Env integration', function() {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('#spyOnGlobalErrorsAsync', function() {
|
||||||
|
const leftInstalledMessage =
|
||||||
|
'Global error spy was not uninstalled. ' +
|
||||||
|
'(Did you forget to await the return value of spyOnGlobalErrorsAsync?)';
|
||||||
|
|
||||||
|
function resultForRunable(reporterSpy, fullName) {
|
||||||
|
const match = reporterSpy.calls.all().find(function(call) {
|
||||||
|
return call.args[0].fullName === fullName;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!match) {
|
||||||
|
throw new Error(`No result for runable "${fullName}"`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return match.args[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
it('allows global errors to be suppressed and spied on', async function() {
|
||||||
|
env.it('a passing spec', async function() {
|
||||||
|
await env.spyOnGlobalErrorsAsync(async spy => {
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error('nope');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
env.expect(spy).toHaveBeenCalledWith(new Error('nope'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a failing spec', async function() {
|
||||||
|
await env.spyOnGlobalErrorsAsync(async spy => {
|
||||||
|
setTimeout(() => {
|
||||||
|
throw new Error('yep');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
env.expect(spy).toHaveBeenCalledWith(new Error('nope'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
const passingResult = resultForRunable(
|
||||||
|
reporter.specDone,
|
||||||
|
'a passing spec'
|
||||||
|
);
|
||||||
|
expect(passingResult.status).toEqual('passed');
|
||||||
|
expect(passingResult.failedExpectations).toEqual([]);
|
||||||
|
|
||||||
|
const failingResult = resultForRunable(
|
||||||
|
reporter.specDone,
|
||||||
|
'a failing spec'
|
||||||
|
);
|
||||||
|
expect(failingResult.status).toEqual('failed');
|
||||||
|
expect(failingResult.failedExpectations[0].message).toMatch(
|
||||||
|
/Expected \$\[0] = Error: yep to equal Error: nope\./
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cleans up if the global error spy is left installed in a beforeAll', async function() {
|
||||||
|
env.configure({ random: false });
|
||||||
|
|
||||||
|
env.describe('Suite 1', function() {
|
||||||
|
env.beforeAll(async function() {
|
||||||
|
env.spyOnGlobalErrorsAsync(function() {
|
||||||
|
// Never resolves
|
||||||
|
return new Promise(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('Suite 2', function() {
|
||||||
|
env.it('a spec', async function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
throw new Error('should fail the spec');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'specDone',
|
||||||
|
'suiteDone'
|
||||||
|
]);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
const suiteResult = resultForRunable(reporter.suiteDone, 'Suite 1');
|
||||||
|
expect(suiteResult.status).toEqual('failed');
|
||||||
|
expect(suiteResult.failedExpectations.length).toEqual(1);
|
||||||
|
expect(suiteResult.failedExpectations[0].message).toEqual(
|
||||||
|
leftInstalledMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
const specResult = resultForRunable(reporter.specDone, 'Suite 2 a spec');
|
||||||
|
expect(specResult.status).toEqual('failed');
|
||||||
|
expect(specResult.failedExpectations.length).toEqual(1);
|
||||||
|
expect(specResult.failedExpectations[0].message).toMatch(
|
||||||
|
/Error: should fail the spec/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cleans up if the global error spy is left installed in an afterAll', async function() {
|
||||||
|
env.configure({ random: false });
|
||||||
|
|
||||||
|
env.describe('Suite 1', function() {
|
||||||
|
env.afterAll(async function() {
|
||||||
|
env.spyOnGlobalErrorsAsync(function() {
|
||||||
|
// Never resolves
|
||||||
|
return new Promise(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('Suite 2', function() {
|
||||||
|
env.it('a spec', async function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
throw new Error('should fail the spec');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'specDone',
|
||||||
|
'suiteDone'
|
||||||
|
]);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
expect(reporter.suiteDone).toHaveFailedExpectationsForRunnable(
|
||||||
|
'Suite 1',
|
||||||
|
[leftInstalledMessage]
|
||||||
|
);
|
||||||
|
|
||||||
|
const suiteResult = resultForRunable(reporter.suiteDone, 'Suite 1');
|
||||||
|
expect(suiteResult.status).toEqual('failed');
|
||||||
|
expect(suiteResult.failedExpectations.length).toEqual(1);
|
||||||
|
expect(suiteResult.failedExpectations[0].message).toEqual(
|
||||||
|
leftInstalledMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
const specResult = resultForRunable(reporter.specDone, 'Suite 2 a spec');
|
||||||
|
expect(specResult.status).toEqual('failed');
|
||||||
|
expect(specResult.failedExpectations.length).toEqual(1);
|
||||||
|
expect(specResult.failedExpectations[0].message).toMatch(
|
||||||
|
/Error: should fail the spec/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cleans up if the global error spy is left installed in a beforeEach', async function() {
|
||||||
|
env.configure({ random: false });
|
||||||
|
|
||||||
|
env.describe('Suite 1', function() {
|
||||||
|
env.beforeEach(async function() {
|
||||||
|
env.spyOnGlobalErrorsAsync(function() {
|
||||||
|
// Never resolves
|
||||||
|
return new Promise(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('Suite 2', function() {
|
||||||
|
env.it('a spec', async function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
throw new Error('should fail the spec');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'specDone',
|
||||||
|
'suiteDone'
|
||||||
|
]);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
||||||
|
expect(spec1Result.status).toEqual('failed');
|
||||||
|
expect(spec1Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec1Result.failedExpectations[0].message).toEqual(
|
||||||
|
leftInstalledMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
const spec2Result = resultForRunable(reporter.specDone, 'Suite 2 a spec');
|
||||||
|
expect(spec2Result.status).toEqual('failed');
|
||||||
|
expect(spec2Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec2Result.failedExpectations[0].message).toMatch(
|
||||||
|
/Error: should fail the spec/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cleans up if the global error spy is left installed in an it', async function() {
|
||||||
|
env.configure({ random: false });
|
||||||
|
|
||||||
|
env.it('spec 1', async function() {
|
||||||
|
env.spyOnGlobalErrorsAsync(function() {
|
||||||
|
// Never resolves
|
||||||
|
return new Promise(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('spec 2', async function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
throw new Error('should fail the spec');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', ['specDone']);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
const spec1Result = resultForRunable(reporter.specDone, 'spec 1');
|
||||||
|
expect(spec1Result.status).toEqual('failed');
|
||||||
|
expect(spec1Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec1Result.failedExpectations[0].message).toEqual(
|
||||||
|
leftInstalledMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
const spec2Result = resultForRunable(reporter.specDone, 'spec 2');
|
||||||
|
expect(spec2Result.status).toEqual('failed');
|
||||||
|
expect(spec2Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec2Result.failedExpectations[0].message).toMatch(
|
||||||
|
/Error: should fail the spec/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('cleans up if the global error spy is left installed in an afterEach', async function() {
|
||||||
|
env.configure({ random: false });
|
||||||
|
|
||||||
|
env.describe('Suite 1', function() {
|
||||||
|
env.afterEach(async function() {
|
||||||
|
env.spyOnGlobalErrorsAsync(function() {
|
||||||
|
// Never resolves
|
||||||
|
return new Promise(() => {});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.it('a spec', function() {});
|
||||||
|
});
|
||||||
|
|
||||||
|
env.describe('Suite 2', function() {
|
||||||
|
env.it('a spec', async function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
throw new Error('should fail the spec');
|
||||||
|
});
|
||||||
|
await new Promise(resolve => setTimeout(resolve));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const reporter = jasmine.createSpyObj('reporter', [
|
||||||
|
'specDone',
|
||||||
|
'suiteDone'
|
||||||
|
]);
|
||||||
|
env.addReporter(reporter);
|
||||||
|
await env.execute();
|
||||||
|
|
||||||
|
const spec1Result = resultForRunable(reporter.specDone, 'Suite 1 a spec');
|
||||||
|
expect(spec1Result.status).toEqual('failed');
|
||||||
|
expect(spec1Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec1Result.failedExpectations[0].message).toEqual(
|
||||||
|
leftInstalledMessage
|
||||||
|
);
|
||||||
|
|
||||||
|
const spec2Result = resultForRunable(reporter.specDone, 'Suite 2 a spec');
|
||||||
|
expect(spec2Result.status).toEqual('failed');
|
||||||
|
expect(spec2Result.failedExpectations.length).toEqual(1);
|
||||||
|
expect(spec2Result.failedExpectations[0].message).toMatch(
|
||||||
|
/Error: should fail the spec/
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
+59
-15
@@ -24,9 +24,23 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
new j$.MockDate(global)
|
new j$.MockDate(global)
|
||||||
);
|
);
|
||||||
|
|
||||||
const runableResources = new j$.RunableResources(function() {
|
const globalErrors = new j$.GlobalErrors();
|
||||||
const r = runner.currentRunable();
|
const installGlobalErrors = (function() {
|
||||||
return r ? r.id : null;
|
let installed = false;
|
||||||
|
return function() {
|
||||||
|
if (!installed) {
|
||||||
|
globalErrors.install();
|
||||||
|
installed = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
const runableResources = new j$.RunableResources({
|
||||||
|
getCurrentRunableId: function() {
|
||||||
|
const r = runner.currentRunable();
|
||||||
|
return r ? r.id : null;
|
||||||
|
},
|
||||||
|
globalErrors
|
||||||
});
|
});
|
||||||
|
|
||||||
let reporter;
|
let reporter;
|
||||||
@@ -133,20 +147,9 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
verboseDeprecations: false
|
verboseDeprecations: false
|
||||||
};
|
};
|
||||||
|
|
||||||
let globalErrors = null;
|
|
||||||
|
|
||||||
function installGlobalErrors() {
|
|
||||||
if (globalErrors) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
globalErrors = new j$.GlobalErrors();
|
|
||||||
globalErrors.install();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!options.suppressLoadErrors) {
|
if (!options.suppressLoadErrors) {
|
||||||
installGlobalErrors();
|
installGlobalErrors();
|
||||||
globalErrors.pushListener(function(
|
globalErrors.pushListener(function loadtimeErrorHandler(
|
||||||
message,
|
message,
|
||||||
filename,
|
filename,
|
||||||
lineno,
|
lineno,
|
||||||
@@ -619,6 +622,47 @@ getJasmineRequireObj().Env = function(j$) {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.spyOnGlobalErrorsAsync = async function(fn) {
|
||||||
|
const spy = this.createSpy('global error handler');
|
||||||
|
const associatedRunable = runner.currentRunable();
|
||||||
|
let cleanedUp = false;
|
||||||
|
|
||||||
|
globalErrors.setOverrideListener(spy, () => {
|
||||||
|
if (!cleanedUp) {
|
||||||
|
const message =
|
||||||
|
'Global error spy was not uninstalled. (Did you ' +
|
||||||
|
'forget to await the return value of spyOnGlobalErrorsAsync?)';
|
||||||
|
associatedRunable.addExpectationResult(false, {
|
||||||
|
matcherName: '',
|
||||||
|
passed: false,
|
||||||
|
expected: '',
|
||||||
|
actual: '',
|
||||||
|
message,
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanedUp = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
const maybePromise = fn(spy);
|
||||||
|
|
||||||
|
if (!j$.isPromiseLike(maybePromise)) {
|
||||||
|
throw new Error(
|
||||||
|
'The callback to spyOnGlobalErrorsAsync must be an async or promise-returning function'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await maybePromise;
|
||||||
|
} finally {
|
||||||
|
if (!cleanedUp) {
|
||||||
|
cleanedUp = true;
|
||||||
|
globalErrors.removeOverrideListener();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function ensureIsNotNested(method) {
|
function ensureIsNotNested(method) {
|
||||||
const runable = runner.currentRunable();
|
const runable = runner.currentRunable();
|
||||||
if (runable !== null && runable !== undefined) {
|
if (runable !== null && runable !== undefined) {
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
getJasmineRequireObj().GlobalErrors = function(j$) {
|
getJasmineRequireObj().GlobalErrors = function(j$) {
|
||||||
function GlobalErrors(global) {
|
function GlobalErrors(global) {
|
||||||
const handlers = [];
|
|
||||||
global = global || j$.getGlobal();
|
global = global || j$.getGlobal();
|
||||||
|
|
||||||
const onerror = function onerror() {
|
const handlers = [];
|
||||||
|
let overrideHandler = null,
|
||||||
|
onRemoveOverrideHandler = null;
|
||||||
|
|
||||||
|
function onerror(message, source, lineno, colno, error) {
|
||||||
|
if (overrideHandler) {
|
||||||
|
overrideHandler(error || message);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
@@ -11,7 +19,7 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
} else {
|
} else {
|
||||||
throw arguments[0];
|
throw arguments[0];
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
this.originalHandlers = {};
|
this.originalHandlers = {};
|
||||||
this.jasmineHandlers = {};
|
this.jasmineHandlers = {};
|
||||||
@@ -42,6 +50,11 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
|
|
||||||
const handler = handlers[handlers.length - 1];
|
const handler = handlers[handlers.length - 1];
|
||||||
|
|
||||||
|
if (overrideHandler) {
|
||||||
|
overrideHandler(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (handler) {
|
if (handler) {
|
||||||
handler(error);
|
handler(error);
|
||||||
} else {
|
} else {
|
||||||
@@ -126,6 +139,24 @@ getJasmineRequireObj().GlobalErrors = function(j$) {
|
|||||||
|
|
||||||
handlers.pop();
|
handlers.pop();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.setOverrideListener = function(listener, onRemove) {
|
||||||
|
if (overrideHandler) {
|
||||||
|
throw new Error("Can't set more than one override listener at a time");
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideHandler = listener;
|
||||||
|
onRemoveOverrideHandler = onRemove;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.removeOverrideListener = function() {
|
||||||
|
if (onRemoveOverrideHandler) {
|
||||||
|
onRemoveOverrideHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
overrideHandler = null;
|
||||||
|
onRemoveOverrideHandler = null;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return GlobalErrors;
|
return GlobalErrors;
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
getJasmineRequireObj().RunableResources = function(j$) {
|
getJasmineRequireObj().RunableResources = function(j$) {
|
||||||
class RunableResources {
|
class RunableResources {
|
||||||
constructor(getCurrentRunableId) {
|
constructor(options) {
|
||||||
this.byRunableId_ = {};
|
this.byRunableId_ = {};
|
||||||
this.getCurrentRunableId_ = getCurrentRunableId;
|
this.getCurrentRunableId_ = options.getCurrentRunableId;
|
||||||
|
this.globalErrors_ = options.globalErrors;
|
||||||
|
|
||||||
this.spyFactory = new j$.SpyFactory(
|
this.spyFactory = new j$.SpyFactory(
|
||||||
() => {
|
() => {
|
||||||
@@ -53,6 +54,7 @@ getJasmineRequireObj().RunableResources = function(j$) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clearForRunable(runableId) {
|
clearForRunable(runableId) {
|
||||||
|
this.globalErrors_.removeOverrideListener();
|
||||||
this.spyRegistry.clearSpies();
|
this.spyRegistry.clearSpies();
|
||||||
delete this.byRunableId_[runableId];
|
delete this.byRunableId_[runableId];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
|
|
||||||
Spec.prototype.addExpectationResult = function(passed, data, isError) {
|
Spec.prototype.addExpectationResult = function(passed, data, isError) {
|
||||||
const expectationResult = j$.buildExpectationResult(data);
|
const expectationResult = j$.buildExpectationResult(data);
|
||||||
|
|
||||||
if (passed) {
|
if (passed) {
|
||||||
this.result.passedExpectations.push(expectationResult);
|
this.result.passedExpectations.push(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
@@ -77,6 +78,11 @@ getJasmineRequireObj().Spec = function(j$) {
|
|||||||
this.onLateError(expectationResult);
|
this.onLateError(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
this.result.failedExpectations.push(expectationResult);
|
this.result.failedExpectations.push(expectationResult);
|
||||||
|
|
||||||
|
// TODO: refactor so that we don't need to override cached status
|
||||||
|
if (this.result.status) {
|
||||||
|
this.result.status = 'failed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.throwOnExpectationFailure && !isError) {
|
if (this.throwOnExpectationFailure && !isError) {
|
||||||
|
|||||||
@@ -227,6 +227,11 @@ getJasmineRequireObj().Suite = function(j$) {
|
|||||||
this.onLateError(expectationResult);
|
this.onLateError(expectationResult);
|
||||||
} else {
|
} else {
|
||||||
this.result.failedExpectations.push(expectationResult);
|
this.result.failedExpectations.push(expectationResult);
|
||||||
|
|
||||||
|
// TODO: refactor so that we don't need to override cached status
|
||||||
|
if (this.result.status) {
|
||||||
|
this.result.status = 'failed';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.throwOnExpectationFailure) {
|
if (this.throwOnExpectationFailure) {
|
||||||
|
|||||||
@@ -421,4 +421,47 @@ getJasmineRequireObj().base = function(j$, jasmineGlobal) {
|
|||||||
j$.debugLog = function(msg) {
|
j$.debugLog = function(msg) {
|
||||||
j$.getEnv().debugLog(msg);
|
j$.getEnv().debugLog(msg);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces Jasmine's global error handling with a spy. This prevents Jasmine
|
||||||
|
* from treating uncaught exceptions and unhandled promise rejections
|
||||||
|
* as spec failures and allows them to be inspected using the spy's
|
||||||
|
* {@link Spy#calls|calls property} and related matchers such as
|
||||||
|
* {@link matchers#toHaveBeenCalledWith|toHaveBeenCalledWith}.
|
||||||
|
*
|
||||||
|
* After installing the spy, spyOnGlobalErrorsAsync immediately calls its
|
||||||
|
* argument, which must be an async or promise-returning function. The spy
|
||||||
|
* will be passed as the first argument to that callback. Normal error
|
||||||
|
* handling will be restored when the promise returned from the callback is
|
||||||
|
* settled.
|
||||||
|
*
|
||||||
|
* Note: The JavaScript runtime may deliver uncaught error events and unhandled
|
||||||
|
* rejection events asynchronously, especially in browsers. If the event
|
||||||
|
* occurs after the promise returned from the callback is settled, it won't
|
||||||
|
* be routed to the spy even if the underlying error occurred previously.
|
||||||
|
* It's up to you to ensure that the returned promise isn't resolved until
|
||||||
|
* all of the error/rejection events that you want to handle have occurred.
|
||||||
|
*
|
||||||
|
* You must await the return value of spyOnGlobalErrorsAsync.
|
||||||
|
* @name jasmine.spyOnGlobalErrorsAsync
|
||||||
|
* @function
|
||||||
|
* @async
|
||||||
|
* @param {AsyncFunction} fn - A function to run, during which the global error spy will be effective
|
||||||
|
* @example
|
||||||
|
* it('demonstrates global error spies', async function() {
|
||||||
|
* await jasmine.spyOnGlobalErrorsAsync(async function(globalErrorSpy) {
|
||||||
|
* setTimeout(function() {
|
||||||
|
* throw new Error('the expected error');
|
||||||
|
* });
|
||||||
|
* await new Promise(function(resolve) {
|
||||||
|
* setTimeout(resolve);
|
||||||
|
* });
|
||||||
|
* const expected = new Error('the expected error');
|
||||||
|
* expect(globalErrorSpy).toHaveBeenCalledWith(expected);
|
||||||
|
* });
|
||||||
|
* });
|
||||||
|
*/
|
||||||
|
j$.spyOnGlobalErrorsAsync = async function(fn) {
|
||||||
|
await jasmine.getEnv().spyOnGlobalErrorsAsync(fn);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user