Playwright API testing with zod

profile
Tim Deschryver
timdeschryver.dev

As you probably are already aware of, I'm a big fan of Playwright and zod. In this blog post, we'll see how we can combine the two to write API tests.

Note

If you're new to Playwright API testing, I recommend taking a look at the official documentation to follow along.

Starting point link

When you're reading the documentation or looking at examples of how to write API tests with Playwright, you'll come across examples using the following structure. The examples use the request context to fire an HTTP request and validate the content of the response object.

This is fine, and it can be a valid requirement to verify the content. But, in most cases, I'm more interested in the shape of the response, and not particularly the content. These tests are more flexible, and less likely to break when the content changes (for example when you're running the same tests on multiple environments).

But do these tests enough provide value? Yes of course because it's your assurance that the contract between the front-end application and the API is kept up-to-date and is valid.

Enter zod link

Luckily, we can use zod to validate the shape of the response.

To use zod to validate the shape of the response, we first need to define a schema. In the example below, we define a schema todoSchema for a todo item. When you're already using zod, for example to verify HTTP response bodies at runtime, this becomes even easier because you can reuse the same schema in production code as in test code.

Then, we use the parse method to validate the response body against the zod schema. Under the hood, zod will throw an error when the response body doesn't match the schema, so we can use the .not.toThrow() assertion from Playwright to test if the shape is correct.

When the response body doesn't match the schema, the test fails with the following error message.

Refactor to a custom Playwright Matcher link

The example above works, but it's not very readable and when we're using this technique in multiple tests we're also duplicating some code. A better approach is to create a custom Playwright matcher. This way, the intention of the test becomes clearer. Another advantage is that the logic is centralized, and if the zod implementation changes, we only need to update it in one place.

Let's take a look at the implementation of the custom matcher, let's call our matcher toMatchSchema. To create the toMatchSchema matcher, we need to extend the expect object from Playwright and add a new method. We can do this by including the matcher in the playwright.config.ts file using the expect.extend() method.

This method name is going to be the name of the matcher, so we'll call it toMatchSchema. The matcher receives the input argument (expect(input)), and in our case accepts the zod schema as the second argument, which we'll need to provide in our test case(s).

Instead of throwing an error when the schema doesn't match, we'll use the safeParse method from zod within this implementation. This method returns a SafeParseReturnType<any, any> object, which contains a success property to indicate if the schema matches. When the schema matches, this property is true, otherwise it's false.

If the schema doesn't match, we can also access the zod issues. These issues contain more information about the error. To improve the developer experience, we'll use the issues property to create a more descriptive error message.

To make TypeScript happy, we also need to define the toMatchSchema matcher within the Playwright schema.

With these two changes in place, we can now use the toMatchSchema matcher in our test case(s).

When the schema doesn't match, the test fails with the following error message.

Recap link

In this blog post, we've seen how we can use zod within our Playwright tests to verify the shape of the response. This technique is beneficial when we're interested in the shape of the response, and not the content. Doing this makes sure that the contract between the front-end application and the API is aligned.

To implement this, we've created a custom Playwright matcher that uses the safeParse method from zod to verify the shape of the response. When the response doesn't match the schema, the test fails with a descriptive error message.

Outgoing links

Feel free to update this blog post on GitHub, thanks in advance!

Join My Newsletter (WIP)

Join my weekly newsletter to receive my latest blog posts and bits, directly in your inbox.

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

Share this post

Twitter LinkedIn