I have a function like this:
const test = (match) => {
if (match !== 'cat') {
throw new TypeError()
}
}
My test would be:
describe('test', () => {
it('must throw error'() => {
try {
test('cat')
catch(err){
expect(err).toStrictEqual(new TypeError())
}
}
}
But the test passed. It should fail. Why did it pass?
Tests only fail if there is an unmet expectation. In your case, because no error is thrown, no expectation is ever even evaluated. Therefore the test passes.
To deal with this, either:
make sure exactly one expectation is evaluated using expect.assertions:
describe('test', () => {
it('must throw error'() => {
expect.assertions(1);
try {
test('cat')
catch(err){
expect(err).toStrictEqual(new TypeError())
}
}
}
or
handle the error with a .toThrow expectation rather than catching it yourself:
describe('test', () => {
it('must throw error'() => {
expect(() => test('cat')).toThrow(TypeError)
}
}
Note that, as Estus Flask pointed out, this can only assert on either the constructor or the message of the error.
Related
I have a basic stringify function that looks like this ->
export const stringify = <T>(value: T) => {
try {
return JSON.stringify(value);
} catch(error){
return ''
}
}
I want to write a test that can cover the catch block of the function.
I've tried adding such a test ->
it('should be able to check for errors', async () => {
await expect(stringify('')).rejects.toThrow()
})
But this test keeps throwing errors about the function not being a promise. The function isn't going into the catch block at all.
The main function isn't a promise so I can't use the promise functions of jest.
How do I test the catch block?
There is no need to use async/await in this test. Also when there is an error you are returning '' from catch block, meaning your function will not throw anything.
Something like will work for your case
it('should be able to check for errors', () => {
expect(stringify(<error value>)).toBe('')
})
Expect the function definition to Throw
const functionDef = () => {
throw new TypeError("Error Message");
};
test("Test description", () => {
expect(functionDef).toThrow(TypeError);
expect(functionDef).toThrow("Error Message");
});
I'm testing my GraphQL api using Jest.
I'm using a separate test suit for each query/mutation
I have 2 tests (each one in a separate test suit) where I mock one function (namely, Meteor's callMethod) that is used in mutations.
it('should throw error if email not found', async () => {
callMethod
.mockReturnValue(new Error('User not found [403]'))
.mockName('callMethod');
const query = FORGOT_PASSWORD_MUTATION;
const params = { email: 'user#example.com' };
const result = await simulateQuery({ query, params });
console.log(result);
// test logic
expect(callMethod).toBeCalledWith({}, 'forgotPassword', {
email: 'user#example.com',
});
// test resolvers
});
When I console.log(result) I get
{ data: { forgotPassword: true } }
This behaviour is not what I want because in .mockReturnValue I throw an Error and therefore expect result to have an error object
Before this test, however, another is ran
it('should throw an error if wrong credentials were provided', async () => {
callMethod
.mockReturnValue(new Error('cannot login'))
.mockName('callMethod');
And it works fine, the error is thrown
I guess the problem is that mock doesn't get reset after the test finishes.
In my jest.conf.js I have clearMocks: true
Each test suit is in a separate file, and I mock functions before tests like this:
import simulateQuery from '../../../helpers/simulate-query';
import callMethod from '../../../../imports/api/users/functions/auth/helpers/call-accounts-method';
import LOGIN_WITH_PASSWORD_MUTATION from './mutations/login-with-password';
jest.mock(
'../../../../imports/api/users/functions/auth/helpers/call-accounts-method'
);
describe('loginWithPassword mutation', function() {
...
UPDATE
When I substituted .mockReturnValue with .mockImplementation everything worked out as expected:
callMethod.mockImplementation(() => {
throw new Error('User not found');
});
But that doesn't explain why in another test .mockReturnValue works fine...
Change .mockReturnValue with .mockImplementation:
yourMockInstance.mockImplementation(() => {
throw new Error();
});
in case you want to assert
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});
If it's a promise you can also to .rejects www.jestjs.io/docs/en/asynchronous#resolves--rejects
For promises, can use https://jestjs.io/docs/mock-function-api#mockfnmockrejectedvaluevalue
test('async test', async () => {
const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // throws "Async error"
});
For testing that error was thrown or not, can use https://eloquentcode.com/expect-a-function-to-throw-an-exception-in-jest
const func = () => {
throw new Error('my error')
}
it('should throw an error', () => {
expect(func).toThrow()
})
For Angular + Jest:
import { throwError } from 'rxjs';
yourMockInstance.mockImplementation(() => {
return throwError(new Error('my error message'));
});
I want to test invalid Inputs of a function and expect the function to throw
on that inputs. However the test does not pass but the function still throws the error. Im kind of a beginner with jest so I dont know why that happens.
My function looks like this:
export class MyClass{
static theFunction(tokens){
let result = [];
if (typeof tokens[0] === "string") {
return tokens;
} else {
try {
for(let token of tokens){
result.push(token.text);
}
return result;
} catch (e) {
throw new Error(e); //also tried throw e; and no try/catch aswell
}
}
}
}}
Test.js:
import {MyClass} from './MyClass'
describe('Test the MyClass:', () => {
test('invalid inputs for thefunction()', () => {
expect(MyClass.theFunction(0)).toThrow(/*'TypeError: tokens is not iterable'*/);
//Tried with and without the Error Message
});
});
What am I missing?
Wrap your function in an anonymous function so that Jest can catch the error:
describe('Test the MyClass:', () => {
test('invalid inputs for thefunction()', () => {
expect( () => { MyClass.theFunction(0) } ).toThrow();
});
});
You might want to read the section about toThrow() in the Jest documentation and also check the implementation in the Jest project on Github.
I am trying to test this class method:
get () {
try {
return 'value'
} catch (e) {
return 'value2'
}
}
with:
test('the get method retrieves value', () => {
const value = MyClass.get()
expect(value).toBe('value')
})
My test coverage shows I have tested the try part of the method but not the catch part.
How can I cover the catch part?
You can test the catch part by wrapping the function call in a try catch block in your test AND expecting an assertion. Without expecting an assertion a run of the test that doesn't cause an error will still pass.
https://jestjs.io/docs/en/tutorial-async#error-handling
test('the fetch fails with an error', async done => {
expect.assertions(1);
try {
await fetchData();
} catch (e) {
expect(e).toMatch('error');
}
});
You can wrap the expectation inside setImmediate() or process.nextTick() as:
test('the fetch fails with an error', async => {
expect.assertions(1);
setImmediate(() => {
expect(fetchData).toMatch('error');
});
});
Please try this:
test('the fetch fails with an error', async () => {
expect(() => {
await fetchData();
}).toThrow();
});
More info: https://jestjs.io/docs/en/expect#tothrowerror
I'm testing my GraphQL api using Jest.
I'm using a separate test suit for each query/mutation
I have 2 tests (each one in a separate test suit) where I mock one function (namely, Meteor's callMethod) that is used in mutations.
it('should throw error if email not found', async () => {
callMethod
.mockReturnValue(new Error('User not found [403]'))
.mockName('callMethod');
const query = FORGOT_PASSWORD_MUTATION;
const params = { email: 'user#example.com' };
const result = await simulateQuery({ query, params });
console.log(result);
// test logic
expect(callMethod).toBeCalledWith({}, 'forgotPassword', {
email: 'user#example.com',
});
// test resolvers
});
When I console.log(result) I get
{ data: { forgotPassword: true } }
This behaviour is not what I want because in .mockReturnValue I throw an Error and therefore expect result to have an error object
Before this test, however, another is ran
it('should throw an error if wrong credentials were provided', async () => {
callMethod
.mockReturnValue(new Error('cannot login'))
.mockName('callMethod');
And it works fine, the error is thrown
I guess the problem is that mock doesn't get reset after the test finishes.
In my jest.conf.js I have clearMocks: true
Each test suit is in a separate file, and I mock functions before tests like this:
import simulateQuery from '../../../helpers/simulate-query';
import callMethod from '../../../../imports/api/users/functions/auth/helpers/call-accounts-method';
import LOGIN_WITH_PASSWORD_MUTATION from './mutations/login-with-password';
jest.mock(
'../../../../imports/api/users/functions/auth/helpers/call-accounts-method'
);
describe('loginWithPassword mutation', function() {
...
UPDATE
When I substituted .mockReturnValue with .mockImplementation everything worked out as expected:
callMethod.mockImplementation(() => {
throw new Error('User not found');
});
But that doesn't explain why in another test .mockReturnValue works fine...
Change .mockReturnValue with .mockImplementation:
yourMockInstance.mockImplementation(() => {
throw new Error();
});
in case you want to assert
test('the fetch fails with an error', () => {
return expect(fetchData()).rejects.toMatch('error');
});
If it's a promise you can also to .rejects www.jestjs.io/docs/en/asynchronous#resolves--rejects
For promises, can use https://jestjs.io/docs/mock-function-api#mockfnmockrejectedvaluevalue
test('async test', async () => {
const asyncMock = jest.fn().mockRejectedValue(new Error('Async error'));
await asyncMock(); // throws "Async error"
});
For testing that error was thrown or not, can use https://eloquentcode.com/expect-a-function-to-throw-an-exception-in-jest
const func = () => {
throw new Error('my error')
}
it('should throw an error', () => {
expect(func).toThrow()
})
For Angular + Jest:
import { throwError } from 'rxjs';
yourMockInstance.mockImplementation(() => {
return throwError(new Error('my error message'));
});