Chai as promised not waiting for promise to be fulfilled - javascript

An output of my console. Note that the console logs are out of order (1,3,4,2 instead of 1,2,3,4)
Code here
it('can store file', () => {
console.log('1) file storage start')
return filestore.store.q(file).then(() => {
console.log('2) file storage done')
}).should.eventually.be.fullfilled
})
describe('block number', () => {
beforeEach(() => {
console.log('3) check blockNumber')
return web3.Q.all([
web3.eth.getBlockNumber.q().then((_blockNumber) => {
blockNumber = _blockNumber
}),
web3.eth.getMining.q().then((isMining) => {
})
])
})
it('can retreive files block number', () => {
console.log('4) retreive')
return filestore.getBlockNumber.q(fileHash).should.eventually.bignumber.equal(blockNumber)
})
})

This turned out to be a stupid typo. I typed fullfilled instead of fulfilled

I suspect you are getting a side-effect from Chai. Try testing without it first, for example:
const assert = require('assert');
it('can store file', () => {
console.log('1) file storage start')
return filestore.store.q(file).then(() => {
// Promise should have fulfilled. Nothing more to do.
// Using should and chai after this is probably causing the problem.
// But you should really add some sort of assertion here to
// be able to detect regressions.
console.log('2) file storage done')
});
});
describe('block number', () => {
let blockNumber;
beforeEach(() => {
console.log('3) check blockNumber')
return web3.Q.all([
web3.eth.getBlockNumber.q().then((_blockNumber) => {
blockNumber = _blockNumber
}),
web3.eth.getMining.q().then((isMining) => {
})
])
})
it('can retreive files block number', () => {
console.log('4) retreive')
return filestore.getBlockNumber.q(fileHash)
.then((result) => {
// I'm not sure if assert.equal will work with big numbers.
// You might need a different comparator here.
assert.equal(result, blockNumber, 'should equal the blocknumber));
});
});
});
Mocha knows how to handle a returned Promise so there's really no need for Chai. It's unnecessary sugar.

Related

How to pass content yielded in cy.wait() to the variable and reuse it in the next steps?

I use cy.intercept() and cy.wait() to listen to the request and yield content from it.
let number;
describe("some test", () => {
before(() => {
cy.clearCookies();
});
it("some test", () => {
cy.someCommand();
clientPage.someMethod();
cy.intercept("**/request").as("idNumber");
clientPage.someMethod1();
cy.wait("#idNumber").then((res) => {
number = res.response.body.numbers.id
});
cy.get(#someELement).type(number)
});
});
It gives me "cy.type() can only accept a string or number. You passed in: undefined"
When I try to log cy.log(number) under "number = res.response.body.numbers.id" it works. When I try to pass the variable out of this code block it is undefined.
How can I pass it into the further steps?
To make sure the value of number is passed on to the type, you have to add a then, something like:
let number
describe('some test', () => {
before(() => {
cy.clearCookies()
})
it('some test', () => {
cy.someCommand()
clientPage.someMethod()
cy.intercept('**/request').as('idNumber')
clientPage.someMethod1()
cy.wait('#idNumber')
.then((res) => {
number = res.response.body.numbers.id
})
.then(() => {
cy.get('#someELement').type(number)
})
})
})
If you want to use the variable globally throughout the project, you can use the Cypress.env() method. Cypress Docs.
describe('some test', () => {
before(() => {
cy.clearCookies()
})
it('some test', () => {
cy.someCommand()
clientPage.someMethod()
cy.intercept('**/request').as('idNumber')
clientPage.someMethod1()
cy.wait('#idNumber').then((res) => {
cypress.env('number', res.response.body.numbers.id) //Sets Number
})
cy.get('#someELement').type(Cypress.env('number')) //Gets Number and types it
})
it('some different test', () => {
cy.get('#someELement').type(Cypress.env('number')) //types the number
})
})
#alex-izbas answer is good if you need for immediate use.
In the option that you need to use it later in your test, you'll need to set it an .alias() and use it in junction with function(){} and this keyword.
describe("some test", () => {
before(() => {
cy.clearCookies();
});
// use function() {} to be able to use this keyword
it("some test", function() {
cy.someCommand();
clientPage.someMethod();
cy.intercept("**/request").as("idNumber");
clientPage.someMethod1();
// use .its() to get the id and store in alias
cy.wait("#idNumber")
.its('response.body.numbers.id')
// add an assertion to check type with .should()
.as('number')
// some more actions
// get alias using this keyword
cy.get(#someELement).type(this.number)
});
});
It happens because of the asynchronous nature of cypress, and at the moment number is called, its value was not assigned yet.
Any further action can be chained by wait command without polluting your scope with context variables:
cy.wait("#idNumber").then((res) => {
cy.get(#someELement).type(res.response.body.numbers.id)
});

Locked it method in chai

I have a js file which supplies some db operations. This file works with promises only which can be chained. To test that class I work with an async function.
The problem is, that whenever I work with promises inside my test function the it function gets blocked for every other test later.
Here are two examples:
'use strict'
const exec = require('child_process').exec
const path = require('path')
const request = require('request')
const expect = require('chai').expect
const createTableStatements = require('../data')
test()
async function test () {
await testGetUser()
console.log('1')
await testGetFaculties()
}
function testGetUser () {
return new Promise((resolve1) => {
describe('test get user', function () {
const db = require('../dbInterface')
it('test get user should be complete', function () {
db.dbFunctions.dropAll()
.then(onResolve => {
return db.dbFunctions.createTable(createTableStatements.createTableStatements.user)
}
)
.then(() => {
console.log('success create user table')
return db.dbFunctions.addUser('1', 'firstName', 'lastName', 'email')
})
.then(resolve => {
return db.dbFunctions.getUser('email', undefined)
})
.then(result => {
expect(result.toString().includes('dummy')).to.equal(false)
})
.then(resolve => {
return db.dbFunctions.dropAll()
})
.then(resolve => {
console.log('resolve')
resolve1()
})
.catch(err => console.log(err))
})
})
})
}
function testGetFaculties () {
return new Promise(resolve => {
describe('test get faculties', function () {
let db
before(function () {
db = require('../dbInterface')
})
console.log('displayed')
it('should work', function () {
console.log('locked')
expect(db.dbFunctions.getFaculties('hsa')).to.be.an('array').that.does.include('Science')
resolve()
})
})
})
}
And this is the output
resolve
1
displayed
As you can see console.log('locked') is not being processed.
What i figured out so far, that I only have this issue when I call expect within a then function. But this is necessary for my tests.
The test () function should contain much more tests, only for this question I shortened it.
And for clarification: If I only test methods type of testGetFaculties () which don't contains another promise chain inside it works like it should.
Any idea why this is like it is?
Most probably the console.log( 'locked' ); doesn't do anything, because your previous test case was not finished at all.
Writing describe, it, before inside a Promise and containing unreturned Promises is something that you should not do.
Much better test case would look like :
'use strict'
const exec = require('child_process').exec
const path = require('path')
const request = require('request')
const expect = require('chai').expect
const createTableStatements = require('../data')
// You use this in both test cases anyway
const db = require('../dbInterface');
describe('test get user', function () {
it('test get user should be complete', function () {
return db
// ^ returning promise will make sure that the test ends when the promise ends.
.dbFunctions
.dropAll()
.then(onResolve => { ... } )
...
)
} );
} );
describe('test get faculties', function () {
it('should work', function () {
return db
// ^ returning promise will make sure that the test ends when the promise ends.
.dbFunctions
.getFaculties('hsa')
.then( value => {
// ^ You actually need to test the value of the resolve promise
expect( value ).to.be.an('array').that.does.include('Science');
} )
} );
} );

Best Way to Test Promises in Jest

Unless I'm misunderstanding something, the resolves and rejects (https://facebook.github.io/jest/docs/expect.html#resolves) won't be available until vNext. What is the recommended way now/in the meantime to test promises with Jest? Is it just putting expects in the thens and catches?
For example:
describe('Fetching', () => {
const filters = {
startDate: '2015-09-01'
};
const api = new TestApiTransport();
it('should reject if no startdate is given', () => {
MyService.fetch().catch(e => expect(e).toBeTruthy()); // see rejects/resolves in v20+
});
it('should return expected data', () => {
MyService.fetch(filters, null, api).then(serviceObjects => {
expect(serviceObjects).toHaveLength(2);
}).catch(e => console.log(e));
});
});
UPDATE 15 June 2019: Not too long after I posted this question, Jest started supporting this out of the box. I changed the accepted answer below to reflect the currently best way to do this.
UPDATE 8 Dec 2021: At some point Jest started supporting async/await. So while other methods noted work, I've taken to simply (for most cases) using something like:
it('should do something', async () => {
const expected = true;
expect(await funcToTest()).toEqual(expected);
});
As with most cases, async/await is much more readable than alternatives. The only case I use resolves or rejects now is for simple cases like:
it('should not throw when doing something', async () => {
await expect(funcToTest()).resolves.not.toThrow();
});
it('should throw when something is wrong', async () => {
await expect(funcToTest()).rejects.toThrow();
});
Nowadays you can write it in this way as well: docs
describe('Fetching', () => {
const filters = {
startDate: '2015-09-01'
};
const api = new TestApiTransport();
it('should reject if no startdate is given', () => {
expect.assertions(1);
return expect(MyService.fetch()).rejects.toEqual({
error: 'Your code message',
});
});
it('should return expected data', () => {
expect.assertions(1);
return expect(MyService.fetch(filters, null, api)).resolves.toEqual(extectedObjectFromApi);
});
});
Update (06.01.2019)
Agree that the accepted answer doesn't work correctly as line
expect.assertions(1); does all the magic. Link to docs
expect.assertions(number) verifies that a certain number of assertions
are called during a test. This is often useful when testing
asynchronous code, in order to make sure that assertions in a callback
actually got called.
So putting this line at the top will control that the specific number of assertions are made by the time when the test is run.
Either return a promise and expect in the resolve or catch
describe('Fetching', () = > {
const filters = {
startDate: '2015-09-01'
};
const api = new TestApiTransport();
it('should reject if no startdate is given', () = > {
return MyService.fetch()
.catch (e => expect(e).toBeTruthy()); // see rejects/resolves in v20+
});
it('should return expected data', () = > {
return MyService.fetch(filters, null, api)
.then(serviceObjects => {
expect(serviceObjects).toHaveLength(2);
})
});
});
or using async/await
describe('Fetching', () = > {
const filters = {
startDate: '2015-09-01'
};
const api = new TestApiTransport();
it('should reject if no startdate is given', async() = > {
try {
const r = await MyService.fetch()
} catch (e) {
expect(e).toBeTruthy()
}
});
it('should return expected data', async() = > {
const serviceObjects = await MyService.fetch(filters, null, api)
expect(serviceObjects).toHaveLength(2);
});
});
I was able to test JEST with AXIOS for HTTP REST calls like this.
it('has an API worth testing', async () => {
let httpResult = null;
await callThefunctionThatReturnsPromiseToMakeTheAxiosApiCall()
.then(function(result) {httpResult=result;})
.catch(function(err) {httpResult=err;});
expect(httpResult.data.myData).toBe("myExpectedValue");
});
or
it('has an API worth testing', async () => {
let httpResult = await callThefunctionThatReturnsPromiseToMakeTheAxiosApiCall();
expect(httpResult.data.myData).toBe("myExpectedValue");
});
For additional Jest matchers maintained by the Jest Community check out jest-extended.
https://jestjs.io/docs/expect
Using jest-extended you can expect your promise toResolve() or toReject(). Then you can expect the result or the error to match something. For example:
test('OK status', async () => {
const request = fetch(...)
await expect(request).toResolve() // First, make sure it resolves
const data = await request
expect(data).toEqual(...) // Then test the result
})
test('ERROR status', async () => {
const request = fetch(...)
await expect(request).toReject() // First, make sure it rejects
await request.catch((error) => expect(error).toBe('...')) // Then test the error
})

how do i test my async jasmine/nodejs/promise code using Spies

I have a module (example has been simplified) called process-promise which has a single function that takes a Promise as input and processes it - it also calls other functions using modules outside it as follows:
//<process-promise.js>
let User = require('user-module');
let processPromise = (promiseObj) => {
let user = new User();
promiseObj.then((full_name) => {
const [ fname, sname ] = full_name.split(' ');
if (fname && sname) {
user.setDetails(fname, sname);
} else{
console.log('nothing happened');
}
}).catch((err) => {
console.log(err.message);
});
};
module.exports = {
processPromise
};
I am trying to unit test the above function using Jasmine, Rewire and Jasmine spies as per following code
let rewire = require('rewire');
let mod = rewire('process-promise');
describe('process-promise module', () => {
beforeEach(() => {
this.fakeUser = createSpyObj('fake-user', ['setDetails']);
this.fakeUserMod = jasmine.createSpy('fake-user-mod');
this.fakeUserMod.and.returnValue(this.fakeUser)
this.revert = mod.__set__({
User: this.fakeUserMod
});
});
afterEach(() => {
this.revert();
});
it('fakeUser.setDetails should be called', (done) => {
mod.processPromise(Promise.resolve('user name'));
done();
expect(this.fakeUser.setDetails).toHaveBeenCalledWith('user','name');
});
});
I expect that the Spy this.fakeUser.setDetails should get called but i get the message from Jasmine "Expected spy fake-user.setAll to have been called with [ 'user', 'name' ] but it was never called." - the problem seems to be the fact the promise is Async but i've included the done function as other SO questions have suggested but this doesn't seem to resolve the problem for me. What's the issue with my code? most other SO questions relate to angular so don't help with my problem.
You are on the right track, the promise is asynchronous and then done function in your test is called before the promise resolved to a value. The done function is used as a callback to tell the test engine, that all your asynchronous code has completed. It should be called after the promise resolved to a value (or failed for that matter).
In order to do that, you'd need to make the following adjustments to your code:
//<process-promise.js>
let User = require('user-module');
let processPromise = (promiseObj) => {
let user = new User();
// return a promise, to allow a client to chain a .then call
return promiseObj.then((full_name) => {
const [ fname, sname ] = full_name.split(' ');
if (fname && sname) {
user.setDetails(fname, sname);
} else{
console.log('nothing happened');
}
}).catch((err) => {
console.log(err.message);
});
};
module.exports = {
processPromise
};
The test would then look like this:
it('fakeUser.setAll should be called', (done) => {
mod.processPromise(Promise.resolve('user name')).then(() => {
expect(this.fakeUser.setAll).toHaveBeenCalledWith('user','name');
done();
}).catch(done);
});
Be sure to add .catch(done). This will make sure your test fails in case the promise resolves to an error.
Is probable that, by the time your test code execute, the promise has not propagated to the code under test. And simply calling done() doesn't the synchronization magic.
I'm not familiar with rewire so I will share an example using
proxyquire
const proxyquire = require('proxyquire');
describe('process-promise module', () => {
const fakeUser = { setDetails: jasmine.createSpy('setDetails') };
const fakeUserMod = jasmine.createSpy('fake-user-mod').and.returnValue(fakeUser);
const promiseObj = Promise.resolve('user name');
beforeEach((done) => {
const processPromiseMod = proxyquire('process-promise', {
'user-module': fakeUserMod,
});
processPromiseMod.processPromise(promiseObj);
promiseObj.then(() => done());
});
it('fakeUser.setDetails should be called', () => {
expect(fakeUser.setDetails).toHaveBeenCalledWith('user','name');
});
});
Also note that setAll doesn't exist in the fakeUser instance. I guess you mean setDetails instead of setAll.

jest - resolve promise before tests

I want to write tests for promise result and I dot'n want to resolve promise in each it/pit section.
I need smth like this:
describe('getData() results test', () => {
return getData().then(response => {
it('foo', () => expect(response.foo).toEqual(1));
it('bar', () => expect(response.bar).toEqual(2));
it('bar', () => expect(response.bar).toEqual(3));
});
});
If use beforeEach - promise will be resolved as many times as number of it sections. I need to resolve it once and then test response. There are a lot of test cases so I want to split all tests into it sections
The beforeAll function is called only once before all the specs in describe are run.
When return promise, Jest will wait for the promise to resolve before letting the test run.
describe('getData() results test', () => {
let data = null;
beforeAll(() => getData().then(response => {
data = response;
}));
it('foo', () => expect(data.foo).toEqual(1));
it('bar', () => expect(data.bar).toEqual(2));
it('bar', () => expect(data.bar).toEqual(3));
});
Have a look at the Async tutorial from the Jest documentation. I believe you need something like this:
describe('getData() results test', () => {
var response;
beforeEach(() => {
response = getData();
});
it('foo', () => { return response.then(r => expect(r.foo).toEqual(1))});
it('bar', () => { return response.then(r => expect(r.bar).toEqual(2))});
it('bar', () => { return response.then(r => expect(r.bar).toEqual(3))});
});
Key bit of the docs:
The promise that is being tested should be returned.
This is not an answer to your question but it may help people comming from Google
Jest will await the promises returned from beforeAll or beforeEach as #tuchk4 mentioned.
In my case, I forgot the it function and implemented the test right into describe. Surprisingly enough, this "works" but the promises from beforeAll and beforeEach will not be awaited and this makes all sense
I said "works" on quote because failed expect() will indeed fail but the Promise they return will not be awaited which will cause a UnhandledPromiseRejectionWarning.
You can simply do the following
describe('some test suite title', () => {
let response;
beforeAll(async (done) => {
// Do some Async. logic before running any test
await require('./somefile');
response = await getData();
done();
});
// Now run tests => response have the data
it('foo', () => expect(response.foo).toEqual(1));
it('bar', () => expect(response.bar).toEqual(2));
it('bar', () => expect(response.bar).toEqual(3));
});

Categories