Mocha testing Promises remains stuck in the process (locked) - javascript

I'm using Mocha to test my Node.js code. This particular test is checking if some stub returns an Array of filled objects.
The test is good, the result returns filled as expected and everything is "green lighted". But when it was expected to Mocha finish its process, it remains stuck. The only way to finish it is by pressing Ctrl+C.
I tried three kinds of writing the test (as follows). In all of them the test passes, but keeps the process locked:
1) Using simple then/catch methods:
describe('#getAll()', function () {
it('should return a list of objects', function (done) {
orderRepository.getAll()
.then((result) => {
assert.isArray(result);
done();
})
.catch((err) => { done(err); });
});
});
2) Using new Mocha-ready Promise test:
describe('#getAll()', function () {
it('should return a list of objects', function () {
return orderRepository.getAll()
.then((result) => {
assert.isArray(result);
});
});
});
3) Using recomended approach with async/await:
describe('#getAll()', function () {
it('should return a list of Order objects', async function () {
var result = await orderRepository.getAll();
assert.isArray(result);
});
});
Again: ALL THREE METHODS returns a green lighted test, but remains stuck in the mocha process.
I'm using Mocha and Chai as required modules.
I'd be glad if anyone could help me!

I tried all your 3 tests and they seem to work fine and exit fine..

you can try to put process.exit()
idk if is the best way but worked for me :)

Related

Refactoring to reduce repitition in Mocha API test

