Creating unit tests for default function parameters in ES6 - javascript

Code below is able to parse a specific response from server. In order to make sure the response will be an empty array like output when the serviceResponse param is undefined, I use an default value provided by ES6 features.
I would like to know if you know better way to covering or testing the default function value defined on locationHistoryParser function.
Source
function _getLagLngCoordinates(coordinates) {
...
}
function _getCoordinates(coordinates) {
return coordinates.locations ?
_getLagLngCoordinates(coordinates.locations) :
_getLagLngCoordinates(coordinates);
}
function locationHistoryParser(serviceResponse = '[]') {
return _getCoordinates(JSON.parse(serviceResponse));
}
Test suite
describe('locationHistoryParser', () => {
describe('retrieving a valid response', function () {
describe('managing an array of objects', function () {
it('should return an array of coordinates parsed properly', () => {
...
});
});
describe('managing an object with locations key', function () {
it('should return an array of coordinates parsed properly', () => {
...
});
});
});
describe('retrieving an invalid response', function () {
it('should return an empty array', () => {
const inputData = undefined;
const expectedObject = [];
const response = locationHistoryParser(inputData);
expect(response).toEqual(expectedObject);
});
});
});

Related

testing variable within the function in class using mocha

I need to test value of the url variable in the pullPackage() function in the TASK class.
class TASK {
constructor(taskData, done) {
//some code
}
// Generic Setup
pullPackage() {
return new Promise((resolve, reject) => {
fs.emptydir(this.taskDir, (err) => {
if (err) return reject(err);
const git = require('simple-git')(this.taskDir);
let url = '';
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'test') {
// url = 'ssh://testuser#127.0.0.1:4000/testuser/test-repo-1.git'; // make this match the below format
url = '/git/testuser/test-repo-1';
} else {
const gitAddress = new URL(config.config.GIT_ADDRESS);
url = `${gitAddress.protocol}//runner:${this.taskData.gitJWT}#${gitAddress.hostname}:${gitAddress.port}${this.taskData.repo}.git`;
}
// console.log(url);
// const url = `${gitAddress.protocol}//runner:${this.taskData.gitJWT}#${gitAddress.hostname}:${gitAddress.port}${this.taskData.repo}.git`;
this.logger.log('Cloning from', url);
return git.clone(url, 'repo', (cloneErr) => {
if (cloneErr) return reject(cloneErr);
// console.log(url);
// console.log(resolve);
return resolve(true);
});
});
});
}
}
I'm using Mocha and Chai to do this. I have two test for this function, to check the variable and the promise. The second test runs as expected, but the first always return fails with AssertionError: expected undefined not to be undefined. I think the issue is how I'm accessing the variable during testing. Currently I'm doing it like this: expect(result.url).to.not.be.undefined; Am I going about this correctly?
describe('Test MenloLab Runner - Task Class', () => {
describe('Pull Package', () => {
it('Check URL constant.', () => task.pullPackage().then((result) => {
expect(result.url).to.not.be.undefined; // adjust the access method
}));
it('It should pull package from GIT.', () => task.pullPackage().then((result) => {
expect(result).to.be.true;
}));
});
});
The workaround to check the URL could be done by spying on git.clone method. To do that, we need to use Sinon
I haven't tested with your code but I give you a clue on the solution below:
const sinon = require('sinon');
const git = require('simple-git');
describe('Test MenloLab Runner - Task Class', () => {
describe('Pull Package', () => {
it('Check URL constant.', () => {
return task.pullPackage().then((result) => {
sinon.spy(git, 'clone'); // spying on git.clone method
expect(result.url).to.not.be.undefined; // adjust the access method
const expectedUrl = 'my-expected-not-undefined-url';
sinon.assertCalledWith(git.clone, expectedUrl); // we check whether git.clone is called with not undefined URL
});
});
it('It should pull package from GIT.', () => task.pullPackage().then((result) => {
expect(result).to.be.true;
}));
});
});
Hope it helps

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');
} )
} );
} );

How to make Jest mocked function toHaveBeenCalledTimes has a fresh count for each test suite?

