can't able to mock a variable while testing - node.js

I am trying testing on node js I want to mock a variable outside of a function that is going to be unit tested.
for example
const sample = [];
function uploadDoc {
sample.push('fileLocation')
}
function toSave(){
for (i=0;i<sample.length;i++)
**some process read and access doc
}
I am facing issue while unit testing the second function
I have tried rewire npm that is also not working

Programming likes this will work,You should call uploadDoc firstly.
const sample = [];
function uploadDoc {
sample.push('fileLocation')
}
function toSave(){
uploadDoc();
for (var i=0;i<sample.length;i++)
**some process read and access doc
}

Well, you face challenges to test both functions, then, what you need is to refactor the code. Because I think, your code is not testable.
I give you this long example, which contain both of your functions but testable.
Changes I made for refactor:
function uploadDoc now will output an array.
function toSave now will require 1 parameter, which is an array.
combine functions into class.
const sinon = require('sinon');
const { expect } = require('chai');
const Doc = {
/**
* #return array of file location.
*/
uploadDoc: () => {
const sample = [];
sample.push('fileLocation');
return sample;
},
/**
* #param array samples
* #return void
*/
toSave: (samples) => {
samples.forEach(() => {
// Some process read and access doc.
})
},
}
/**
* This is for example purposes.
* #return void.
*/
function integrationBothFunction () {
const samples = Doc.uploadDoc();
Doc.toSave(samples);
}
describe('Unit Test', function () {
it('uploadDoc fn', function () {
const result = Doc.uploadDoc();
// You expect the result to be an array.
expect(result).to.be.an('array');
});
it('toSave fn', function () {
const samples = [];
const spySamples = sinon.spy(samples, 'forEach');
// Call the function
Doc.toSave(samples);
// You expect: there is forEach called for samples.
expect(spySamples.calledOnce).to.equal(true);
// Do not forget to restore.
spySamples.restore();
});
it('integrationBothFunction fn', function () {
// This is just sample to check.
const testSample = ['x'];
// Now finally, you can stub uploadDoc.
// Where real uploadDoc function not get called.
const stubUploadDoc = sinon.stub(Doc, 'uploadDoc');
stubUploadDoc.returns(testSample);
// Spy on toSave fn.
const spyToSave = sinon.spy(Doc, 'toSave');
integrationBothFunction();
// You expect that toSave is processing output from uploadDoc.
expect(stubUploadDoc.calledOnce).to.equal(true);
expect(spyToSave.calledOnce).to.equal(true);
// Check argument toSave.
const { args } = spyToSave;
expect(args).to.have.lengthOf(1);
expect(args[0]).to.have.lengthOf(1);
expect(args[0][0]).to.include(testSample[0]);
// Restore spy and stub.
stubUploadDoc.restore();
spyToSave.restore();
});
});
I you run using mocha:
$ npx mocha stackoverflow.js
Unit Test
✓ uploadDoc fn
✓ toSave fn
✓ integrationBothFunction fn
3 passing (13ms)
$
Hope this helps. Good luck!

Related

How can I store the value of a promise and use it once resolved?

