mocked function never called - node.js

I have this function in my implementation.js file:
getForecast({ context, entities } ) {
const location = firstEntityValue(entities, 'location');
if (location) {
/* global fetch */
return fetch(`https://api.apixu.com/v1/forecast.json?key=someKey&q=${location}`)
.then(response => response.json())
.then((responseJSON) => {
context.forecast = `whatever`;
delete (context.missingLocation : boolean);
return context;
});
}
delete (context.forecast);
return context;
}
And this is my unit test for this function:
it('should return the expected context when location is valid', () => {
const firstEntityValueMock = sinon.mock(imp);
console.log(firstEntityValueMock);
firstEntityValueMock.expects('firstEntityValue')
.once()
.withArgs(entities, 'location')
.returns('Paris');
const scope = nock('https://api.apixu.com')
.get(/.*/)
.reply(200, fetchResult);
const currentResult = `whatever`;
return imp.actions.getForecast({ context, entities })
.then((resultContext) => {
const res1 = _.lowerCase(resultContext.forecast);
const res2 = _.lowerCase(currentResult);
expect(res1).to.eql(res2);
expect(resultContext.missingLocation).to.be.undefined;
firstEntityValueMock.verify();
});
});
When I run my test, i get this error : ExpectationError: Expected firstEntityValue once (never called)
imp : const imp = require('../build/implementation.js');
I'm exporting my functions in implementation.js, I tried to replace the mock.verify() positioning, I tried some other syntaxes, I always get this error...

Related

Uncaught (in promise) TypeError: "nameMyFunction" is not a function in useEffect React

I'm sorry for my English. I'm using a translator. I have the following problem. I'm trying to use a function from another component, but it gives me the following error.
I will leave the code extract:enter image description here
I used useEffect to display the data for an id depending if that id has records:
export async function getOrderByTableApi(idTable, status= "", ordering= ""){
try {
const tableFilter = `table=${idTable}`;
const statusFilter = `status=${status}`;
const closeFilter = "close=false";
const url = `${BASE_API}/api/orders/?${tableFilter}&${statusFilter}&${closeFilter}&${ordering}`;
const response = await fetch(url);
const result = await response.json();
return result;
} catch (error) {
throw error;
}
}
the function comes from another component as follows:
import { getOrderByTableApi } from "../api/orders";
export function useOrder(){
const [setLoading] = useState(true);
const [setError] = useState(false);
const [setOrders] = useState(null);
const getOrderByTable = async (idTable, status, ordering) => {
try {
setLoading(true);
const response = await getOrderByTableApi(idTable, status, ordering);
setLoading(false);
setOrders(response);
} catch (error) {
setLoading(false);
setError(error);
}
};
return{
getOrderByTable,
};
}
and when using it, the console tells me that getOrderByTable is not a function
import { useTables } from "../../hooks";
export function OrdersHistory() {
const [idTable, setIdTable] = useState(null);
const { getOrdersByTable } = useOrder();
const { getTableByNumber } = useTables();
useEffect(() => {
(async () => {
const table = await getTableByNumber(tableNumber);
const idTableTemp = table[0].id;
setIdTable(idTableTemp);
**getOrdersByTable(idTableTemp, "", "ordering=-status,-created_at");**
})();
}, []);
return (
<p>Help please</p>
);
}
adjunto imagen
There is a typing mistake in your code. You're exporting the function as getOrderByTable from your custom hook useOrder but you're importing it as getOrdersByTable instead of getOrderByTable in your OrdersHistory component.
If you want to rename your function, you can do it as below
const { getOrderByTable as getOrdersByTable } = useOrder();
I appreciate the review, due to fatigue I did not notice that the name of the function did not match a letter and that is why it gave me an error, I will take the recommendation to copy and paste the names of the functions in the future, I consider this question closed. Thank you so much.

How can I mock this http request using jest?

