Jasmine - How to set a timeout for a describe block? - javascript

I have a class which is poorly written, and get initialized only after a short timeout. (It's dependent in a 3rd party loading, so it's pointless to offer modifying the code. thank you)
Nevertheless, it needs to be unit tested.
What I have right now is the following structure:
describe('my tests', function() {
var timeoutPromise = function () {
/... return promise .../
}
it('test1', function (done) {
timeoutPromise.then(function() {
expect(...);
done();
});
});
it('test2', function (done) {
timeoutPromise.then(function() {
expect(...);
done();
});
});
});
That way I make sure all tests run after a few ms timeout.
Is there is way to make the whole describe block run only after the timeout?
Something like
describe('my tests', function(done) {
it(...);
it(...);
done();
}

There's no describe() level done callback. From the Jasmine 2.5 docs:
Calls to beforeAll, afterAll, beforeEach, afterEach, and it can take an optional single argument that should be called when the async work is complete.
However, you can do one time initialization in a beforeEach() on the same level as the it() blocks they belong to.
The following code will fullfill your requirements. It is inline commented:
describe('your tests', function() {
var timeoutPromise = new Promise(function(resolve, reject){
setTimeout(resolve, 4000);
});
// execute timeoutPromise and wait for it to resolve ...
beforeEach(function(done) {
timeoutPromise.then(function() {
// timeout resolved, test initialization in this block done
done();
});
});
// for all following it()s the beforeEach() needs to complete
it('test1', function () {
expect(...);
});
it('test2', function () {
expect(...);
});
// ...
});

Related

stub setTimeout function

I have a function wait
async function wait(time) {
return new Promise((resolve) => setTimeout(resolve, time));
}
And I call this wait like this: await wait(5000); from a different function.
I am writing unit test cases and it always executes wait and each test case waits for 5s.
How do I stub the setTimeout using Sinon?
I tried:
// Skip setTimeOut
clock = sinon.useFakeTimers({
now: Date.now(),
toFake: ['setTimeout']
});
await clock.tickAsync(4000);
await Promise.resolve();
But it didn't work.
Related post: setTimeout not triggered while using Sinon's fake timers
Github issue: https://github.com/sinonjs/fake-timers/issues/194#issuecomment-395224370
You can solve this in two ways.
Consider whether your test case requires a delay of 5000ms.
The unit test should test the code logic, it's not integration tests. So, maybe you just need to make an assertion check the wait function is to be called with parameter. It's enough. We don't need to wait for 5000ms delay in the test case.
If you insist want to use sinon.useFakeTimers() and clock.tick(5000).
From the related post, we can do it like this:
index.ts:
async function wait(time: number, clock?) {
return new Promise((resolve) => {
setTimeout(resolve, time);
clock && clock.tick(time);
});
}
export async function main(time, /* for testing */ clock?) {
await wait(time, clock);
console.log('main');
}
index.test.ts:
import { main } from './';
import sinon, { SinonFakeTimers } from 'sinon';
describe('60617715', () => {
let clock: SinonFakeTimers;
beforeEach(() => {
clock = sinon.useFakeTimers();
});
afterEach(() => {
clock.restore();
});
it('should pass', async () => {
await main(5000, clock);
});
});
unit test results:
60617715
main
✓ should pass
1 passing (9ms)

Jest cleanup after test case failed

What is a good and clean way to cleanup after a test case failed?
For a lot of test cases, I first create a clean database environment, which needs to be cleaned up after a test case finishes.
test('some test', async () => {
const { sheetService, cleanup } = await makeUniqueTestSheetService();
// do tests with expect()
await cleanup();
});
Problem is: If one of the expects fails, cleanup() is not invoked and thus the database environment is not cleaned up and jest complains Jest did not exit one second after the test run has completed. because the connection is not closed.
My current workaround looks like this, but it doesn't feel good and clean to push the cleanup hooks to an array which than is handled in the afterAll event.
const cleanUpHooks: (() => Promise<void>)[] = [];
afterAll(async () => {
await Promise.all(cleanUpHooks.map(hook => hook()));
});
test('some test', async () => {
const { sheetService, cleanup } = await makeUniqueTestSheetService();
// do tests with expect()
await cleanup();
});
Use try/finally block for such cases.
For example:
it("some test case", async done => {
try {
expect(false).toEqual(true);
console.log("abc");
done();
}finally{
console.log("finally");
// cleanup code below...
}
});
Above code would just execute the finally block (hence "finally" gets printed in console instead of "abc".
Note that the catch block gives a timeout so just use finally.
This answer must be useful.
What if you use afterEach()? it will execute after each test
test('some test', async () => {
const { sheetService, cleanup } = await makeUniqueTestSheetService();
// do tests with expect()
});
afterEach(async()=>{
await cleanup();
});

Unit testing logic inside promise callback

I have an ES6 / Aurelia app that I am using jasmine to test. The method I am trying to test looks something like this:
update() {
let vm = this;
vm.getData()
.then((response) => {
vm.processData(response);
});
}
Where this.getData is a function that returns a promise.
My spec file looks something like this:
describe('my service update function', () => {
it('it will call the other functions', () => {
myService = new MyService();
spyOn(myService, 'getData').and.callFake(function() {
return new Promise((resolve) => { resolve(); });
});
spyOn(myService, 'processData').and.callFake(function() { return; });
myService.update();
// this one passes
expect(myService.getData).toHaveBeenCalled();
// this one fails
expect(myService.processData).toHaveBeenCalled();
});
});
I understand why this fails - promises are asynchronous and it hasn't been resolved by the time it hits the expect.
How can I push the promises to resolve from my test so that I can test the code inside the call back?
jsfiddle of failed test: http://jsfiddle.net/yammerade/2aap5u37/6/
I got a workaround running by returning an object that behaves like a promise instead of an actual promise
describe('my service update function', () => {
it('it will call the other functions', () => {
myService = new MyService();
spyOn(myService, 'getData').and.returnValue({
then(callback) {
callback();
}
});
spyOn(myService, 'processData').and.callFake(function() { return; });
myService.update();
// this one passes
expect(myService.getData).toHaveBeenCalled();
// this one fails
expect(myService.processData).toHaveBeenCalled();
});
});
Fiddle here: http://jsfiddle.net/yammerade/9rLrzszm/2/
Is there anything wrong with doing it this way?
it((done) => {
// call done, when you are done
spyOn(myService, 'processData').and.callFake(function() {
expect(myService.processData).toHaveBeenCalled();
done();
});
})

How to get asserts in mocha before blocks to work?

How to get asserts in mocha before blocks to work? If I am not suppose to do this let me know. Currently, using promises, if I get an error using an catch block, I'll add an assert to fail the before block. WHat I want is it to fail the describe block, but instead I get two possible outcomes. 1. My test suite completely crashes, 2. I have to wait for each timeout to hit for each test because the before block failed.
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
assert(!error);
done();
});
});
I even tried this, thinking, maybe the done was never called.
before(function (done) {
promise()
.then(function () {
//no done here
})
.catch(function (error) {
assert(!error);
});
.finally(function () {
done();
});
});
So far to avoid crashing and waiting, and to make it work, I have done this:
var beforeError;
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
beforeError = error;
done();
});
});
it('test something', function () {
assert(beforeError, 'Before block failed with error.');
});
I am really curious if there is a better way to go about this so that if my before/beforeEach/after/afterEach blocks fail, it doesn't cause me to wait ages or my suite to crash! Thanks S/O community! :)
I can't speak to your use of the done callback, but mocha 3.0 supports promises in before hooks now. Were I to write this, I would let the returned promise throw its own error, which will fail the before hook without breaking the suite.
before(function () {
return promise(<async behavior here>);
});