I am currently developing an app which interacts with uniswap, and I have developed a Wrapper class to contain the info and variables I'll need about some pair (e.g DAI/WETH).
As some of this values are asynchronous, I have coded a build() async function to get those before calling the constructor, so I can store them. I want to store the result of this build function, which is an instance of the class I have defined, inside a variable to use it later, but I need to know whether the Promise that that build function returns is resolved before using it, so how can I make it?
Here is the code of the class:
'use strict'
const { ChainId, Fetcher, WETH, Route, Trade, TokenAmoun, TradeType, TokenAmount } = require('#uniswap/sdk')
const { toChecksumAddress } = require('ethereum-checksum-address')
const Web3 = require('web3')
const web3 = new Web3()
const chainId = ChainId.MAINNET;
let tok1;
let tok2;
let pair;
let route;
let trade;
class UniswapTokenPriceFetcher
{
constructor(async_params)
{
async_params.forEach((element) => {
if (element === 'undefined')
{
throw new Error('All parameters must be defined')
}
});
this.trade = async_params[0];
this.route = async_params[1];
this.pair = async_params[2];
this.tok1 = async_params[3];
this.tok2 = async_params[4];
}
static async build(token1, token2)
{
var tok1 = await Fetcher.fetchTokenData(chainId, toChecksumAddress(token1))
var tok2 = await Fetcher.fetchTokenData(chainId, toChecksumAddress(token2))
var pair = await Fetcher.fetchPairData(tok1, tok2)
var route = new Route([pair], tok2)
var trade = new Trade(route, new TokenAmount(tok2, web3.utils.toWei('1', 'Ether')), TradeType.EXACT_INPUT)
return new UniswapTokenPriceFetcher([trade, route, pair, tok1, tok2])
}
getExecutionPrice6d = () =>
{
return this.trade.executionPrice.toSignificant(6);
}
getNextMidPrice6d = () =>
{
return this.trade.nextMidPrice.toSignificant(6);
}
}
module.exports = UniswapTokenPriceFetcher
Thank you everybody!
EDIT: I know Uniswap only pairs with WETH so one of my token variables is unneccesary, but the problem remains the same! Also keep in mind that I want to store an instance of this class for latter use inside another file.
You should either call the build function with await
const priceFetcher = await UniswapTokenPriceFetcher.build(token1, token2)
or followed by then
UniswapTokenPriceFetcher.build(token1, token2).then(priceFetcher => {...})
I don't see any other way.

Jest spy.On() does not call the method in React Js

I write a test for a method:
const methods = {
run: (name) => {
console.log('run');
return name;
}
}
Using const testMethod = jest.spyOn(methods, 'run').mockResolvedValue({});, the console.log('run') is not triggered, but if i write: const testMethod = jest.spyOn(methods, 'run');, the console.log() is triggered. Why in the first case the console.log() is not triggered and how to solve this?
When you use mockResolvedValue, you are replacing your function with a stub. As the purpose of a stub is not to execute the real implementation of the function but just to return a fictitious value, this behavior is normal.
jest.fn().mockResolvedValue({})
is equivalent to:
jest.fn().mockImplementation(() => Promise.resolve({}));
https://jestjs.io/docs/mock-function-api#mockfnmockresolvedvaluevalue
Update:
If you want to verify if your function is called and if it returned a specific value, then:
const spy = jest.spyOn(methods, 'run');
const myName = 'John Doe';
// Call the method...
expect(spy).toBeCalled();
expect(spy).toHaveReturnedWith(myName);

node.js - Use variables outside functions