When running API tests in Node.js I often find myself repeating whole blocks of it statements with slightly different assertions. This seems a waste and I'd like it to respect DRY principles.
Let's take the following as an example:-
const { expect } = require('chai');
const got = require('got');
const core = require('../Libraries/CoreFunctions')
describe('Some description', function() {
beforeEach(function() {
})
it('should do something', function(done) {
got.get('https://someurl.com',
{headers: core.headers()})
.then(res => {
core.respDateCode(res);
console.log(core.prettyJSON(res));
expect(core.something).to.be.lessThan(2000);
done()
})
.catch(err => {
console.log('Error: ', err.message);
});
}).timeout(5000);
it('should do something else', function(done) {
got.get('https://someurl.com',
{headers: core.headers()})
.then(res => {
core.respDateCode(res);
console.log(core.prettyJSON(res));
expect(core.somethingElse).to.be.greaterThan(1000);
done()
})
.catch(err => {
console.log('Error: ', err.message);
});
}).timeout(5000);
});
I'm looking for suggestions as to how best to refactor the above to reduce repetition?
Move the logic for fetching into a seperate file. You can then encapsulate every request into a function (with no parameters, so if API URL changes, your tests won't have to change). Every test should call the function under test explicitly in the "it" block, so it is quickly apparent what is being tested. If you have a lot of repeated setup code, you can move that into a function.
A nice side effect of the isolation of the API calls is that you will end up with a client for the API, that is actually being tested at the same time as your API.
Don't be afraid of your test code being duplicated at the high level. Basically "given this setup, when function under test is called, then this happens". You can put test setup into other functions, but don't overdo it, as you might risk not being able to tell what actually happened when looking at the test. Also, never abstract away the function under test.
const { expect } = require('chai');
const gotClient = require('../somewhere/client/uses/got');
const core = require('../Libraries/CoreFunctions')
describe('Some description', function() {
it('should do something', async function(done) {
// given
const res = await gotClient.resource.getOne()
// when
core.functionThatIsBeingTested(res);
// then
expect(core.something).to.be.lessThan(2000);
done()
}).timeout(5000);
it('should do something else', async function(done) {
// given
const res = await gotClient.resource.getOne()
// when
core.functionThatIsBeingTested(res);
// then
console.log(core.prettyJSON(res));
expect(core.somethingElse).to.be.greaterThan(1000);
done()
}).timeout(5000);
});
Notice, the only real difference between this version and your version is that in my version you don't need to concern yourself with the url and the headers, which makes the code more readable and easier to understand. It would be even better if client was named after the API it was fetching and the resource was a name of the resource.
Just as an example:
const res = await twilio.phoneNumbers.availableForPurchase()

What is considered the correct way to test methods that return http observables?

I have a TypeScript project which I would like to deploy as JS NPM package. This package performs some http requests using rxjs ajax functions. Now I would like to write tests for these methods.
At some point I have a method like this (simplified!):
getAllUsers(): Observable<AjaxResponse> {
return ajax.get(this.apiUrl + '/users');
}
I know about basic testing, for example with spyOn I can mock a response from the server. But how would I actually test the http request?
The documentation of jasmine says that I cannot do async work in the it part, but in the beforeEach: https://jasmine.github.io/tutorials/async
Would this be the correct approach to test the API?
let value: AjaxResponse;
let error: AjaxError;
beforeEach((done) => {
const user = new UsersApi();
user.getAllUsers().subscribe(
(_value: any) => {
value = _value;
done();
},
(_error: any) => {
error = _error;
done();
}
);
});
it("should test the actual http request", () => {
// Test here something
// expect(value).toBe...
// expect(error).toBe...
});
I couldn't think of another approach how to do the async work...
You need to mock ajax.get to return an Observable that emits values that you want to test.
This is done depending on how ajax is declared in your file that contains user.getAllUsers method.
It'd be ideal if UsersApi() had ajax passed into it (pure function style) because then you could just do something like this:
e.g.
class UsersApi {
public ajax;
constructor(ajax) {
this.ajax = ajax;
}
getAllUsers() {
return this.ajax.get(....)
}
}
Edit: Passing in dependencies (aka dependency injection) is one thing that makes modules like this significantly easier to test - consider doing it!
Then you could very easily mock your tests out like this:
const someSuccessfulResponse = ...
const someFailedResponse = ...
const ajaxWithSuccess = {
get:jest.fn(() => of(someSuccessfulResponse))
}
const ajaxWithFailed = {
get:jest.fn(() => throwError(someFailedResponse))
}
describe('my test suite',() => {
it("should test a successful response", (done) => {
const user = new UsersApi(ajaxWithSuccess);
user.getAllUsers().subscribe(d => {
expect(d).toBe(someSuccessfulResponse);
done();
});
});
it("should test a failed response", (done) => {
const user = new UsersApi(ajaxWithFailed);
user.getAllUsers().subscribe(null,error => {
expect(d).toBe(someFailedResponse);
done();
});
});
});
Note: You DO NOT want to test the actual API request. You want to test that your code successfully handles whatever API responses you think it could receive. Think about it, how are you going to test if a failed API response is handled correctly by your code if your API always returns 200s?
EDIT #27: The above code works fine for me when I run jest, not totally clear on why jasmine (doesn't jest run on jasmine?) says it can't do async in it's. In any case, you could just change the code above to set everything up in the beforeEach and just do your expects in the it's.

Jest Unit test, mock implementation of IF condition within function for complete code coverage

I have a API script in a file
const ApiCall = {
fetchData: async (url) => {
const result = await fetch(url);
if (!result.ok) {
const body = await result.text(); // uncovered line
throw new Error(`Error fetching ${url}: ${result.status} ${result.statusText} - ${body}`); // uncovered line
}
return result.json();
},
};
export default ApiCall;
When I mock the call, I have two uncovered lines in code coverage.
Any idea how can I make them cover as well.
Here is what I have tried so far which is not working
it('test', async () => {
ApiCall.fetchData = jest.fn();
ApiCall.fetchData.result = { ok: false };
});
I am kind of new into Jest, so any help would be great.
You need to provide a stubb response in your test spec so that the if statement is triggered. https://www.npmjs.com/package/jest-fetch-mock will allow you to do just that. The example on their npm page should give you what you need https://www.npmjs.com/package/jest-fetch-mock#example-1---mocking-all-fetches
Basically the result is stored in state(redux) and is called from there. jest-fetch-mock overrides your api call/route and returns the stored result in redux all within the framework.
Assuming that what you want to test is the ApiCall then you would need to mock fetch. You are mocking the entire ApiCall so those lines will never execute.
Also, you have an issue, because if you find an error or promise rejection, the json() won't be available so that line will trigger an error.
Try this (haven't test it):
it('test error', (done) => {
let promise = Promise.reject(new Error("test"));
global.fetch = jest.fn(() => promise); //You might need to store the original fetch before swapping this
ApiCall.fetchData()
.catch(err => );
expect(err.message).toEqual("test");
done();
});
it('test OK', (done) => {
let promise = Promise.resolve({
json: jest.fn(() => {data: "data"})
});
global.fetch = jest.fn(() => promise);
ApiCall.fetchData()
.then(response => );
expect(response.data).toEqual("data");
done();
});
That probably won't work right away but hopefully you will get the idea. In this case, you already are working with a promise so see that I added the done() callback in the test, so you can tell jest you finished processing. There is another way to also make jest wait for the promise which is something like "return promise.then()".
Plese post back

Loading existing HTML file with JSDOM for frontend unit testing

I'm new to unit testing, and I'm aware my tests may not be valuable or following a specific best practice, but I'm focused on getting this working, which will allow me to test my frontend code using JSDOM.
const { JSDOM } = require('jsdom');
const { describe, it, beforeEach } = require('mocha');
const { expect } = require('chai');
let checkboxes;
const options = {
contentType: 'text/html',
};
describe('component.js', () => {
beforeEach(() => {
JSDOM.fromFile('/Users/johnsoct/Dropbox/Development/andybeverlyschool/dist/individual.html', options).then((dom) => {
checkboxes = dom.window.document.querySelectorAll('.checkbox');
});
});
describe('checkboxes', () => {
it('Checkboxes should be an array', () => {
expect(checkboxes).to.be.a('array');
});
});
});
I'm getting the error "AssertionError: expected undefined to be an array". I'm simply using the array test as a test to ensure I have JSDOM functioning correctly. There are no other errors occurring. Any help would be much appreciated!
fromFile is an async function, meaning that by the time your beforeEach() has finished and the tests start running, it is (probably) still loading the file.
Mocha handles async code in two ways: either return a promise or pass in a callback. So either return the promise from fromFile or do this:
beforeEach(function(done) {
JSDOM.fromFile(myFile)
.then((dom) => {
checkboxes = dom.window.document.querySelectorAll('.checkbox');
})
.then(done, done);
});
The promise version looks like this:
beforeEach(function() {
return JSDOM.fromFile(myFile)
.then((dom) => {
checkboxes = dom.window.document.querySelectorAll('.checkbox');
});
});

Test promise-chain with Jest

I'm trying to test promises-chain sequence with Jest:
someChainPromisesMethod: function() {
async()
.then(async1)
.then(async2)
.then(result)
.catch(error);
}
While testing single promise is good documented not sure what is a proper way (not sure what to do TBO) to test this kind of chain. Let's assume all asyncs are mocked and just resolves promises (Promise.resolve) in theirs body.
So I need something that will test whole sequence.
You can use jest.fn() to mock implementation and check what the function has been called with and return what you want. You need to mock all async functions you have in your function and return what you want.
e.g.
async = jest.fn(() => {
return Promise.resolve('value');
});
async1 = jest.fn(() => {
return Promise.resolve('value1');
});
async2 = jest.fn(() => {
return Promise.resolve('Final Value');
});
You can use this in your test as
it('should your test scenario', (done) => {
someChainPromisesMethod()
.then(data => {
expect(async1).toBeCalledWith('value');
expect(async2).toBeCalledWith('value1');
expect(data).toEqual('Final Value');
done();
});
});
However, I would flatten your chain and test them separately if you have logic in them, that way you can test all possibilities easily.
Using done does not fix the issue, it will give you a false positive test. If for any reason an expectation fails, your test will timeout and you'll not have the real result.
The right solution is to return your Promise, so Jest will be able to evaluate the expect result correctly.
Following the #grgmo example, a better approach could be:
it('should your test scenario', () => {
return someChainPromisesMethod()
.then(data => {
expect(async1).toBeCalledWith('value');
expect(async2).toBeCalledWith('value1');
expect(data).toEqual('Final Value');
});
});

Categories