I am new to using Jest for unit tests. How can I mock this simple http request method "getData"? Here is the class:
const got = require("got")
class Checker {
constructor() {
this.url
this.logData = this.logData.bind(this);
this.getData = this.getData.bind(this);
}
async getData(url) {
const response = await got(url);
const data = await response.body;
return data;
}
async logData(first, second, threshold) {
let data = await this.getData(this.url)
console.log("received " + data.body);
}
}
I am trying to mock "getData" so I can write a unit test for "logData". Do I need to mock out the entire "got" module? Thanks.
If you change invoking got to got.get you should be able to have a working test like so:
const got = require('got');
const Checker = require('../index.js');
describe("some test", () => {
beforeEach(() => {
jest.spyOn(got, 'get').mockResolvedValue({ response: { body: { somekey: "somevalue" } } } );
});
it("works", async () => {
new Checker().getData();
expect(got.get).toBeCalledTimes(1);
})
})
One approach is to use dependency injection. Instead of calling 'got' directly, you can 'ask for it' in the class constructor and assign it to a private variable. Then, in the unit test, pass a mock version instead which will return what you want it to.
const got = require("got");
class Checker {
constructor(gotService) {
this.got = gotService;
this.logData = this.logData.bind(this);
this.getData = this.getData.bind(this);
}
async getData(url) {
const response = await this.got(url);
const data = await response.body;
return data;
}
async logData(first, second, threshold) {
let data = await this.getData(this.url)
console.log("received " + data.body);
}
}
//real code
const real = new Checker(got);
//unit testable code
const fakeGot = () => Promise.resolve(mockedData);
const fake = new Checker(fakeGot);
Here is what we are doing:
'Inject' got into the class.
In the class, call our injected version instead of directly calling the original version.
When it's time to unit test, pass a fake version which does what you want it to.
You can include this directly inside your test files. Then trigger the test that makes the Http request and this will be provided as the payload.
global.fetch = jest.fn(() =>
Promise.resolve({
json: () => Promise.resolve({ data: { eth: 0.6, btc: 0.02, ada: 1 } }),
})
);
it('should return correct mock token values', async () => {
const addresses = ["mockA", "mockB", "mockC"];
const res = await getTokenData(addresses);
expect(res.data).toEqual({ eth: 0.6, btc: 0.02, ada: 1 });
});

async function doesn't wait of inside await in nodejs

