Closed
Description
What
I'd like to suggest to use Mock Service Worker in test examples that concern API mocking.
Why
- MSW uses a declarative API to describe requests that should be mocked.
- MSW captures all outgoing network communication on both client and server. It also runs in a fall-through mode, which means unrelated requests are left intact.
- MSW utilizes Service Worker API on the client-side usage, making the mocks completely detached from the application. Unlike most of the other solutions, that means a request interception on the network level, not application level (i.e. making even the mocked requests/responses inspectable in the "Network" tab of your browser).
- MSW is not opinionated over how you construct your mock definitions. You can use plain request-response contracts, or bring in ORM and integrate it closer to your actual server's logic. The beauty if that you don't have to do that.
- MSW can be used on both client and server, being agnostic of frameworks and request-issuing libraries (use React, Vue,
fetch
oraxios
—you're covered).
Looks like @kentcdodds would support recommending
msw
as a part of Testing Library ❤️ .
What would it bring?
- Discourage people to stub
window.fetch
for the sake of API mocking. Instead, they would describe how an imaginary server would respond. - Educate people on how Service Worker can be used for API mocking (the approach is relatively new and not explored).
Where
Here's the "Example" page that showcases the usage of axiosMock.get.mockResolvedValueOnce
:
This example alone brings some of the following pain-points:
- It assumes that developer is using
axios
, making it a test's dependency. - It stubs
axios.get
method to make it return what you need. - Asserts of
axiosMock.get
was called, while it's not a part of the functionality we are testing.
Compare the page above with how it may look like with MSW:
// __tests__/fetch.test.js
import React from 'react'
import { render, fireEvent, waitFor, screen } from '@testing-library/react'
import '@testing-library/jest-dom/extend-expect'
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import Fetch from '../fetch'
const server = setupServer(
rest.get('/greeting', (req, res, ctx) => {
return res(ctx.json({ greeting: 'hello there'}))
})
)
beforeAll(() => server.listen())
afterAll(() => server.close())
test('loads and displays greeting', async () => {
const url = '/greeting'
render(<Fetch url={url} />)
fireEvent.click(screen.getByText('Load Greeting'))
await waitFor(() => screen.getByRole('heading'))
expect(screen.getByRole('heading')).toHaveTextContent('hello there')
expect(screen.getByRole('button')).toHaveAttribute('disabled')
})
Notice how test suite itself now knows nothing about the mocking. Because it shouldn't. We also remove the assertion that
axiosMock.get
was called, because it is not related to what we are actually testing.
How
I would be glad to issue a pull request regarding these changes. Any guidance on that is also highly appreciated!
Metadata
Metadata
Assignees
Labels
No labels