I'm new to node.js, and I'm struggling with functions and variables.
let shops = ['shop-one', 'shop-two']
function getShops(shops){
shops.forEach(element => {
console.log(element)
const shop = element
});
}
function getUrl(shop){
console.log(shop)
}
getShops(shops)
getUrl(shop) // shop is not defined
How can I use variables from one function on the other function or outside the functions for further use?
Like in my example I would use the Shopname 'shop-one' from the forEach-Loop in function getShops to be used on the function getUrl or even outside any function.
I would be grateful for any help.
let shops = ['shop-one', 'shop-two'];
// An object to store urls that will look like
// {'shop-one': 'http://aurl4shop1.com', 'shop-two': 'http://aurl4shop2.com' }
let urls = {};
let json = [];
function getShops(shops){
shops.forEach(element => {
console.log(element);
const shop = element;
// The following line will set a property on the url object with the value of the url. The property name is the shop name.
url[shop] = getUrl(shop);
});
}
function getUrl(shop){
console.log(shop);
}
shops.forEach(shop => json[shop] = fetchJson(shop);
// At this point the json object should look like this:
// { 'shop-one': { /* some json */ }, 'shop-two': /* some json */ }

Is there a way to access module.exports.myInstance in a function from other file?

I want to access module.exports.myInstance in a function from other file which simply looks like this below.
// a.js
const func = async function () {
...
module.exports.myInstance = ...;
}
func();
// b.js
const module = require("a.js").myInstance;
console.log(module);
I need to put module.exports inside of a function because I have something to work with await to get myInstance. I tried this and tested, but I've got undefined when console.log(module). Is this not a possible format? If it is, what should I do to make this work?
This is a really bad pattern.. to let it works you should write:
// a.js
const func = async function () {
module.exports.myInstance = 'hello'
}
func()
// b.js
require('./a.js') // trigger the async function
// wait the loading with nextTick or setTimeout (if the operation takes longer)
process.nextTick(() => {
// you must re-run the require since the first execution returns undefined!
console.log(require('./asd.js').myInstance)
})
As you see it is really fragile this code based on timing and execution order.
If you want a singleton you may write this:
// a.js
let cached
module.exports = async function () {
if (cached) {
return cached
}
cached = 'hello'
return cached
}
// b.js
const factory = require('./a.js')
factory()
.then(salut => { console.log(salut) })

How to mock API client created inside a test class?

I have a component class as below which create the rest and websocket connections using a third party npm module. I could change the Component.constructor to accept the module as a dependency so that I can inject a mock version during my Jest testing. But I read about Mocks with Jest, I thought I want to try it, but I cannot seem to understand how to intercept Api.Rest() and Api.Websocket return values.
// component.ts
import * as Api from 'npm-module'
import * as wait from 'wait-for-stuff' // actual npm module
export class Component {
private _rest:any;
private _websocket:any;
public events = new EventEmitter();
constructor() {
// I want to intecept the return value of
// Api.Rest() and Api.Websocket() to use mock versions.
this._rest = new Api.Rest();
this._websocket = new Api.Websocket();
this._init();
}
private _init() {
// so that when do stuff with this._rest and this._websocket;
// I can control what is the expected results during test
this._websocket.onUpdate((data) => {
events.emit('update', data);
});
var value = wait.for.promise(this._rest.getSomething());
}
}
Do I have to use another test library like Sinon or Jasmine?
Here is a simplified working example to get you started:
// #ts-ignore
import * as Api from 'npm-module'; // <= (ts-ignore since "npm-module" doesn't exist)
import EventEmitter from 'events';
jest.mock('npm-module', () => {
const getSomethingMock = jest.fn(); // <= always return...
const onUpdateMock = jest.fn(); // <= ...the same mocks...
return {
Rest: () => ({ getSomething: getSomethingMock }),
Websocket: () => ({ onUpdate: onUpdateMock })
}
},
{ virtual: true }); // <= (use virtual since "npm-module" doesn't exist)
class Component {
private _rest: any;
private _websocket: any;
public events = new EventEmitter();
constructor() {
this._rest = new Api.Rest();
this._websocket = new Api.Websocket();
this._init();
}
private _init() {
this._websocket.onUpdate((data) => { // <= ...so that this onUpdate...
this.events.emit('update', data);
});
}
}
test('Component', () => {
const component = new Component();
const listener = jest.fn();
component.events.on('update', listener);
const onUpdate = new Api.Websocket().onUpdate; // <= ...is the same as this one
const onUpdateArrowFunction = onUpdate.mock.calls[0][0]; // <= get the arrow function passed to it
onUpdateArrowFunction('mock data'); // <= now call the function
expect(listener).toHaveBeenCalledWith('mock data'); // Success!
});
Details
Jest takes over the require system and allows you to specify what you want it to return when a module is required (note that TypeScript import statements get compiled to require calls).
One way to mock a module is to create a manual mock by creating a file at __mocks__/npm-module.ts that contains your mock.
Another way (show above) is to use jest.mock and pass it a module factory function.
Whenever the module is required during the test Jest will return the mocked module instead.
Note that the example above always returns the same mock for getSomething and onUpdate so those mock functions can be retrieved during the test.
Also note the use of mockFn.mock.calls to retrieve this arrow function:
(data) => {
this.events.emit('update', data);
}
...which gets passed to onUpdate. Once it has been retrieved, it can be called directly which triggers the listener as expected.

Resources