Created
May 18, 2022 12:51
-
-
Save zirkelc/1ebb4e3d026bb85b6cbd4ae21174f83c to your computer and use it in GitHub Desktop.
Custom matcher in Jest
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fetch from 'cross-fetch'; | |
type Todo = { | |
id: number; | |
userId: number; | |
title: string; | |
completed: boolean; | |
}; | |
interface CustomMatchers<R = unknown> { | |
toMatchTodo(todo?: Partial<Todo> | Array<Partial<Todo>> | undefined): R; | |
} | |
declare global { | |
namespace jest { | |
interface Expect extends CustomMatchers {} | |
interface Matchers<R> extends CustomMatchers<R> {} | |
interface InverseAsymmetricMatchers extends CustomMatchers {} | |
} | |
} | |
expect.extend({ | |
toMatchTodo(received, expected) { | |
// define Todo object structure with objectContaining | |
const expectTodoObject = (todo?: Todo) => | |
expect.objectContaining({ | |
id: todo?.id ?? expect.any(Number), | |
userId: todo?.userId ?? expect.any(Number), | |
title: todo?.title ?? expect.any(String), | |
completed: todo?.completed ?? expect.any(Boolean), | |
}); | |
// define Todo array with arrayContaining and re-use expectTodoObject | |
const expectTodoArray = (todos: Array<Todo>) => | |
todos.length === 0 | |
? // in case an empty array is passed | |
expect.arrayContaining([expectTodoObject()]) | |
: // in case an array of Todos is passed | |
expect.arrayContaining(todos.map(expectTodoObject)); | |
// expected can either be an array or an object | |
const expectedResult = Array.isArray(expected) ? expectTodoArray(expected) : expectTodoObject(expected); | |
// equality check for received todo and expected todo | |
const pass = this.equals(received, expectedResult); | |
if (pass) { | |
return { | |
message: () => | |
`Expected: ${this.utils.printExpected(expectedResult)}\nReceived: ${this.utils.printReceived(received)}`, | |
pass: true, | |
}; | |
} | |
return { | |
message: () => | |
`Expected: ${this.utils.printExpected(expectedResult)}\nReceived: ${this.utils.printReceived( | |
received, | |
)}\n\n${this.utils.diff(expectedResult, received)}`, | |
pass: false, | |
}; | |
}, | |
}); | |
describe('Todo API', () => { | |
test('Get Todo By ID', async () => { | |
const todo = await fetch(`https://jsonplaceholder.typicode.com/todos/1`).then((r) => r.json()); | |
// match any Todo item | |
expect(todo).toMatchTodo(); | |
// match specific Todo item | |
expect(todo).toMatchTodo({ | |
id: 1, | |
userId: 1, | |
title: 'delectus aut autem', | |
completed: false, | |
}); | |
// fails because of missing properties (id, userId, completed) | |
expect({ title: 'delectus aut autem' }).toMatchTodo(); | |
}); | |
test('List all Todos ', async () => { | |
const todos = await fetch(`https://jsonplaceholder.typicode.com/todos`).then((r) => r.json()); | |
const todo1 = { | |
id: 1, | |
userId: 1, | |
title: 'delectus aut autem', | |
completed: false, | |
}; | |
const todo2 = { | |
id: 2, | |
userId: 1, | |
title: 'quis ut nam facilis et officia qui', | |
completed: false, | |
}; | |
// match any array of Todos | |
expect(todos).toMatchTodo([]); | |
// match array of Todos with specific items | |
expect(todos).toMatchTodo([todo1, todo2]); | |
// fails because of missing todo item (todo2) | |
expect([todo1]).toMatchTodo([todo1, todo2]); | |
}); | |
test('Create Todo', async () => { | |
const newTodo = { | |
userId: 1, | |
title: 'quis ut nam facilis et officia qui', | |
completed: false, | |
}; | |
const todo = await fetch(`https://jsonplaceholder.typicode.com/todos`, { | |
method: 'POST', | |
headers: { | |
'Content-type': 'application/json; charset=UTF-8', | |
}, | |
body: JSON.stringify(newTodo), | |
}).then((r) => r.json()); | |
// match any Todo item | |
expect(todo).toMatchTodo(); | |
// match specific newTodo item, but match any ID property as it's generated by the server | |
expect(todo).toMatchTodo(newTodo); | |
// fails because of id is string instead of number | |
expect({ ...todo, id: '2' }).toMatchTodo(newTodo); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment