84
vitest + mocks = πͺ superpower
Previously, we discovered how powerful vitest can be when used with vite.
Using mocks gives us the flexibility to simulate, develop, test, and refine use cases quickly and easily.
For mocking behavior in development and API integration I will use MSW.
For simple function business logic, I will demonstrate vitest mocking function.
Full code - https://github.com/yanirmanor/vite-test-vitest
For a simple function mock you will use
vi.fn()
then you have all kinds of functions that you can use and control the mock. The most popular I think is mockReturnValue for mocking the return value or mockImplementation for mocking the function implementation.
examples:
vi.fn().mockReturnValue(23)
expect(mockFnOverrideValue()).toBe(23)
const mockFnGetSum =
vi.fn().mockImplementation(sum => sum * 3.14)
const total = mockFnGetSum(100)
expect(total).toBe(314)
Nice. now I will show how you can use MSW for development and testing.
First install msw -
pnpm install msw --save-dev
then run
pnpx msw init public/ --save
In development - I created a vite .env variables VITE_MOCKING and set it to be true.
in the app.jsx I added an if statement, then you need to create and handlers a set of request mock.
you need to set the handlers array inside setupWorker and make it start.
you can open the network tab inside the chrome devtools
and look for the service worker in the response header.
also, you will see in devtools console - [MSW] Mocking enabled
if (import.meta.env.VITE_MOCKING === true) {
const handlers = [
rest.get('https://randomuser.me/api/', (req, res, ctx) => {
return res(
ctx.delay(1000),
ctx.status(202, 'Mocked status'),
ctx.json({
results: [
{
name: {
first: 'John',
last: 'Doe'
}
}
]
})
)
})
]
const worker = setupWorker(...handlers)
worker.start()
}
We have almost done.
this technique is similar for testing.
instead of using serviceWorker we will replace it with setupServer
and start this node server to run by listen() before all tests
, after all, we call close and finally on after each test we will reset
const server = setupServer(...restHandlers)
// Start server before all tests
beforeAll(() => server.listen({ onUnhandledRequest: 'error' }))
// Close server after all tests
afterAll(() => server.close())
// Reset handlers after each test `important for test isolation`
afterEach(() => server.resetHandlers())
With this approach, your tests will be cleaner and more readable, and your software will be developed more quickly.
Enjoy π
84