Creating Reusable API Methods with Playwright Mimicking the Page Object Model

Ben Fellows

API testing is a critical aspect of software testing that is often overlooked, but it is an essential part of building a comprehensive Playwright test suite.

When building an application, developers rely on APIs to facilitate communication and data exchange between different software components. These APIs are the foundation of the application, and if they are not functioning properly it can lead to errors and instability in the application.

That's why it is so important to include API testing as part of your Playwright test suite. By performing API testing, you can catch any issues with the APIs before the application is released, saving time and effort in the long run. In addition, API testing helps to improve the reliability and robustness of the application, as it ensures that it is built on a solid foundation of well-functioning APIs.

But API testing is not just important for catching and fixing issues; it is also a valuable tool for verifying that the APIs are functioning as intended. By creating a set of API tests that cover a wide range of scenarios and input values, developers can gain confidence that the APIs are working correctly and will continue to do so as the application evolves.

Page Object Models & API Testing

Many automation engineers are comfortable building page object models for UX/UI tests, but may not have as much experience creating reusable methods for API tests using Playwright. This is because page object models are a common design pattern for automating UX/UI tests, and they provide a clear structure and separation of concerns that make it easier for engineers to build and maintain test scripts. 

In contrast, API tests can be more challenging to automate because they often involve a greater degree of complexity, such as dealing with different types of request and response payloads, handling authentication and authorization, and managing rate limits and other constraints. As a result, many automation engineers may not feel as confident building reusable methods for API tests, and may rely more on ad-hoc test scripts that are less maintainable in the long run.

Shared API Methods

At Loop, we advocate for organizing API calls by creating a separate file for each end point. This allows for clear separation of concerns and makes it easier to locate and maintain the code for a specific end point. Additionally, if you have larger categories of end points, you can group the end point files together within a folder or directory.

Additionally, grouping API calls by end point can help to clarify the purpose and functionality of each call. For example, a file for the "create user" end point might contain API calls for creating a new user, updating a user's profile, and deleting a user, while a file for the "product catalog" end point might contain calls for retrieving a list of products, searching for a specific product, and updating product information. This organization makes it easier for other team members to understand the functionality of the API and how it is being tested.

If you have a large number of end points, it can also be helpful to group the end point files by larger categories. For example, you might have a "users" directory that contains all of the end points related to user management, and a "products" directory that contains all of the end points related to the product catalog. This can help to further clarify the structure and purpose of the API and make it easier to navigate.

Download our Automation ROI Formula

APIRequestContext

If you want to make a class that includes reusable API methods with Playwright Automation, we recommend you use the APIRequestContext. The APIRequestContext is a utility class that provides a simplified interface for making API calls within the Playwright automation environment.

One of the key benefits of using the APIRequestContext is that it abstracts away many of the low-level details of making HTTP requests. This means that you can focus on building the specific functionality of your API, rather than worrying about the underlying mechanics of sending and receiving HTTP requests.

The APIRequestContext also includes a number of convenient features, such as automatic retry logic and support for specifying custom HTTP headers. This can make it easier to build robust and reliable API clients that can handle a wide range of scenarios and use cases.

Example Code

Housing Data in Constructors

At Loop, we prefer to use reusable API methods that rely on arguments being passed in from the test. This allows our API methods to be flexible and adaptable, as they can accept a variety of different inputs and use them to perform a specific task.

Our template at Loop includes arguments for the request body, the response body, and the status. This allows us to compare the results within each method and significantly reduce the time it takes to write and maintain our code. By encapsulating this logic within a single method, we can avoid repeating the same code across multiple tests, which helps to reduce the overall complexity and maintenance burden of our test suite.

We use the dotenv node library for controlling the base URL of our API calls. This library allows us to specify the base URL as an environment variable, which can be passed in at runtime. This approach has a number of benefits, including the ability to easily switch between different environments (such as staging and production) and the ability to maintain a separation between the codebase and environment-specific configurations.

Using the dotenv library is simple and straightforward. First, we create a .env file in the root of our project and specify the base URL as an environment variable. Then, we can access this variable within our code using the process.env object. This allows us to dynamically construct the full API URL at runtime, based on the environment in which the code is running.

Example Code

Download our Automation ROI Formula

Inserting Arguments

At Loop, we prefer to use reusable API methods that rely on arguments being passed in from the test. This allows our API methods to be flexible and adaptable, as they can accept a variety of different inputs and use them to perform a specific task.

Our template at Loop includes arguments for the request body, the response body, and the status. This allows us to compare the results within each method and significantly reduce the time it takes to write and maintain our code. By encapsulating this logic within a single method, we can avoid repeating the same code across multiple tests, which helps to reduce the overall complexity and maintenance burden of our test suite.

We use the dotenv node library for controlling the base URL of our API calls. This library allows us to specify the base URL as an environment variable, which can be passed in at runtime. This approach has a number of benefits, including the ability to easily switch between different environments (such as staging and production) and the ability to maintain a separation between the codebase and environment-specific configurations.

Using the dotenv library is simple and straightforward. First, we create a .env file in the root of our project and specify the base URL as an environment variable. Then, we can access this variable within our code using the process.env object. This allows us to dynamically construct the full API URL at runtime, based on the environment in which the code is running.

Example Code

Leveraging Test Steps (Human Readable Reporting)

At Loop, we leverage Playwright's test.step functionality in order to build our shared API methods. This allows us to structure our tests in a logical and easy-to-follow manner, and it also provides us with a range of helpful features and capabilities.

The first step is the actual action, such as a POST, GET, or DELETE request. This is the core functionality of the method, and it typically involves sending an HTTP request to a specific end point and handling the response.

The second step is a check to determine whether the status returned as expected. This is an important step, as it allows us to verify that the API is functioning correctly and that the response is what we expected.

The third step is a comparison of the JSON body. This involves examining the structure and content of the response payload to ensure that it meets the requirements of our tests. For more information about comparing JSON bodies, you can refer to this article.

Example Code

Overall, these three steps form the foundation of our shared API methods at Loop. By following this approach, we can ensure that our methods are reliable, maintainable, and easy to use.


Conclusion

In conclusion, building reusable API methods with Playwright is an important aspect of creating a comprehensive and maintainable test suite. By following best practices such as organizing API calls by end point, grouping end points by larger categories, and leveraging the APIRequestContext utility class, automation engineers can build reliable and efficient methods that are easy to understand and use.

 

Additionally, by leveraging Playwright's test.step functionality, engineers can break down their methods into clear and discrete units of work, making it easier to understand and maintain the tests. 

Overall, by investing the time and effort to build reusable API methods, engineers can save time and effort in the long run, while also improving the reliability and robustness of their applications.

Download our Automation ROI Formula

More from Loop

Get updates on Loop's best content

Stay in touch as we publish more great Quality Assurance content!