- Published on
Simplifying tests with Jest test.each
- Authors
- Name
- Emanoel Oliveira
The problem
When testing a function, it's very common to have a mental map of all the input and output scenarios and then write the unit tests to cover all the code.
Here's an example of a hypothetical function whose purpose is to receive the name of a color and return its hexadecimal:
// Auxiliary enum with hex map
enum HexColors {
black = '#000000',
white = '#ffffff',
red = '#dc2626',
blue = '#3b82f6',
yellow = '#fde047',
}
// Function that converts a color by name to hexadecimal
function colorToHex(colorName: string): string {
const colorMap = {
black: HexColors.black,
white: HexColors.white,
red: HexColors.red,
blue: HexColors.blue,
yellow: HexColors.yellow,
};
const hexColor = colorMap[colorName];
return hexColor ?? HexColors.white;
}
The most common solution
Usually in such a scenario, the most common code looks something like this:
describe('hard way', () => {
it('should return #000000, when 0 is given', () => {
const result = colorToHex('black');
expect(result).toBe(HexColors.black);
});
it('should return #ffffff, when 1 is given', () => {
const result = colorToHex('white');
expect(result).toBe(HexColors.white);
});
it('should return #dc2626, when 2 is given', () => {
const result = colorToHex('red');
expect(result).toBe(HexColors.red);
});
it('should return #3b82f6, when 3 is given', () => {
const result = colorToHex('blue');
expect(result).toBe(HexColors.blue);
});
it('should return #fde047, when 4 is given', () => {
const result = colorToHex('yellow');
expect(result).toBe(HexColors.yellow);
});
it('should return #ffffff, when 5 is given', () => {
const result = colorToHex('magenta');
expect(result).toBe(HexColors.white);
});
});
These tests run and pass, but it is a very repetitive job since the same test is repeated 6 times, only changing the input and output parameters.
The optimized solution
You can get the same result with less effort and in a more optimized way, without having to write the same test 6 times and manually changing the input and output variables, with test.each
in jest
.
const testCases = [
{ input: 'black', output: '#000000' },
{ input: 'white', output: '#ffffff' },
{ input: 'red', output: '#dc2626' },
{ input: 'blue', output: '#3b82f6' },
{ input: 'yellow', output: '#fde047' },
{ input: 'magenta', output: '#ffffff' },
];
describe('easy way', () => {
test.each(testCases)(
'should return $output, when $input is given',
({ input, output }) => {
const result = colorToHex(input);
expect(result).toBe(output);
},
);
});
With this new approach we have several benefits, starting with the fact that the code is more succinct and still readable and easy to maintain, and also writing the test only once, since this code will run through all the test scenarios defined in testCases
.
Conclusão
Test code doesn't have to take the same care as production code, but there are ways to make it more readable, performant and, above all, less laborious. So every time you realize that you're repeating the same test several times, remember test.each
.