get value from a Promise for unit-testing - javascript

I have a method inside a class calculating the sum of 2 parameters that returns a Promise (a must):
module.exports = class Sum {
sum(a, b) {
let c = a + b;
const myPromise = new Promise(function(myResolve) {
setTimeout(function(){ myResolve(c); }, 100);
});
return myPromise;
}
}
I use Jasmine framework to unit-test
const MyLocalVariable1 = require('../src/sum');
describe('CommonJS modules', () => {
it('should import whole module using module.exports = sum;', async () => {
const result = new MyLocalVariable1();
expect(result.sum(4, 5).then(function(value) {
return value;
})).toBe(9);
});
}
The first expression is what we want to test:
result.sum(4, 5).then(function(value) {
return value;
})
and the second one is the expected value:
toBe(9)
But how can I get a value from the first expression, because it's a Promise, and expected value of it is [object Promise]. Thanks in advance

To drive Konrad's point home, you can do the following:
it('should import whole module using module.exports = sum;', async () => {
const result = new MyLocalVariable1();
const answer = await result.sum(4, 5);
expect(answer).toBe(9);
});
Or the following:
// add done callback to tell Jasmine when you're done with the unit test
it('should import whole module using module.exports = sum;', (done) => {
const result = new MyLocalVariable1();
result.sum(4, 5).then(answer => {
expect(answer).toBe(9);
done();
});
});

Related

How to mock a node module with jest within a class?

I need to mock the DNS node module in a class but I am unsure how to do so as it is enclosed in the class. Here is a sample of what the class looks like...
import { lookup } from 'dns';
class Foo {
// ...
protected async _bar(IP: string) {
// I want to mock "lookup"
await new Promise<undefined>((resolve, reject) => {
lookup(IP, (err, addr) => {
if (err) reject(new Error('DNS Lookup failed for IP_ADDR ' + IP));
resolve();
});
});
// If dns found then return true
return true;
}
// ...
}
I would like to create a test file foo.spec.ts that contains a test similar to the following:
import { Foo } from './Foo';
describe('Foo', () => {
it('Bar Method returns true on success', () => {
const test = new Foo();
expect(test._bar('192.168.1.1')).resolves.toBeTruthy();
});
});
I am unsure how to mock the lookup call within the class Foo given that the class definition is in a separate file from the test itself.
Any help would be appreciated!
The way you are using lookup won't work since it doesn't return a Promise...
...but you can convert it to a version that does return a Promise by using util.promisify.
The code would end up looking something like this:
import { lookup as originalLookup } from 'dns'; // <= import original lookup...
import { promisify } from 'util';
const lookup = promisify(originalLookup); // <= ...and promisify it
export class Foo {
async _bar(IP: string) {
await lookup(IP).catch(err => { throw new Error('Failed'); });
return true;
}
}
You could then mock lookup in your test using jest.mock like this:
import { Foo } from './Foo';
jest.mock('dns', () => ({
lookup: (hostname, callback) => {
hostname === 'example.com' ? callback() : callback('error');
}
}))
describe('Foo', () => {
it('Bar Method returns true on success', async () => {
const test = new Foo();
await expect(test._bar('example.com')).resolves.toBeTruthy(); // Success!
await expect(test._bar('something else')).rejects.toThrowError('Failed'); // Success!
});
});
Note that the mock needs to be created using jest.mock (and not something like jest.spyOn) since calls to jest.mock get hoisted and run first. The mock needs to be in place before Foo.js is imported since the first thing it does is create and store the promisified lookup.
From jest's tutorial,
jest.mock('./sound-player', () => {
return function() {
return {playSoundFile: () => {}};
};
});
so you could do sth like jest.mock('dns', () => ({ ... }));

Jest: restore original module implementation on a manual mock

I have a pretty common testing use case and I am not sure what's the best approach there.
Context
I would like to test a module that depends on a userland dependency. The userland dependency (neat-csv) exports a single function that returns a Promise.
Goal
I want to mock neat-csv's behavior so that it rejects with an error for one single test. Then I want to restore the original module implementation.
AFAIK, I can't use jest.spyOn here as the module exports a single function.
So I thought using manual mocks was appropriated and it works. However I can't figure it out how to restore the original implementation over a manual mock.
Simplified example
For simplicity here's a stripped down version of the module I am trying to test:
'use strict';
const neatCsv = require('neat-csv');
async function convertCsvToJson(apiResponse) {
try {
const result = await neatCsv(apiResponse.body, {
separator: ';'
});
return result;
} catch (parseError) {
throw parseError;
}
}
module.exports = {
convertCsvToJson
};
And here's an attempt of testing that fails on the second test (non mocked version):
'use strict';
let neatCsv = require('neat-csv');
let { convertCsvToJson } = require('./module-under-test.js');
jest.mock('neat-csv', () =>
jest.fn().mockRejectedValueOnce(new Error('Error while parsing'))
);
const csv = 'type;part\nunicorn;horn\nrainbow;pink';
const apiResponse = {
body: csv
};
const rejectionOf = (promise) =>
promise.then(
(value) => {
throw value;
},
(reason) => reason
);
test('mocked version', async () => {
const e = await rejectionOf(convertCsvToJson(apiResponse));
expect(neatCsv).toHaveBeenCalledTimes(1);
expect(e.message).toEqual('Error while parsing');
});
test('non mocked version', async () => {
jest.resetModules();
neatCsv = require('neat-csv');
({ convertCsvToJson } = require('./module-under-test.js'));
const result = await convertCsvToJson(apiResponse);
expect(JSON.stringify(result)).toEqual(
'[{"type":"unicorn","part":"horn"},{"type":"rainbow","part":"pink"}]'
);
});
I am wondering if jest is designed to do such things or if I am going the wrong way and should inject neat-csv instead ?
What would be the idiomatic way of handling this ?
Yes, Jest is designed to do such things.
The API method you are looking for is jest.doMock. It provides a way of mocking modules without the implicit hoisting that happens with jest.mock, allowing you to mock in the scope of tests.
Here is a working example of your test code that shows this:
const csv = 'type;part\nunicorn;horn\nrainbow;pink';
const apiResponse = {
body: csv
};
const rejectionOf = promise =>
promise.then(value => {
throw value;
}, reason => reason);
test('mocked version', async () => {
jest.doMock('neat-csv', () => jest.fn().mockRejectedValueOnce(new Error('Error while parsing')));
const neatCsv = require('neat-csv');
const { convertCsvToJson } = require('./module-under-test.js');
const e = await rejectionOf(convertCsvToJson(apiResponse));
expect(neatCsv).toHaveBeenCalledTimes(1);
expect(e.message).toEqual('Error while parsing');
jest.restoreAllMocks();
});
test('non mocked version', async () => {
const { convertCsvToJson } = require('./module-under-test.js');
const result = await convertCsvToJson(apiResponse);
expect(JSON.stringify(result)).toEqual('[{"type":"unicorn","part":"horn"},{"type":"rainbow","part":"pink"}]');
});

Returning the results of an async array in Javascript using ES6

I'm a novice with Javascript and am struggling to understand how or at least, how best to return array values to another script to assert agains their values.
The context is I want to use Puppeteer to obtain some string values from WebElement attributes and then use the Chai expect library to assert for correct values( or otherwise).
The code I have thus far is:
//app.spec.js
const clothingChoice = await frame.$eval('#option-clothing-5787', e => e.getAttribute('value'));
const groceryChoice = await frame.$eval('#option-clothing-4556', e => e.getAttribute('value'));
const wineChoice = await frame.$eval('#option-clothing-4433', e => e.getAttribute('value'));
const voucherChoice = await frame.$eval('#option-clothing-3454', e => e.getAttribute('value'));
function testFunction() {
return new Promise(function(resolve, reject) {
resolve([clothingChoice, groceryChoice, wineChoice, voucherChoice]);
});
}
async function getChosenItemValues() {
const [clothingChoice, groceryChoice, wineChoice, voucherChoice] = await testFunction();
console.log(clothingChoice, groceryChoice, wineChoice, voucherChoice);
}
getChosenItemValues();
module.exports = getChosenItemValues;
};
I simply need to understand how to import the values that are currently simply printed out as:
1|clothing|option 1|grocery|option 1|wine|option 1|voucher|option
...into another file test.js in which I want to use chai to assert for their presence like so:
expect(clothingChoice).to.equal('1|clothing|option');
Try this:
// app.spec.js (.spec is normally reserved for test files, you may to change the name to avoid confusion)
const clothingChoice = frame.$eval('#option-clothing-5787', e => e.getAttribute('value'));
const groceryChoice = frame.$eval('#option-clothing-4556', e => e.getAttribute('value'));
const wineChoice = frame.$eval('#option-clothing-4433', e => e.getAttribute('value'));
const voucherChoice = frame.$eval('#option-clothing-3454', e => e.getAttribute('value'));
async function getChosenItemValues() {
return await Promise.all([clothingChoice, groceryChoice, wineChoice, voucherChoice]);
}
module.exports = {
getChosenItemValues
};
NOTE: does frame.$eval definitely return a Promise? I've not had any experience with Puppeteer.
// test file
const app = require('/path/to/app.spec.js');
describe('Suite', function() {
it('Returns expected values', function(done) {
app.getChosenItemValues()
.then(res => {
const [clothingChoice, groceryChoice, wineChoice, voucherChoice] = res;
// assertions here
done();
});
});
});
Excuse me if the test functions aren't in the correct format, I don't use Mocha or Chai.