I am implementing function monthlyRevenue.
Simply, it will return total monthly revenue,and it takes arguments of station array which will make revenues, month and year.
Problem
Inside of this function I have getStationPortion which will fetch the revenue portion of user's.
So I would like to make it return object like this.
stationsPortion = {station1 : 30, station2 : 20}
In the monthlyRevenue
const stationPortions = await getStationPortions(stations)
console.log("portion map", stationPortions //it will be shown very beginning with empty
getStationPortions
const getStationPortions = async (stations) => {
let stationPortions = {}
stations.map(async (value) => {
const doc = await fdb.collection('Stations').doc(value).get()
if (!doc.exists) {
console.log("NO DOC")
} else {
stationPortions[value] = doc.data().salesPortion
console.log(stationPortions) //it will be shown at the last.
}
})
return stationPortions
}
I thought that async function should wait for the result, but it does not.
I am kind of confusing if my understanding is wrong.
Thank you
(by the way, fdb is firebase admin(firestore)
Working code
const getStationPortions = async (stations) => {
let stationPortions = {}
await Promise.all(stations.map(async (value) => {
const doc = await fdb.collection('Stations').doc(value).get()
if (!doc.exists) {
console.log("NO DOC")
} else {
stationPortions[value] = doc.data().salesPortion
console.log(stationPortions)
}
}))
return stationPortions
}
module.exports = router;

stub never called with sinon and nodejs using chai-as-promised

i'm facing a issue with my unit test, stuck completely, the code is simple, please need to understand what's going on, my stub is never called, the set seems to be correct, here the code:
let strategy = fixtures.load('strategy')
chai.use(chaiAsPromised)
describe.only('Spawn Order Job', () => {
let getPositionsStub, createJobStub, daoStub,sandbox
beforeEach(()=>{
sandbox = sinon.createSandbox()
daoStub = sandbox.stub(dao, 'updateActiveOrders').resolves(true) //async
getPositionsStub = sandbox.stub(strategyModule, 'getPositions') //sync
createJobStub = sandbox.stub(helpers, 'createJob') //sync
createJobStub.returns(true)
getPositionsStub.resolves([{fake:'t'}, {fake:'t'}])
})
afterEach(()=>{
sandbox.restore()
})
//OK
it('Should failed with no param, type error context', ()=> {
const promise = spawnOrderJob()
expect(promise).to.be.rejectedWith(TypeError)
})
//OK
it('Should throw error timeout order', () => {
getPositionsStub.resolves([{fake:'t'}, {fake:'t'}])
strategy.lastDateOrder = new Date()
const ctx = { state: {strategy, dashboard, position:null}}
const action = {b: true, s: false}
const promise = spawnOrderJob(action, ctx)
expect(getPositionsStub.called).to.be.true
expect(daoStub.called).to.be.false
expect(createJobStub.called).to.be.false
expect(promise).to.be.rejectedWith(ORDER_ERROR, 'Timeout between order not expired.')
})
//KO stub never called
it.only('Should pass validation on buy', () => {
strategy.lastDateOrder = 0
const ctx = { state: {strategy, dashboard, position: null }}
const action = {b: true, s: false}
const promise = spawnOrderJob(action, ctx)
expect(promise).to.be.fulfilled
expect(getPositionsStub.called).to.be.true //ok
expect(createJobStub.called).to.be.true //never callled ????
expect(daoStub.called).to.be.true //never called ????
})
})
Want to understand what's going now there, the call are correct imo, running with mocha 5.2
Helpers.js : function is described as follow:
async function spawnOrderJob(action, ctx) {
try {
const { strategy, dashboard, position } = ctx.state
const {b, s} = action
//check in case strategy context
if (strategy) {
//pass validation buy contnext
if (b) {
//this stub is working
const positions = await strategyModule.getPositions(ctx)
const { maxPosition } = strategy.allocatedBTC
const { activeOrders, maxActiveOrders, timeBetweenOrder, lastDateOrder } = strategy
debug('Active orders:', strategy.activeOrders)
debug('Position:', positions.length)
if (activeOrders >= maxActiveOrders)
throw new ORDER_ERROR('Max active orders reach.')
if (positions.length + activeOrders >= maxPosition)
throw new ORDER_ERROR('Max positions reach.')
if (!timeoutExpired(lastDateOrder, timeBetweenOrder))
throw new ORDER_ERROR('Timeout between order not expired.')
//increment active orders counter
//stub fail, but not called at all
await dao.updateActiveOrders(strategy, true)
}
//Sell context
if (s) {
if (!position)
throw new ORDER_ERROR('No position to sell')
}
}
//stub fail, but called internally
return createJob(constants.DASHBOARD_CREATE_ORDER, {
orderType: b ? 'BUY' : 'SELL',
title: `Strategy create order ( ${ b ? 'BUY' : 'SELL'} )`,
strategy,
dashboard,
position
})
} catch (e) {
throw e
}
}
function createJob(name, data){
//shortcut queue.create (kue.js)
return queue.c(name,data)
}
module.exports = {
createJob,
spawnOrderJob
}
DAO
const updateActiveOrders = async (strategy, increment) => {
try {
const s = await model.findOne({_id: strategy._id})
if (!s) throw new Error('Strategy not found.')
s.activeOrders = increment ? s.activeOrders+1 :s.activeOrders-1
s.lastDateOrder = new Date()
return await s.save()
}catch(e){
throw e
}
}
module.exports = {updateActiveOrders}

ESOCKETTIMEDOUT Cloud Functions for Firebase

I am using Cloud Functions for Firebase together with my Firebase Realtime Database in order to do some data management for my app.
One of my functions though seems to get terminated since it takes about 100-150 seconds to complete. This happens with error : ESOCKETTIMEDOUT.
Is there a way to prevent this?
Here is my function:
function getTopCarsForUserWithPreferences(userId, genres) {
const pathToCars = admin.database().ref('cars');
pathTocars.orderByChild("IsTop").equalTo(true).once("value").then(function(snapshot) {
return writeSuggestedCars(userId, genres, snapshot);
}).catch(reason => {
console.log(reason)
})
}
function writeSuggestedCars(userId, genres, snapshot) {
const carsToWrite = {};
var snapCount = 0
snapshot.forEach(function(carSnapshot) {
snapCount += 1
const carDict = carSnapshot.val();
const carGenres = carDict.taCarGenre;
const genre_one = genres[0];
const genre_two = genres[1];
if (carGenres[genre_one] === true ||carGenres[genre_two] == true) {
carsToWrite[carSnapshot.key] = carDict
}
if (snapshot.numChildren() - 1 == snapCount) {
const pathToSuggest = admin.database().ref('carsSuggested').child(userId);
pathToSuggest.set(carsToWrite).then(snap => {
}).catch(reason => {
console.log(reason)
});
}
});
}
The getTopCarsForUserWithPreferences gets called when a user adds preferences. Also the cars table has about 50k entries.
Well you need to return everytime you use a async task.
Edit: you return 'writeSuggestedCars' but I think it never returns a value. I do not have a compiler, but I thought it was return Promise.resolved(). Can you insert it where I putted 'HERE'?
Maybe this will work:
function getTopCarsForUserWithPreferences(userId, genres) {
const pathToCars = admin.database().ref('cars');
return pathTocars.orderByChild("IsTop").equalTo(true).once("value").then(function(snapshot) {
return writeSuggestedCars(userId, genres, snapshot);
}).catch(reason => {
console.log(reason)
})
}
function writeSuggestedCars(userId, genres, snapshot) {
const carsToWrite = {};
var snapCount = 0
snapshot.forEach(function(carSnapshot) {
snapCount += 1
const carDict = carSnapshot.val();
const carGenres = carDict.taCarGenre;
const genre_one = genres[0];
const genre_two = genres[1];
if (carGenres[genre_one] === true ||carGenres[genre_two] == true) {
carsToWrite[carSnapshot.key] = carDict
}
if (snapshot.numChildren() - 1 == snapCount) {
const pathToSuggest = admin.database().ref('carsSuggested').child(userId);
return pathToSuggest.set(carsToWrite).then(snap => {
// 'HERE' I think return promise/Promise.resolve() will work
}).catch(reason => {
console.log(reason)
});
}
});
}

Resources