I'm trying to do some tests with chai using sinon stub. The thing is, I'm stubbing my fetch like this and resolving my promise.
let fetchedStub;
beforeEach(() => {
fetchedStub = sinon.stub(global, 'fetch');
fetchedStub.resolves({ json: () => { body: 'json' } });
});
Then I'm testing if my data is returning correctly
it('should return the JSON data from the promise', () => {
const result = search('test');
result.then((data) => {
expect(data).to.be.eql({ body: 'json' });
});
});
But instead of passing the test, I'm getting
TypeError: Cannot read property 'then' of undefined
Am I doing something wrong with my promise? I think I need some light here.
Edit: this is the search function.
export const search = (query) => {
fetch(`https://api.spotify.com/v1/search?q=${query}&type=artist`)
.then(data => data.json());
};
Your search arrow function does not return anything, hence in your test result is undefined, hence the error message.
You should simply return the result of your fetch:
export const search = (query) => {
// return something
return fetch(`url`).then(data => data.json());
};
You might have been confused by the arrow function shorthand syntax, which automatically returns the result of a single expression, provided that it is not wrapped in curly braces:
export const search = (query) => fetch(`url`).then(data => data.json()); // no curly braces after the arrow
Related
I want it to log the ai generated text after the api has returned something but it doesn't seem to be waiting for the variable and only logs it after waiting.
//don't use await if you are using then operator on promise
function lyrics(message) {
var resp = deepai.callStandardApi("text-generator", {
text: fs.createReadStream("./Images/Elma.txt"),
}).then(
console.log(resp)
).catch(err => console.log(err));
console.log(resp);
As it's an async call which its result might returned only after the async call, don't use the returned value; You should specify & use the then's callback param as follows:
function lyrics(message) {
deepai.callStandardApi("text-generator", {
text: fs.createReadStream("./Images/Elma.txt"),
}).then(resp)(
console.log(resp)
).catch(err => console.log(err));
}
BTW, notice that you don't use the declared message param.
Title says it all and it returns a message like this
Error: startDate is a required field
I tried to use equal, instanceof.
describe('filter', () => {
it('needs to return a startDate required message', async () => {
let dto = {
'endDate': '2000-02-02',
};
let result = await service.filter(dto);
expect(result).to.throw();
};
});
The problem here is you are not testing the error.
Think about that: When you are doing expect(result).to.throw(); the error has been thrown.
Also result didn't throws any error.
So you can test the error is thrown when calling the function.
You can do it using chai as promised in this way:
service.filter(dto).should.be.rejected;
Also, I've testd your approach using this code:
describe('Test', () => {
it('Test1', async () => {
//Only this line pass the test
thisFunctionThrowAnError().should.be.rejected;
//This not pass
let result = await thisFunctionThrowAnError();
expect(result).to.throw();
});
});
async function thisFunctionThrowAnError(){
throw new Error("Can mocha get this error?")
}
Basically, I want to make sure the methods of analytics are called with certain properties but so far it is not working:
Cannot spy the logAppOpen property because it is not a function; undefined given instead
the library is successfully mocked since I can see console log out of my jest.fn():
jest.mock('#react-native-firebase/analytics', () => {
return () => ({
logAppOpen: jest.fn(() => console.log('mocked fun called')), //===>shown correctly
})
})
My class is:
import analytics from '#react-native-firebase/analytics';
export default class GA {
appStarted = async () =>{
console.log('appStarted called'); //==> showing
await analytics().logAppOpen();
}
}
my test:
it("should log app starting", async () =>{
const spy = jest.spyOn(analytics, 'logAppOpen') //===>FAILS HERE
congst ga = new GA();
await ga.appStarted();
expect(spy).toHaveBeenCalled();
})
but in my test: console.log(analytics) does show an empty object {}
It's analytics().logAppOpen() while jest.spyOn tries to spy on analytics.logAppOpen which doesn't exist.
For lazily evaluated spied functions it's easier to expose them as variables:
const mockLogAppOpen = jest.fn();
jest.mock('#react-native-firebase/analytics', () => {
return jest.fn()
.mockReturnValue({ logAppOpen: mockLogAppOpen });
});
This way it can be accessed for call assertions. There's no need for jest.spyOn for a function that is already a spy.
The problem I'm having is that Jest is reporting setResultsSpy is being called 0 times when in fact, I know that it is being called. I know this by putting console.log(results) under the const results = await getFileList(data.path); in my code and was able to see results returned.
My guess right now is that try-catch blocks creates a local scope, which is causing those calls to not be registered. If this is true, my question is "how can I test if those methods have been called"?
// test_myFunction.js
test((`myFunction with valid path should return list of files`), () => {
const actions = {
setMsg: () => { },
setButton: () => {},
setResults: () => {},
setAppState: () => {}
};
const setMsgSpy = jest.spyOn(actions, 'setMsg');
const setSubmitButtonStateSpy = jest.spyOn(actions, 'setButton');
const setResultsSpy = jest.spyOn(actions, 'setResults');
const setAppStateSpy = jest.spyOn(actions, 'setAppState');
const returnedFileList = [
'file1.pdf',
'file2.pdf',
'file3.pdf',
];
const requestConfig = {
component: COMPONENTS.myComponent,
request: RequestTypes.REQUEST,
data: {path: 'folder1'},
actions
};
processRequest(requestConfig)
expect(setMsgSpy).toHaveBeenCalledTimes(1);
expect(setMsgSpy)
.toHaveBeenCalledWith('loading');
expect(setButtonSpy).toHaveBeenCalledTimes(1);
expect(setResultsSpy).toHaveBeenCalledTimes(1);
expect(setResultsSpy).toHaveBeenCalledWith(returnedFileList);
expect(setAppStateSpy).toHaveBeenCalledTimes(1);
expect(setAppStateSpy).toHaveBeenCalledWith('confirm');
});
_
// myFunction.js
async function processRequest({
component,
request,
data,
actions,
}){
if (component === COMPONENTS.myComponent) {
const path = data.path.trim();
switch (request) {
case RequestTypes.REQUEST:
actions.setMsg('message');
actions.setButton('disabled');
try {
const results = await getFileList(data.path);
actions.setResults(results);
actions.setAppState('confirm');
} catch (e) {
actions.setError(e);
actions.setAppState('error');
}
}
break;
default:
break;
}
}
The the problem was Jest was failing out of the test before the results from getFileList() execution has completed since getFileList() is an async function.
The solution is for the test to handle the execution asynchronously as per the documentation. There are 4 ways to solve this problem:
Use callbacks
Use .then() and .catch() on the returned promise (see docs on .then() here and .catch() here)
Use .resolves() or .rejects() Jest methods on expect() to let Jest resolve the promise.
Use Async-Await syntax by declaring the test anonymous function as async and using await on processRequest() .
I went with option 4 as I enjoy using async-await syntax. Here's the solution:
// test_myFunction.js
test((`myFunction with valid path should return list of files`), async () => {
//(all of the variables established from above)
await processRequest(requestConfig)
expect(setMsgSpy).toHaveBeenCalledTimes(1);
expect(setMsgSpy)
.toHaveBeenCalledWith('loading');
expect(setButtonSpy).toHaveBeenCalledTimes(1);
expect(setResultsSpy).toHaveBeenCalledTimes(1);
expect(setResultsSpy).toHaveBeenCalledWith(returnedFileList);
expect(setAppStateSpy).toHaveBeenCalledTimes(1);
expect(setAppStateSpy).toHaveBeenCalledWith('confirm');
});
Notice async being used on the first line and await when calling processRequest(requestConfig).
I want to test this methode below with Mocha and chai, but I got an error :
I want to test this methode below with Mocha and chai, but I got an error :
exports.getCaracteristiques = (req,res) => {
db.query('SELECT "titi", "toto"')
.then( ({rows}) => {
var caracteristiqueResult = rows.map((row) => {
return {
'idCaracteristique': row.CARACT_ID
, 'libelleCaracteristique': row.toto
, 'libelleCaracteristique': row.titi
};
})
res.json(caracteristiqueResult);
})
.catch(err => {
// handle the error
console.log("ERROR :", err)
res.status(500).end(err)
})
};
test.js file contains :
var expect = require('chai').expect;
require("../config/config");
var ctr = require('../api/controllers/caracteristiques')
describe('Caracteristiques', () => {
it('returns an array of Carateristiques', () => {
// This will fail if "Caracteristiques result "is
// not array.
return ctr.getCaracteristiques.then(function(data){
expect(data).to.be.a('array');
});// no catch, it'll figure it out since the promise is rejected
});
})
but I got this error :
Caracteristiques
1) returns an array of Carateristiques
0 passing (0ms)
1 failing
1) Caracteristiques
returns an array of Carateristiques:
TypeError: ctr.getCaracteristiques.then is not a function
at Context.it (test\caracteristiques.js:13:40)
How to resolve this problem ?
The error:
TypeError: ctr.getCaracteristiques.then is not a function
Is just plain right. You missed the () when onvoking the getCaracteristiques() method.
This should work:
return ctr.getCaracteristiques().then(function(data){
expect(data).to.be.a('array');
});
Edit after OP comment:
In your code, getCaracteristiques requires a req and a res objects. My guess is that your using express or any other node js http library, which usually fills that for you.
In mocha, we are calling the method by ourselves, without any web server, so we need to craft those objects by ourselves.
The getCaracteristiques method does not use req, but it does needs resto have a json() method. So we can do:
const res = {
json: (a) => a,
};
return ctr.getCaracteristiques({}, res).then(function(data){
expect(data).to.be.a('array');
});
In our test so getCaracteristiques return what we want (just the data, because the fake jsonmethod just yields away its parameter).
Now, the test will fail again, because getCaracteristiques does not return the jsoncall. If we add a return statement, the whole thing should work:
exports.getCaracteristiques = (req,res) => {
return db.query('SELECT "CARACT_ID", "CARACT_LIB", "COULEUR", "IMAGE_ACTIVE",
"IMAGE_PASSIVE", "ACTIF" FROM "DIM_PRC_CARACT"')
.then( ({rows}) => {
var caracteristiqueResult = rows.map((row) => {
return {
'idCaracteristique': row.CARACT_ID
, 'libelleCaracteristique': row.CARACT_CD
, 'libelleCaracteristique': row.CARACT_LIB
, 'couleurCaracteristique': row.COULEUR
, 'pictogrammeActifCaracteristique': row.IMAGE_PASSIVE
, 'pictogrammePassifCaracteristique': row.IMAGE_PASSIVE
};
})
return res.json(caracteristiqueResult);
})
Note that a return was added to db.query and res.json, so the getCaracteristiques method now returns a promise of the caracteristiques.