How to Unit Test ES6 Static Class with Sinon (spy/stub/mock)? child function, internal function [JS + SINON]

Below there is a simplified version of the static class I want to test using Chai, Sinon and Mocha. It exposes 2 functions and has another internal.
//demo.js
const parentFunc = (baseNum) => {
return childFunc(baseNum, 10);
};
const childFunc = (base, extra) => {
const sum = base + extra;
return internalFunc(sum);
};
const internalFunc = (num) => {
return 100 + num;
};
module.exports = {
parentFunc: parentFunc,
childFunc: childFunc
}
Logic is irrelevant, what I want to know is how to spy, stub or mock all the functions of the class to have full UT coverage.
Below there are test cases I want do.
import DemoUtils from '../../src/scripts/common/demo';
import sinon from 'sinon';
import chai from 'chai';
const assert = chai.assert;
const expect = chai.expect;
describe('Demo', () => {
describe('Internal Function', () => {
//const res = DemoUtils.internalFunc(8);
});
describe('Child Function', () => {
it('should return ', () => {
const res = DemoUtils.childFunc(5,10);
assert.equal(res, 115);
});
});
describe('Parent Function', () => {
it('should return 140', () => {
const res = DemoUtils.parentFunc(30);
assert.equal(res, 140);
});
it('should call the child function', () => {
const stubFunction = sinon.stub(DemoUtils, 'childFunc');
stubFunction.returns(13);
const res = DemoUtils.parentFunc(30);
assert.equal(res, 13);
assert.equal(stubFunction.calledOnce, true);
stubFunction.restore();
});
});
});
Internal Function: I guess internal function can't be tested because couldn't be called/mocked, isn't it?
Child Function: test works.
Parent Function: first test work but stub function never get called. I tried with spy and mocked too but I can't make it work either.
Anyone has been able to test a ES6 Static Class?
Thanks :)

Mock exported function in module

I have two modules which contain exported functions. "ModuleB" uses a function from "ModuleA". Now I want to test "ModuleB" and mock the used function from "ModuleA".
I use ES6 with babel. For testing I use karma and jasmine.
I tried using babel-rewire and inject-loader, but it just does not work. I'm kind of new to all this and I guess I'm just doing something wrong. So any help is appreciated!
moduleA.js
export function getResult() {
return realResult;
}
moduleB.js
import * as ModuleA from './moduleA'
export function functionToTest() {
let result = ModuleA.getResult();
// do stuff with result which I want to test
}
my test
it("does the right thing", () => {
// I tried using rewire, but this gives me an exception:
ModuleB.__Rewire__('ModuleA', {
getResult: () => {
return fakeResult;
}
});
let xyz = ModuleB.functionToTest(canvas, element);
});
Take a look to this library https://www.npmjs.com/package/mockery I thought It's exactly what do you want. Hope it helps!
EDITED:
Basically you have to use mockery in each test to mock your function, the only problem is that you must use require against import with the modules you want to mock. Look this example:
const moduleUnderTest = './moduleB.js';
const moduleA_fake = { getResult: () => { return "This is a fake result"; } } ;
describe("Mocking functions", () => {
it('Should be Fake Result', (done) => {
mock.registerAllowable(moduleUnderTest);
mock.registerMock('./moduleA.js', moduleA_fake);
mock.enable({ useCleanCache: true });
let ModuleB = require(moduleUnderTest);
let res = ModuleB.functionToTest();
res.should.be.eql("This is a fake result");
mock.disable();
mock.deregisterAll();
done();
});
it('Should be Real Result', (done) => {
let ModuleB = require(moduleUnderTest);
let res = ModuleB.functionToTest();
res.should.be.eql("real foo");
done();
});
});
You could see the complete example Here
For anyone who is interested in how it works with babel-rewire: The trick is to use __RewireAPI__.
import * as ModuleB from '../ModuleB'
import {__RewireAPI__ as ModuleBRewire} from '../ModuleA';
it("does the right thing", () => {
let moduleAMock = {
getResult: () => {
return fakeResult;
}
}
ModuleBRewire.__Rewire__('ModuleA', moduleAMock);
let xyz = ModuleB.functionToTest();
});

Categories

Resources