When I assert the number of time the mocked function been called the imported mocked function always return the combined number of invocations.
For example, the first test suite has a function called the mocked function import { get } from 'axios' once and the expected toHaveBeenCalledTimes is 1. However, the second test suite, the function called get again and toHaveBeenCalledTimes is 2 instead of 1.
How to make the mocked function toHaveBeenCalledTimes return a refresh count for each test suit?
describe('fetchAData', () => {
it('should return the right A data response', (done) => {
const sampleResponse = { data: dataASample };
get.mockImplementationOnce(() => {
return Promise.resolve(sampleResponse);
});
fetchAData().then(() => {
expect(get).toHaveBeenCalledTimes(1);
done();
});
});
});
describe('fetchBData', () => {
it('should return the right B data response', (done) => {
const sampleResponse = { data: dataBSample };
get.mockImplementationOnce(() => {
return Promise.resolve(sampleResponse);
});
fetchBData().then(() => {
expect(get).toHaveBeenCalledTimes(1); // -> Return `2`
done();
});
});
});
mockFn.mockReset() just did the trick, https://jestjs.io/docs/en/mock-function-api#mockfnmockreset
Does everything that mockFn.mockClear() does, and also removes any mocked return values or implementations.
beforeEach(() => {
get.mockReset();
});

Return value from asynchronous function and pass result to another function

I'm using a class to do do some database stuff. In this example I want to reset the data and return the data.
export default class Db {
constructor () {
this.connection = monk('localhost:27017/db')
}
async resetDB () {
const Content = this.connection.get('content')
await Content.remove({})
await createContent()
return Content.findOne({ title: 'article' })
}
}
In my test I'm calling the db.resetDB(), but I need to get the returned value, as I need to pass the ID as parameter.
But how do I do that? I think my problem is, that this is asynchronous.
let id
describe('Test', () => {
before(() => {
db.resetDB(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
})
})
it('should do something', () => {
// ...
})
})
When the async function is called, it returns a Promise. hence you can get the return value in .then() of the promise. You can do it something like this,
let id
describe('Test', () => {
before(() => {
db.resetDB().then(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
})
})
it('should do something', () => {
// ...
})
})
You can make the before function to wait until all asynch calls gets finished by using done() callback.
https://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
What you can do is
let id
describe('Test', () => {
before((done) => {
db.resetDB().then(res => {
id = res._id
Article.open(id) // How do I get the ID?? I do get undefined here
Article.title.waitForVisible()
done()
})
})
it('should do something', () => {
// ...
})
})

Jest: How to mock function and test that it was called?

I have a method that loops through an array and makes a HTTP request for each element:
file-processor.js
const chunkFile = (array) => {
return array.map(el => {
sendChunkToNode(el);
});
};
const sendChunkToNode = (data) =>
new Promise((resolve, reject) => {
request.post(...);
});
export default {
chunkFile,
sendChunkToNode,
};
I already have a test for sendChunkToNode:
describe("sendChunkToNode", () => {
beforeEach(() => {
// TODO: figure out how to mock request with certain params
nock(API.HOST)
.post(API.V1_UPLOAD_CHUNKS_PATH)
.reply(201, {
ok: true
});
});
it("makes a POST request to /api/v1/upload-chunks", async () => {
const response = await FileProcessor.sendChunkToNode(
1,
"not_encrypted",
"handle"
);
expect(response).toEqual({ ok: true });
});
});
I now want a test for chunkFile. In the test I just want to test that sendChunkToNode was called with the different elements. Something like this:
describe("chunkFile", () => {
it("calls sendChunkToNode with each element", async () => {
expect(sendChunkToNode).toBeCalledWith(1) //<--- I made the toBeCalledWith method up
expect(sendChunkToNode).toBeCalledWith(2) //<--- I made the toBeCalledWith method up
chunkFile([1,2]);
});
});
Is there a way to do this in Jest?
The way you have it written, you should just make a loop and execute nock for as many times as the number of elements in the array. Then, you call chunkFile(); if there are pending nock requests, that means something is wrong and the test will fail.
test('...', () => {
const someArray = ['a', 'b', 'c']; // someArray.length == 3
someArray.forEach(element => {
nock(...); // set up nock using element value
});
// if the nock interceptors you set up don't match any request, it will throw an error
chunkFile(someArray);
});

Categories