Npm package สำหรับเขียน jest ให้ง่าย
30 Sep 2023 16:05
Written by: Yosapol Jitrak
ตัวนี้มาช่วยเรื่องการ Assert ของเรา ที่ Jest อาจจะมีไม่เพียบพอ วิธีติดตั้งก็แสนง่าย สามารถไปอ่านได้ตาม Installation
วิธีติดตั้งครับ
pnpm i -D jest-extended
ยกตัวอย่างของที่น่าจะเป็นประโยชน์นะครับ
test('passes when given an empty string', () => {
expect('').toBeEmpty();
expect('hello').not.toBeEmpty();
});
test('passes when given an empty array', () => {
expect([]).toBeEmpty();
expect(['hello']).not.toBeEmpty();
});
test('passes when given an empty object', () => {
expect({}).toBeEmpty();
expect({ hello: 'world' }).not.toBeEmpty();
});
test('passes when value is null or undefined', () => {
expect(null).toBeNil();
expect(undefined).toBeNil();
expect(true).not.toBeNil();
});
test('passes when value is in given array', () => {
expect(1).toBeOneOf([1, 2, 3]);
expect(4).not.toBeOneOf([1, 2, 3]);
});
test('passes when given array is in range', () => {
expect([4, 5, 7, 9]).toBeInRange(4, 10);
expect([12, 13, 15, 17]).not.toBeInRange(4, 9);
});
test('passes when value is a date', () => {
expect(new Date()).toBeDate();
expect('01/01/2018').not.toBeDate();
expect(new Date('01/01/2018')).toBeDate();
expect(undefined).not.toBeDate();
});
test('passes when input is after date', () => {
expect(new Date('01/01/2019')).toBeAfter(new Date('01/01/2018'));
expect('01/01/2018').not.toBeAfter(new Date('01/01/2019'));
});
test('passes when input is equal to or after date', () => {
expect(new Date('01/01/2019')).toBeAfterOrEqualTo(new Date('01/01/2018'));
expect(new Date('01/01/2019')).toBeAfterOrEqualTo(new Date('01/01/2019'));
expect('01/01/2018').not.toBeAfterOrEqualTo(new Date('01/01/2019'));
});
test('passes when input is before date', () => {
expect(new Date('01/01/2018')).toBeBefore(new Date('01/01/2019'));
expect('01/01/2019').not.toBeBefore(new Date('01/01/2018'));
});
test('passes when input is equal to or before date', () => {
expect(new Date('01/01/2018')).toBeBeforeOrEqualTo(new Date('01/01/2019'));
expect(new Date('01/01/2018')).toBeBeforeOrEqualTo(new Date('01/01/2018'));
expect('01/01/2019').not.toBeBeforeOrEqualTo(new Date('01/01/2018'));
});
test('passes when input is in given date range', () => {
expect(new Date('05/01/2019')).toBeBetween(new Date('01/01/2019'), new Date('10/01/2019'));
expect(new Date('05/01/2019')).toBeBetween(new Date('05/01/2019'), new Date('10/01/2019'));
expect(new Date('01/01/2019')).not.toBeBetween(new Date('05/01/2019'), new Date('10/01/2019'));
});
test('calls mock1 before mock2', () => {
const mock1 = jest.fn();
const mock2 = jest.fn();
mock1();
mock2();
mock1();
expect(mock1).toHaveBeenCalledBefore(mock2);
});
test('calls mock1 after mock2', () => {
const mock1 = jest.fn();
const mock2 = jest.fn();
mock2();
mock1();
mock2();
expect(mock1).toHaveBeenCalledAfter(mock2);
});
test('passes when object contains given entry', () => {
const o = { a: 'foo', b: 'bar', c: 'baz' };
expect(o).toContainEntry(['a', 'foo']);
expect(o).toContainEntry(['b', 'bar']);
expect(o).toContainEntry(['c', 'baz']);
expect(o).not.toContainEntry(['a', 'qux']);
});
test('passes when object contains all of the given entries', () => {
const o = { a: 'foo', b: 'bar', c: 'baz' };
expect(o).toContainEntries([['a', 'foo']]);
expect(o).toContainEntries([
['c', 'baz'],
['a', 'foo'],
]);
expect(o).not.toContainEntries([
['b', 'qux'],
['a', 'foo'],
]);
});
jest-when ตัวนี้มาช่วยเรื่อง Mock ถ้าได้รับค่าจะทำตามเงื่อนไข ว่าง่าย ๆ ก็คือ Swith case ของการ Mock นั่นเอง
วิธีติดตั้ง
pnpm i -D jest-when
ยกตัวอย่างการใช้งาน
import { when } from 'jest-when';
const fn = jest.fn();
when(fn).calledWith(1).mockReturnValue('yay!').calledWith(2).mockReturnValue('nay!');
expect(fn(1)).toEqual('yay!');
expect(fn(2)).toEqual('nay!');
jest-mock-extended ตัวนี้สำหรับนี้ถือว่าเป็น Hero เพราะช่วยลดการ Mock ของได้มาก ๆ จากบทความที่แล้วเรื่อง Test double ผมมียกตัวอย่างของ NSubstitute ซึ่งเป็น Mocking library ของฝั่ง .NET สำหรับตัว jest-mock-extended จะทำงานเหมือนกันครับ แต่จะเป็นสำหรับ JavaScript และ TypeScript
วิธีติดตั้ง
pnpm i -D jest-mock-extended
ยกตัวอย่างการเป็นการใช้งานจริงเลยนะครับ ในที่นี้ใช้ NestJS Framework นะครับ
describe('GetUserByIdUseCase', () => {
const userRepository = mock<UserRepository>();
let userUserByIdUseCase: GetUserByIdUseCase;
beforeEach(() => {
userUserByIdUseCase = new GetUserByIdUseCase(userRepository);
});
afterEach(() => {
jest.resetAllMocks();
});
it(`should be get correctly user`, async () => {
// Arrange
const userId = 'userId';
const mockUser = mock<IUser>({
id: userId,
});
userRepository.getById.mockResolvedValue(mockUser);
// Act
const actual = await userUserByIdUseCase.execute(userId);
// Assert
expect(userRepository.getById).toHaveBeenCalledWith(userId);
expect(actual).toStrictEqual(mockUser);
});
});
export interface UserRepository {
getById(id: string): Promise<IUser>;
}
@Injectable()
export class GetUserByIdUseCase {
constructor(@Inject('UserRepository') private userRepository: UserRepository) {}
public async execute(userId: string): Promise<IUser> {
return this.userRepository.getById(userId);
}
}
ในที่นี้จะเห็นว่าเราทำ Dummy object ของ IUser แถมช่วยให้เราสามารถทำ Stub และ Mock object ที่ Function getById ของ userRepository ได้อย่างง่าย ๆ เลยทีเดียว
axios-mock-adapter ตัวนี้จะช่วยให้เราสามารถ Mock request ของ axios ได้ง่าย ๆ
วิธีติดตั้ง
pnpm i -D axios-mock-adapter
ขอยกตัวอย่างเพียงนิดหน่อยนะครับ ที่เหลือลองไปศึกษากันดูเองนะครับ
import MockAdaptor from 'axios-mock-adapter';
const mockAxios = new MockAdaptor(axios);
// Mock GET request to /users when param `searchText` is 'John'
// arguments for reply are (status, data, headers)
mock.onGet('/users', { params: { searchText: 'John' } }).reply(200, {
users: [{ id: 1, name: 'John Smith' }],
});
// Returns a failed promise with Error('Network Error');
mock.onGet('/users').networkError();
จบแล้วนะครับบทความนี้ หวังว่าจะเป็นประโยชน์กับหลาย ๆ คนที่เขียน Uni test ด้วย Jest นะครับ