DEV Community

Discussion on: Testing a Generic Fetch Item List hook with Mock Service Worker

Collapse
 
rexebin profile image
Rex

Bringing the expert into the discussion makes a huge difference!

If testing query directly, a separate bad path approach is the best because the test can easily change the url.

But when it’s indirect, say if we are testing a form component which would make a request, we would have to touch the implementation details to manually change the url, which is less ideal.

Assuming we keep the mocked api very simple, a switch for a bad path for all apis may work better. If it is simply and works the same for all endpoints, it could be a known convention for the team. This also resembles the real api closer: the same api point can return good or bad response.

I love the idea of using global instead of local storage. I will make the switch, thank you!

Thread Thread
 
kettanaito profile image
Artem Zakharchenko

But when it’s indirect, say if we are testing a form component which would make a request, we would have to touch the implementation details to manually change the url, which is less ideal.

Well, you're still relying on that implementation detail in your handlers. I do share the notion not to expose too many internals in tests—on that I wholeheartedly agree. Yet observability is also a thing to consider, especially when it comes to the testing setup. I'd still go with explicit handler/override declaration 99% of the time.

This also resembles the real api closer: the same api point can return good or bad response.

Yeah, that is a perfectly valid way to model your request handlers. You can either focus each handler on a particular behavior and utilize overrides via server.use(), or scope handlers per resource, like in a conventional server, and include any conditional behavior within. I'd say it's a personal choice, which comes from the complexity of the mocked API before anything else.

My main concern with using global error mocking is the same as using anything globally: it may be hard to keep track of global setups. This is partially solved by descriptive naming (as in global.shouldRequestsError) but it still introduces an implicit piece of logic that is detached from MSW.

The "ideal" setup, in my opinion, would be to expose internals by reference. That's a cost-free way of exposing internal details.

// endpoints.js
export const getUserDetail = '/v2/user'
Enter fullscreen mode Exit fullscreen mode
// app.js
import { getUserDetail } from './endpoints'

function MyApp() {
  fetch(getUserDetail)
}
Enter fullscreen mode Exit fullscreen mode
// app.test.js
import { getUserDetail } from './endpoints'

it('handles server errors gracefully', () => {
  // Referencing the endpoint is a free way of
  // exposing internals.
  server.use(getUserDetail, (req, res, ctx) => res(ctx.status(500)))
})
Enter fullscreen mode Exit fullscreen mode
Thread Thread
 
rexebin profile image
Rex

Thank you! I didn’t know the override, my bad, I should read the docs a lot more.

With the override, I am very happy to ditch the global error mocking. So much clearer and so elegant!

Thread Thread
 
rexebin profile image
Rex

@kettanaito Thanks to your help, I have updated @mockapi/msw removing the global error handlers. I also recommended the use of server.use to override endpoints in the readme. Phew, almost mislead the community.

Thread Thread
 
rexebin profile image
Rex

@kettanaito I also updated the tests and setup here in this post to reflect the best practices.