Tips & Tricks : Intuitive API Testing With Playwright

Amr Salem
6 min readOct 18, 2023

Hey there, my dear friends! API testing is undeniably a vital aspect of our testing journey. It plays a significant role as the second layer in the testing pyramid. API testing offers remarkable efficiency and cost-effectiveness, allowing us to catch potential bugs in the early stages of development.

You can approach API testing in two different ways. The first is the traditional manual method using tools like “Postman” for execution. Alternatively, you can automate the test cases using any of the existing API testing tools with the relevant programming language. In this blog, we will explore the process of constructing an API automation framework using Playwright in a proactive way. Our goal is to embrace the best practices, ensuring efficiency and maximised utility.

Let’s check it out together! 🚀

Why Choose Playwright for API Testing? There are many reasons for using Playwright when it comes to API testing. One primary advantage is utilising the full power of Playwright. Playwright supports API testing out of the box, granting us access to all API request methods. This includes the ability to use essential assertions, leverage test fixtures, and employ necessary testing hooks — all without the need for external test runners like “Mocha” or “Jest”, among others. With Playwright, API testing becomes a seamless and efficient part of your testing toolkit.

We’ll initiate the process by performing a standard installation of the “@playwright/test” package in our package.json file, and then proceed to include the required test script.

We’ll employ the Page Object Model (POM) design pattern to enhance reusability, readability, and facilitate debugging. Here is the envisioned structure of our framework:

1. “Features” will serve as the repository for storing specialized API requests and associated logic for each relevant feature.

2. We will utilize a “Fixture” to kickstart our API abstraction process. It will pass the request instance to the constructor in APIutils.ts.

3. Within “APIutils.ts,” we will house all the test methods for API requests that will be utilized in our testing process.

4. Within “APITestSuite.ts,” we will contains all our test cases to be executed

And finally the playwright.config.ts file which contains all the basic configurations that we need for our framework

One convenient method available to us in Playwright is to utilize the “request” argument within Playwright test parameters, allowing us to directly invoke it from our test block, as demonstrated below.

This represents the simplest and quickest approach for conducting your API tests with minimal coding effort. However, if you wish to execute more complex scenarios with more nested request while utilizing the same request instance simultaneously, it will be better to warp them inside a test method (“POM”) to achieve this through the test fixture.

Building our test fixture is quite straight forward as showing below,
we are establishing custom fixtures, including the “API” fixture of type api, extending the base test object. The "API" fixture sets up an instance of the api utility using the Playwright request object and makes it available to tests via the use function, ensuring easy API interaction.

Now we can write our testing method inside our APIUtils.ts
This code below defines a class named API for handling API requests using Playwright. It initializes an instance of the class with an APIRequestContext object, allowing it to interact with HTTP requests managed by Playwright.

import { APIRequestContext } from "playwright-core";

export default class API {
private request: APIRequestContext;

constructor(request: APIRequestContext) {
this.request = request;
}

After that we can easily write our testing method as shown below:

  async postReq(endpoint: string, reqBody: object) {
const res = await this.request.post(endpoint, { data: reqBody })
return res
}

async getReq(endpoint: string) {
const res = await this.request.get(endpoint)
return res
}

async putReq(endpoint: string, reqBody: object, token: string) {
const res = await this.request.put(endpoint, {
data: reqBody, headers: {
'Cookie': `token=${token}`
}
})
return res
}

async patchReq(endpoint: string, reqBody: object, token: string) {
const res = await this.request.patch(endpoint, {
data: reqBody, headers: {
'Cookie': `token=${token}`
}
})
return res
}

async deleteReq(endpoint: string, token: string) {
const res = await this.request.delete(endpoint, {
headers: {
'Cookie': `token=${token}`
}
})
return res
}

To enhance reusability, minimize redundancy, and achieve more optimized code, we can structure it as follows:

This code defines a private method, `makeRequest`, for sending HTTP requests with Playwright. It accepts parameters like the endpoint, HTTP method, request body, and an optional token for authentication. It forms the request, including headers and data, and returns the response.

Additionally, there are methods such as postReq’ and ‘getReq’..etc, that use `makeRequest` for making POST and GET.. requests, respectively. These methods simplify API testing by specifying the HTTP method and handling request details.

For our API test suite, the process is straightforward. We begin by importing the necessary libraries and test fixtures. Then, we define our describe block, test hooks and cases according to our our scenarios.

Next, as we proceed with crafting our test cases, we do so by creating test blocks and utilizing the API parameter. This parameter allows us to invoke all the test methods within the API class.

Now we can execute our test and preview the testing report as shown below:

Conclusion

API testing plays a pivotal role in our testing process, and extensive coverage of it contributes to a high-quality product. Playwright can be an excellent tool for API testing, especially when it’s the same tool used for end-to-end testing. This choice reduces the number of testing tools and utilizes the flexibility and capabilities provided by Playwright. In this blog, I’ve showcased both the conventional approach and an alternative method, particularly valuable for complex and nested scenarios, to create more clean, readable and optimized test cases. I’ve also included examples for the most common API RESTful verbs, including GET, PUT, PATCH, and DELETE.

References

https://playwright.dev/docs/
Repository Url will be available soon on my linkedin project section

Thank you for taking the time to read my blog — I hope it provided some insight and value into your project. Stay tuned for the new upcoming interesting blogs…

--

--