tryCatch Unit testing with Jest - javascript

I'm trying to test tryCatch code with jest but keep on getting error, currently this is what I've tried
student.js
async checkStudentExist(studentName) {
try {
const studentExist = await this.StudentRepository.getOne({name: studentName})
if (studentExist) {
throw new Error(`Student already exist with the name: ${studentName}`)
}
return studentExist
} catch (error) {
throw error
}
}
student.test.js
it('should throw an error if the input name already exist in database', async () => {
mockGetOne.mockReturnValue(Promise.resolve(expectedOrganization))
await studentService.checkStudentExist('john doe')
expect(mockGetOne).toHaveBeenCalledWith({name: 'sample org'})
expect(studentService.checkStudentExist('john doe')).resolves.toThrowError(new Error(`Organization already exist with the name: john doe`))
})
and this is the error I'm getting
FAIL test/specs/services/student_service.test.js
● Console
console.log src/services/student_service.js:53
111
console.log src/services/student_service.js:53
111
● Check if Student exist › should throw an error if the input name already exist in database
Student already exist with the name: john doe
55 | const studentExist = await this.StudentRepository.getOne({name: studentName})
56 | if (studentExist) {
> 57 | throw new Error(`Student already exist with the name: ${studentName}`)
| ^
58 | }
59 | return studentExist
60 | } catch (error) {
at StudentService.checkStudentExist (src/services/student_service.js:57:23)

Related

Jest mock function is called but expect.toHaveBeenCalled() fails

I know that there are already questions about this but I can't find a definite answer. I am using SvelteKit and I tried to mock $app/navigation likes this in setup file.
jest.mock('$app/navigation', () => {
return {
__esModule: true,
goto: jest.fn().mockImplementation((target) => console.log(target))
};
});
I test a component that call goto. It is indeed called because there is a console.log call in the test output. When I tried to test it with expect(goto).toHaveBeenCalled(), it fails.
// SvelteKit
import * as navigations from '$app/navigation';
it('show error when account does not exists', async () => {
// render is in before Each
await fireEvent.change(screen.getByLabelText('Email'), {
target: { value: 'example#email.com' }
});
await fireEvent.change(screen.getByLabelText('Password'), {
target: { value: 'B#adPass0rd' }
});
await fireEvent.click(screen.getByRole('button'));
// There is no problem. It should redirect.
expect(navigations.goto).toHaveBeenCalled();
});
Output
console.log
/success
at log (jest-setup.js:6:58)
FAIL src/lib/routes-tests/login.test.js
Login
✕ show error when account does not exists (23 ms)
● Login › show error when account does not exists
expect(jest.fn()).toHaveBeenCalled()
Expected number of calls: >= 1
Received number of calls: 0
24 | await fireEvent.click(screen.getByRole('button'));
25 | // expect(screen.queryByText('Account does not exist')).not.toBeNull();
> 26 | expect(navigations.goto).toHaveBeenCalled();
| ^
27 | });
28 | });
29 |
at toHaveBeenCalled (src/lib/routes-tests/login.test.js:26:28)
at tryCatch (src/lib/routes-tests/login.test.js:23:2404)
at Generator._invoke (src/lib/routes-tests/login.test.js:23:1964)
at Generator.next (src/lib/routes-tests/login.test.js:23:3255)
at asyncGeneratorStep (src/lib/routes-tests/login.test.js:25:103)
at _next (src/lib/routes-tests/login.test.js:27:194)
It turns out that I called goto in async function. I must use waitFor to expect the change.
await waitFor(() => expect(navigations.goto).toHaveBeenCalled())

Why java script fs.readFileSync is not getting mocked?

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

i wanted to ask about this error please Unhandled Rejection (TypeError): Cannot destructure property `data` of 'undefined' or 'null'

so first this I use this in authentication im using redux and each time I try to fill the email and password forms and click sign in it give me this error
Unhandled Rejection (TypeError): Cannot destructure property data of 'undefined' or 'null'.
this is my code :
import {AUTH_ATTEMPTING, AUTH_SUCCESS, AUTH_FAILED } from'./types';
import axios from 'axios';
const token_name= 'vendo_app_token';
export const login = (request_data) =>{
return async dispatch =>{
dispatch ({type: AUTH_ATTEMPTING})
try{
const {data: {token}} = await axios.post('http://localhost:5000/api/V1/login', request_data);
dispatch(success(token) );
}catch(e){
const {response: {data}} = e;
dispatch(error(data.error));
}
};
};
and this is the path I use to connect into the home page
if(isAuth===true){
this.props.history.push('/register');
}
The only place where you are destructuring data is in the error handler, where you are trying to destructure to ultimately get e.response.data. The error message you are getting indicates that the error that was thrown does not have a response property.
Try:
} catch(e) {
if ( ! e.response ) {
console.error( 'Error without response:', e );
} else {
const { response : { data } } = e;
dispatch( error( data.error ) );
}
}
heyy jason well i got another error let me show you
TypeError: Cannot read property 'push' of undefined
36 | );
37 | }
38 | if(isAuth){
> 39 | this.props.history.push('/');
| ^ 40 | }
41 | }
42 |
and this error also :
12 | console.error( 'Error without response:', e );
13 | } else {
14 | const { response : { data } } = e;
> 15 | dispatch( error( data.error ) );
| ^ 16 | }
17 | }
18 |

