[Unit testing + Jest] Use jest-in-case to Reduce Duplication and Improve Test Titles
Jest has a test-generation feature built-in called test.each which is great, but I don’t particularly like it’s API. Instead, we’re going to use an open source project called jest-in-case which gives us a really nice API for generated tests and improved error messages. Let’s try that library out for our isPasswordAllowed tests here.
// From import {isPasswordAllowed} from '../auth' describe('isPasswordAllowed', () => { const allowedPwds = ['!aBc123'] const disallowedPwds = { 'too short': 'a2c!', 'no alphabet characters': '123456', 'no numbers': 'ABCdef!', 'no uppercase letters': 'abc123!', 'no lowercase letters': 'ABC123!', 'no non-alphanumeric characters': 'ABCdef123', } allowedPwds.forEach((pwd) => { test(`allow ${pwd}`, () => { expect(isPasswordAllowed(pwd)).toBeTruthy() }) }) Object.entries(disallowedPwds).forEach(([key, value]) => { test(`disallow - ${key}: ${value}`, () => { expect(isPasswordAllowed(value)).toBeFalsy() }) }) })
to:
import cases from 'jest-in-case' import {isPasswordAllowed} from '../auth' cases( 'isPasswordAllowed: valid passwords', ({password}) => { expect(isPasswordAllowed(password)).toBe(true) }, { 'valid password': { password: '!aBc123', }, }, ) cases( 'isPasswordAllowed: invalid passwords', ({password}) => { expect(isPasswordAllowed(password)).toBe(false) }, { 'too short': { password: 'a2c!', }, 'no letters': { password: '123456!', }, 'no numbers': { password: 'ABCdef!', }, 'no uppercase letters': { password: 'abc123!', }, 'no lowercase letters': { password: 'ABC123!', }, 'no non-alphanumeric characters': { password: 'ABCdef123', }, }, )
(Not necessary)
Even with jest-in-case there can be a little boilerplate and you can easily side-step that by creating a simple function that allows you to write test cases that are more suited for your use case. Let’s give that a try!
import cases from 'jest-in-case' import {isPasswordAllowed} from '../auth' function casify(obj) { return Object.entries(obj).map(([name, password]) => ({ name: `${password} - ${name}`, password, })) } cases( 'isPasswordAllowed: valid passwords', ({password}) => { expect(isPasswordAllowed(password)).toBe(true) }, casify({'valid password': '!aBc123'}), ) cases( 'isPasswordAllowed: invalid passwords', ({password}) => { expect(isPasswordAllowed(password)).toBe(false) }, casify({ 'too short': 'a2c!', 'no letters': '123456!', 'no numbers': 'ABCdef!', 'no uppercase letters': 'abc123!', 'no lowercase letters': 'ABC123!', 'no non-alphanumeric characters': 'ABCdef123', }), )