i have a fs.readFileSync function that i need to mock using jest.
i have tried the below code.
my original file which i want to test.
const fs = require('fs');
const read_file = (path) => {
try {
const data = fs.readFileSync(path, 'utf8');
return data;
} catch (err) {
console.error('Error in read_file', err);
throw err;
}
};
const getSecret = secretName => {
try {
return read_file(`/etc/secrets/${secretName}.txt`);
} catch (err){
throw err;
}
};
const secretConfig = {
kafka_keystore_password: getSecret('kafka_keystore_password')
};
module.exports = secretConfig;
here is my test case
const secret = require('./secret');
let fs = require('fs')
jest.mock('fs');
describe('secret read files', () => {
afterEach(jest.restoreAllMocks);
it('should read secret from file', () => {
//fs.readFileSync.mockReturnValue("randomPrivateKey");
fs.readFileSync.mockResolvedValue("randomPrivateKey")
const secretMessage = secret.kafka_keystore_password;
//expect(fs.readFileSync).toHaveBeenCalled();
expect(secretMessage).toEqual('randomPrivateKey');
})
})
describe('getSecretsFromFile', () => {
const secret = 'secret';
const secrets = { mySecret: secret };
afterEach(jest.restoreAllMocks);
it('returns secrets if file is present', () => {
fs.existsSync.mockReturnValue(true);
fs.readFileSync.mockReturnValue('randomPrivateKey');
const secretMessage = secret.kafka_keystore_password;
expect(secretMessage).toEqual('randomPrivateKey');
});
});
and i get the following error.
FAIL src/config/secret.test.js ● secret read files › should read
secret from file
expect(received).toEqual(expected) // deep equality
Expected: "randomPrivateKey"
Received: undefined
15 | const secretMessage = secret.kafka_keystore_password;
16 | //expect(fs.readFileSync).toHaveBeenCalled();
> 17 | expect(secretMessage).toEqual('randomPrivateKey');
| ^
18 |
19 | })
20 |
at Object.<anonymous> (src/config/secret.test.js:17:27)
● getSecretsFromFile › returns secrets if file is present
expect(received).toEqual(expected) // deep equality
Expected: "randomPrivateKey"
Received: undefined
32 |
33 | const secretMessage = secret.kafka_keystore_password;
> 34 | expect(secretMessage).toEqual('randomPrivateKey');
| ^
35 | });
36 | });
37 |
at Object.<anonymous> (src/config/secret.test.js:34:29)
help me fix this .
try:
const fs = {
readFileSync: jest.fn(() => ({ message: 'Test'}))
}
to mock the fs readFileSync message.
But I don't see how this test is ever going to pass because you're returning value "Test"
but checking for randomPrivateKey
expect(secretMessage).toEqual('randomPrivateKey');
Without seeing what's going on inside the code it's difficult to say but I am assuming you might want to change that line to:
expect(secretMessage).toEqual('test');
As test is the value your mocking alternatively return randomPrivateKey from the mock.
I'm having to make a load of assumptions here because I don't know-how
secret.kafka_keystore_password is calculated. I'm assuming it just returns the whatever the fs.readFileSync returns.7
Related
I defined let token and logged in before each implements, but in this one i simply token = '' to make sure that client is not logged in. I am supposed to get status 401 but instead i am getting 200. Can you tell me what i am doing wrong?
describe('PUT /:id', () => {
let token;
let genre;
let newName;
let id;
const exec = async () => {
return await request(server)
.put('/api/genres/' + id)
.set('x-auth-token', token)
.send({ name: newName });
}
beforeEach(async () => {
genre = new Genre({ name: 'genre1' });
await genre.save();
token = new User().generateAuthToken();
id = genre._id;
newName = 'updatedName';
});
it('should return 401 if client is not logged in', async () => {
token = '';
const res = await exec();
expect(res.status).toBe(401);
});
● /api/genres › PUT /:id › should return 401 if client is not logged in
expect(received).toBe(expected) // Object.is equality
Expected: 401
Received: 200
142 | const res = await exec();
143 |
> 144 | expect(res.status).toBe(401);
| ^
145 | });
146 |
147 | it('should return 400 if genre is less than 5 characters', async () => {
at Object.toBe (tests/integration/genres.test.js:144:32)
You might need to show us your route folder containing the endpoint for checking if a user is logged in, and also try to check if your auth middleware function is required on your endpoint.
Please refer below code.
Server.js code which is calling an API enclosed in loadUser function and called by fullNameGen function to create full name
const axios = require('axios');
function loadUser(){
return new Promise((resolve,reject)=>{
console.log("Load user called");
axios.get('https://reqres.in/api/users/2').then((response)=>{
resolve(response);
}).catch((err)=>{
reject(err);
})
})
}
function fullNameGen(){
return new Promise((res,rej)=>{
loadUser().then(({data:info})=>{
console.log(info.data);
res(info.data.first_name+" "+info.data.last_name);
}).catch((err)=>{
console.log(err.message);
rej(err.message);
})
})
}
module.exports={
fullNameGen:fullNameGen,
loadUser:loadUser
}
And in server.test.js file I am trying to mock loadUser function not the axios directly.
But the test still calling axios with the API .
server.test.js
const axios = require('axios');
const server = require('./server');
test("Check full Name generation",async()=>{
server.loadUser=jest.fn();
server.loadUser.mockResolvedValue={
data:{
data:{
first_name:"rav",
last_name:"shekhar"
}}
};
const result = await server.fullNameGen();
expect(result).toBe("ravi shekhar");
expect(server.fullNameGen).toBeCalledTimes(1)
})
Please tell me why this test is giving error
expect(received).toBe(expected) // Object.is equality
Expected: "ravi shekhar"
Received: "Janet Weaver"
28 | const result = await server.fullNameGen();
29 |
> 30 | expect(result).toBe("ravi shekhar");
| ^
31 | expect(server.fullNameGen).toBeCalledTimes(1)
32 | })
at Object.<anonymous> (server.test.js:30:20)
I've created a very small app that calculates the total price to pay for certain crypto if you pass in the coin and quantity. I want to test for errors but I am always getting "Received promise resolved instead of rejected". I believe this is due to the fact that if the url is wrong axios still resolves the promise.
The second problem I have is that I have tried testing if the url is correct but I have an issue that headers are part of the url and I can't see to figure out how to test just the url path without headers.
Those are tests 2 and 3 (Test number 1 is working)
// getTotalPrice.js
const axios = require("axios");
let symbol = process.argv[2];
let quantity = process.argv[3];
const API = `https://rest.coinapi.io/v1/exchangerate`;
const headers = {headers:{"X-CoinAPI-Key": "MY TOKEN"},};
const getTotalPrice = async (symbol = "BTC", quantity = 1) => {
try {
let res = await axios.get(`${API}/${symbol}/USD`, headers);
let data = res.data;
return Math.round(data.rate * quantity * 100) / 100;
} catch(err) {
console.log(err)
}
};
getTotalPrice(symbol, quantity);
module.exports = {
getTotalPrice,
API
};
// getTotalPrice.test.js
const { get, getError } = require("axios");
const { getTotalPrice } = require("../getTotalPrice");
describe("getTotalPrice", () => {
afterEach(() => {
get.mockClear();
});
it("fetches data successfully from an api", async () => {
const res = {
data: {
rate: 34000,
},
};
get.mockImplementation(() => Promise.resolve(res));
await expect(getTotalPrice()).resolves.toEqual(res.data.rate);
});
it("throws an error when incorrect data is passed", async () => {
const errorMessage = "Wrong inputs passed in";
getError.mockImplementationOnce(() => Promise.reject({}));
await expect(getTotalPrice()).rejects.toThrowError();
});
it("uses correct url", async () => {
const data = {
data: {
rate: 2000,
},
};
get.mockImplementationOnce(() => Promise.resolve(data));
await getTotalPrice("ETH");
expect(get).toHaveBeenCalledWith(
`${API}/ETH/USD`
);
});
});
// axios.js (in __mocks__)
module.exports = {
get: jest.fn(() => Promise.resolve({ data: {} })),
getError: jest.fn(() => Promise.reject()),
};
To recap, test 1 passes, test 2 fails with "Received promise resolved instead of rejected" and test 3 fails as I am getting headers as well not just url.
You should mock axios.get() with resolved/rejected value. Since you use the try...catch... statement, the error is thrown by axios.get() method will be caught, and you didn't rethrow any errors. So the assertion of test case 2 will not match toThrowError. Instead, you can use jest.spyOn() to add spy to console.log, and assert it to be called with the mocked Error.
Here is an solution only using jest.mock('axios') to mock axios module without __mocks__/axios.js file.
E.g.
getTotalPrice.js:
const axios = require('axios');
let symbol = process.argv[2];
let quantity = process.argv[3];
const API = `https://rest.coinapi.io/v1/exchangerate`;
const headers = { headers: { 'X-CoinAPI-Key': 'MY TOKEN' } };
const getTotalPrice = async (symbol = 'BTC', quantity = 1) => {
try {
let res = await axios.get(`${API}/${symbol}/USD`, headers);
let data = res.data;
return Math.round(data.rate * quantity * 100) / 100;
} catch (err) {
console.log(err);
}
};
module.exports = { getTotalPrice, API };
getTotalPrice.test.js:
const axios = require('axios');
const { getTotalPrice, API } = require('./getTotalPrice');
jest.mock('axios');
describe('getTotalPrice', () => {
it('fetches data successfully from an api', async () => {
const res = { data: { rate: 34000 } };
axios.get.mockResolvedValueOnce(res);
await expect(getTotalPrice()).resolves.toEqual(res.data.rate);
});
it('throws an error when incorrect data is passed', async () => {
const logSpy = jest.spyOn(console, 'log');
const err = new Error('Wrong inputs passed in');
axios.get.mockRejectedValueOnce(err);
await getTotalPrice();
expect(logSpy).toBeCalledWith(err);
});
it('uses correct url', async () => {
const res = { data: { rate: 2000 } };
axios.get.mockResolvedValueOnce(res);
await getTotalPrice('ETH');
expect(axios.get).toHaveBeenCalledWith(`${API}/ETH/USD`, { headers: { 'X-CoinAPI-Key': 'MY TOKEN' } });
});
});
test result:
PASS examples/68200193/getTotalPrice.test.js (7.527 s)
getTotalPrice
✓ fetches data successfully from an api (3 ms)
✓ throws an error when incorrect data is passed (14 ms)
✓ uses correct url (1 ms)
console.log
Error: Wrong inputs passed in
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:14:17
at Generator.next (<anonymous>)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:8:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:4:12)
at Object.<anonymous> (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/examples/68200193/getTotalPrice.test.js:12:66)
at Object.asyncJestTest (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:106:37)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:45:12
at new Promise (<anonymous>)
at mapper (/Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:28:19)
at /Users/dulin/workspace/github.com/mrdulin/jest-v26-codelab/node_modules/jest-jasmine2/build/queueRunner.js:75:41
at console.<anonymous> (node_modules/jest-environment-enzyme/node_modules/jest-mock/build/index.js:866:25)
at Generator.throw (<anonymous>)
------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
getTotalPrice.js | 100 | 100 | 100 | 100 |
------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 3 passed, 3 total
Snapshots: 0 total
Time: 8.034 s
A colleague recommended this to me, today, for mocking axios. I haven't tried it out, yet, though.
API mocking of the next generation
Mock by intercepting requests on the network level. Seamlessly reuse the same mock definition for testing, development, and debugging.
https://mswjs.io/
I have a logging module set up like this:
utils/debugLogger.js
/** Logging to stderr/stdout etc using debug package */
const debug = require('debug');
// this will make sure all logging goes to console.info
// debug.log = console.info.bind(console);
const getLogger = (namespace) => {
const logger = {
log: debug(`${namespace}:log`),
debug: debug(`${namespace}:debug`),
warn: debug(`${namespace}:warning`),
info: debug(`${namespace}:info`),
error: debug(`${namespace}:error`)
}
logger.log.log = console.log.bind(console);
logger.debug.log = console.debug.bind(console);
logger.info.log = console.info.bind(console);
logger.warn.log = console.warn.bind(console);
logger.error.log = console.error.bind(console);
return logger;
}
module.exports = getLogger;
And its mock implementation:
utils/__mocks__/debugLogger.js
const getLogger = () => {
return {
error: () => {},
debug : () => {},
info : () => {},
warn: jest.fn().mockName('logger.warn-mock'),
log: () => {},
}
}
module.exports = getLogger;
And my module whose functions I want to test:
helpers/myModule.js
const logger = require('../utils/debugLogger')('helpers');
const helpers = {
getCleanTimestamp: function() {
// do something
logger.warn("something was done")
return;
},
}
module.exports = helpers;
And the test to check if the logger.info was called with "something as done":
__tests__/helpers.test.js
jest.mock(__base + 'utils/debugLogger');
const helpers = require(__base + "helpers/helpers");
const logger = require('../../utils/debugLogger')('helpers');
describe('getCleanTimestamp', () => {
it.only('should set off warnings for invalid timestamp', () => {
const logwarnSpy = jest.spyOn(logger, 'warn');
const now = helpers.getCleanTimestamp();
expect(logwarnSpy).toBeCalledWith("something was done");
});
});
I've done the following things correctly:
I've mocked the debugLogger module
did the import of debugLogger module after mocking it
But still I get this error:
FAIL server/__tests__/helpers.test.js
getCleanTimestamp
✕ should set off warnings for invalid timestamp (5 ms)
● getCleanTimestamp › should set off warnings for invalid timestamp
expect(jest.fn()).toBeCalledWith(...expected)
Expected: "something was done"
Number of calls: 0
37 | jest.spyOn(logger, 'warn');
38 | // const logwarnSpy = jest.spyOn(logger, 'warn');
> 39 | expect(logger.warn).toBeCalledWith("something was done");
| ^
40 | });
41 | });
at Object.<anonymous> (server/__tests__/helpers.test.js:39:25)
Edit: Put in the edits as prescribed in first answer. Still not working though. Getting:
● getCleanTimestamp › should set off warnings for invalid timestamp
expect(logger.warn-mock).toBeCalledWith(...expected)
Expected: "something was done"
Number of calls: 0
52 | const logInfoSpy = jest.spyOn(logger, 'warn');
53 | const now = helpers.getCleanTimestamp();
> 54 | expect(logInfoSpy).toBeCalledWith("something was done");
| ^
55 | });
56 | });
The jest.spyOn statement should happen before the action you're testing. In addition, as #jonrsharpe mentioned, the spy should be set on the info method rather than warn.
it('should set off warnings for invalid timestamp', () => {
const logInfoSpy = jest.spyOn(logger, 'info');
const now = helpers.getCleanTimestamp();
expect(logInfoSpy).toBeCalledWith("something was done");
});
i am using jest to test my application but when I add more and more code to test, i get more errors to previous codes.
I have this code to test in test
const {Genre} = require('../../models/genre')
describe('GET /:id', ()=>{
it('should return genre with given id', async ()=>{
const genre = new Genre({ name: "Genre1 "});
await genre.save();
console.log(genre._id)
const res = await request(server).get('/api/genres/' + genre._id);
expect(res.status).toBe(200);
expect(res.body).toHaveProperty('name', genre.name)
})
});
this one is in genres.js
router.get('/:id', validateObjectId ,async (req, res) => {
const genre = await Genre.findById(req.params.id);
if (!genre) return res.status(404).send('The genre with the given ID was not found.');
res.send(genre);
});
and i am getting error:
expect(received).toBe(expected) // Object.is equality
Expected: 200
Received: 404
32 | const res = await request(server).get('/api/genres/' + genre._id);
33 |
> 34 | expect(res.status).toBe(200);
| ^
35 | expect(res.body).toHaveProperty('name', genre.name)
36 | })
37 | it('should return 404 if invalid id is passed', async ()=>{
is there any solution to fix this?
when i run only genres.test.js file it works fine but when i want to test all my project it gets error