why i am getting 404 error when i am testing my project?

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

How to test a unhandledRejection / uncaughtException handler with jest

I have handlers for unhandledRejections and uncaughtExceptions:
bin.js
['unhandledRejection', 'uncaughtException'].forEach(event => {
process.on(event, err => logger.error(err));
});
Now I want to test them with jest:
bin.test.js
const bin = require('../bin');
test('catches unhandled rejections', async () => {
const error = new Error('mock error');
await Promise.reject(error);
expect(logger.error).toHaveBeenCalledWith(error);
});
test('catches uncaught exceptions', () => {
const error = new Error('mock error');
throw error;
expect(logger.error).toHaveBeenCalledWith(error);
});
But jest just tells me that there are errors in the tests:
● catches unhandled rejections
mock error
8 | // https://github.com/facebook/jest/issues/5620
9 | test('catches unhandled rejections', async () => {
> 10 | const error = new Error('mock error');
| ^
11 | await Promise.reject(error);
12 | expect(logger.error).toHaveBeenCalledWith(error);
13 | });
at Object.<anonymous>.test (test/bin.test.js:10:17)
● catches uncaught exceptions
mock error
14 |
15 | test('catches uncaught exceptions', () => {
> 16 | const error = new Error('mock error');
| ^
17 | throw error;
18 | expect(logger.error).toHaveBeenCalledWith(error);
19 | });
at Object.<anonymous>.test (test/bin.test.js:16:17)
is there a way to test this?
This might be related: https://github.com/facebook/jest/issues/5620
My test strategy is to install spy onto process.on() and logger.error methods using jest.spyOn(object, methodName). After doing this, these methods have no side effects. Then, you can test your code logic in an isolated environment.
Besides, there are a few things to note:
You should spy the functions before require('./bin') statement. Because when you load the bin.js module, the code will be executed.
You should use jest.resetModules() in the beforeEach hook to resets the module registry - the cache of all required modules. Why? because require() caches its results. So, the first time a module is required, then its initialization code runs. After that, the cache just returns the value of module.exports without running the initialization code again. But we have two test cases, we want the code in module scope to be executed twice.
Now, here is the example:
bin.js:
const logger = require('./logger');
['unhandledRejection', 'uncaughtException'].forEach((event) => {
process.on(event, (err) => logger.error(err));
});
logger.js:
const logger = console;
module.exports = logger;
bin.test.js:
const logger = require('./logger');
describe('52493145', () => {
beforeEach(() => {
jest.resetModules();
});
afterEach(() => {
jest.restoreAllMocks();
});
test('catches unhandled rejections', () => {
const error = new Error('mock error');
jest.spyOn(process, 'on').mockImplementation((event, handler) => {
if (event === 'unhandledRejection') {
handler(error);
}
});
jest.spyOn(logger, 'error').mockReturnValueOnce();
require('./bin');
expect(process.on).toBeCalledWith('unhandledRejection', expect.any(Function));
expect(logger.error).toHaveBeenCalledWith(error);
});
test('catches uncaught exceptions', () => {
const error = new Error('mock error');
jest.spyOn(process, 'on').mockImplementation((event, handler) => {
if (event === 'uncaughtException') {
handler(error);
}
});
jest.spyOn(logger, 'error').mockReturnValueOnce();
require('./bin');
expect(process.on).toBeCalledWith('uncaughtException', expect.any(Function));
expect(logger.error).toHaveBeenCalledWith(error);
});
});
unit test result:
PASS examples/52493145/bin.test.js
52493145
✓ catches unhandled rejections (5 ms)
✓ catches uncaught exceptions (1 ms)
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
bin.js | 100 | 100 | 100 | 100 |
logger.js | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 2.73 s, estimated 4 s
source code: https://github.com/mrdulin/jest-v26-codelab/tree/main/examples/52493145
putting it inside try catch will help:
const error = new Error('mock error');
try {
await Promise.reject(error);
}
catch(error){
expect(logger.error).toHaveBeenCalledWith(error);
}

Categories

Resources