DEV Community

yanir manor
yanir manor

Posted on

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) 
Enter fullscreen mode Exit fullscreen mode
const mockFnGetSum = 
  vi.fn().mockImplementation(sum => sum * 3.14)
  const total = mockFnGetSum(100)
  expect(total).toBe(314) 
Enter fullscreen mode Exit fullscreen mode

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()
}
Enter fullscreen mode Exit fullscreen mode

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())
Enter fullscreen mode Exit fullscreen mode

With this approach, your tests will be cleaner and more readable, and your software will be developed more quickly.
Enjoy 😎

Top comments (4)

Collapse
 
drazisil profile image
Molly Crendraven

Thank you! Very helpful! :)

Collapse
 
simmol profile image
Pavlin Angelov

Is it me or this article/tutorial is missing details?
How we got from using simple vi.fn for mocking to
install MSW (what is this? And why should I care about it?

I neither understood what this is suppose to achieve, nor how to achieve it :(

Collapse
 
manoryanir profile image
yanir manor

This article is about mocking vitest and the great power that you will get if you are using msw as mocking api calls for integration testing. Integration testing are very more efficient than unit testing.
In this article you can see how easy it is to install and using it. Also, you can use it for development.

Collapse
 
simmol profile image
Pavlin Angelov • Edited

Then the title should be something like vitest + MSW = 💪 superpower instead of vitest + mocks = 💪 superpower

And at least introduce the fact you are proposing to use an external package, not the vitest mocking functionality itself.

Integration testing are very more efficient than unit testing.
Efficient in what manner? If I have to install external packages, configure it, and run it each time I want to run my tests. It doesn't sound more efficient to me than just writing one test with correct mocks and being done with it.

But for each their own.
No matter the approach taken, the Article title is misleading and the premise is unclear.

So you may want to edit that, to make it a bit more clear what you are proposing and explaining.

Have a good day