Tim Deschryver

Using zod-fixture with MSW to generate mocked API responses

@tim_deschryver

In the last blog post we've already covered a use case for zod-fixture in How zod-fixture can help with your test setups. In this blog post, we're extending that idea by integrating zod-fixture with Mock Service Worker (MSW).

To give a small recap of what zod-fixture is, it's a library that makes use of a zod schema to generate instances that satisfy the shape of its schema. Instead of thinking about the values an object must have and creating them manually, zod-fixture makes it easy to create new objects.

In most cases, as long as the object has the correct shape and the properties have the correct type, the actual value(s) don't matter that much. For example, let's say the application fetches a collection of customers via an HTTP request and renders them on the page. In this case it doesn't matter if the first name is an actual first name (e.g. "Sarah"), or if it's a generated one (e.g. "firstName-28a0c5ef-3bb9-4bb9-88b5-d7489058a570"). As long as it gets rendered we know that we have a working feature.

In this blog post, we see how to create a mocked API with MSW, in combination with zod-fixture to return randomly generated response models.

Mock by intercepting requests on the network level. Seamlessly reuse the same mock definition for testing, development, and debugging. - mswjs.io

If this is the first time that you hear MSW, I encourage you to take a look at their docs just to get an idea of why it's useful. Personally, I find MSW effective to create a new front-end feature without having a backend API up and running. It can then also serve as a way to mock your services in test suites, as we've explored in Using MSW (Mock Service Worker) in an Angular project.

Let's have a look at a simple example, and render a collection of customers.

The first thing I start with is to define the interface of the needed models, in this case, a Customer model. Because we're using zod, we do this by using the z utility methods. The benefit of this, in contrast to defining a "normal" TypeScript interface, is that we also have a schema that holds the meta-data of these contracts at runtime.

Once the model is defined, we can use its schema within an MSW Rest handler to generate a response object. In our example, we pass the a CustomerSchema to the createFixture method of zod-fixture to generate a collection of customers.

Now, every time the application hits the customer's endpoint (/api/customers), it gets intercepted by the handler, which returns a new mocked response. As you can notice from an example response below, the customers are randomly generated but follow a few conventions, for example, the prefix of a string is always the property name, and a collection always has 3 items. It's possible to tweak the default behavior, but this falls out of the scope of this blog post.

And that's it, we've successfully created an MSW handler that uses zod and zod-fixture to create response models!

Conclusion

I don't like to spend time creating response objects and thinking of the values I give to these objects. Once I believed that all of the data must be real, and I would spend (a lot of) time creating and maintaining this data. Over the years I learned that there's no such thing as perfect test data and that using the shape is crucial to create working applications.

That's why I like to use zod-fixture because it generates this data for me. This way, I don't have to spend time thinking about what to return anymore and I can give more focus to the implementation of a feature.

zod-fixture in combination with MSW is a powerful combination because it allows me to have a mocked API, which can be consumed by the application when it's under development, and by the tests, we write to verify that the application is working as intended.

You'll also see that by using MSW, the rest of the application doesn't change. If you're working with Angular, this means that there's probably a component that consumes a service that fires HTTP requests with the HttpClient. Within the test cases, the HTTP client or the service doesn't need to be mocked as it does with "traditional" tests that don't use MSW. Because the HTTP requests are intercepted the actual API isn't hit and you don't create a dependency on the actual API. This practice means that your tests won't be slowed down and that you could create and test your frontend feature independently from the backend.

Tim Deschryver

@tim_deschryver

Another zod use case: parsing the query parameters of a route.
If it isn't obvious, I keep liking this library more and more.

Outgoing links
Support me

I appreciate it if you would support me if have you enjoyed this post and found it useful, thank you in advance.

Buy Me a Coffee at ko-fi.com PayPal logo
Support the blog Share on Twitter Discuss on Twitter Edit on GitHub