Jasmine 2.0 async beforeEach not waiting for async to finish

I am using Jasmine 2.0 and require.js. I cannot get the async tests to work properly when I put the async code in a beforeEach function. My it statement is still running before the async call finishes.
Here is my spec:
describe("App Model :: ", function() {
var AppModel;
beforeEach(function(done) {
require(['models/appModel'], function(AppModel) {
AppModel = AppModel;
done();
});
});
// THIS SPEC FAILS AND RUNS BEFORE ASYNC CALL
it("should exist", function(done) {
this.appModel = new AppModel()
expect(this.appModel).toBeDefined();
done();
});
// THIS SPEC PASSES
it("should still exist", function(done) {
require(['models/appModel'], function(AppModel) {
this.appModel2 = new AppModel()
expect(this.appModel2).toBeDefined();
done();
});
});
});
The first spec fails but the second spec passes, when I include the async within the it.
Ideally, I'd like the beforeEach async to work rather than being not DRY and copying each require into the individual it statements.
Any tips?
Local require var should have another name to be wrapped to the outside scope. Also in the "it" you do not require done, it is only in the async part. Something like this must work:
describe("App Model :: ", function() {
var AppModel;
beforeEach(function(done) {
require(['models/appModel'], function(_AppModel) {
AppModel = _AppModel;
done();
});
});
it("should exist", function() {
var appModel = new AppModel()
expect(appModel).toBeDefined();
});
});

Categories

Resources