Supercharge Your API Testing with Playwright and TypeScript
Tags: playwright, typescript, automation
Published: 2023-10-30 08:59:33

**Introduction**

API (Application Programming Interface) testing is a critical part of software development. Ensuring that APIs perform as expected is essential for delivering a seamless user experience. TypeScript, a statically typed superset of JavaScript, along with Playwright, can be a powerful combination for API automation in a type-safe manner. In this blog, we'll explore how to supercharge your API testing using Playwright and TypeScript.

**What is Playwright?**

Playwright is an open-source automation framework developed by Microsoft that allows you to interact with web applications in a browser-agnostic way. It natively supports TypeScript, making it a versatile choice for automation. While its primary purpose is web automation, Playwright can be extended for API testing using its powerful features.

**Why Use Playwright with TypeScript for API Automation?**

1. **Type Safety**: TypeScript enforces static typing, catching errors at compile time rather than runtime, which leads to more reliable code.

2. **Cross-Browser Compatibility**: Playwright supports multiple browsers like Chrome, Firefox, and WebKit, ensuring that your API tests are browser-agnostic.
 
3. **Headless Mode**: Playwright can run tests in headless mode, which is crucial for running tests on CI/CD pipelines and servers without a graphical user interface.
 
4. **Parallel Testing**: Playwright enables parallel test execution, reducing the time it takes to run your API tests.

**Getting Started with API Automation Using Playwright and TypeScript**

Let's dive into the steps to get started with API automation using Playwright and TypeScript.

**Step 1:** Install node.js on your machine

You can download it directly from the Node.js website and install it on your machine. Once installed, check the version:

```
node -v
```

**Step 2:** Download and Install Visual Studio Code

**Step 3:** Open your integrated terminal and run the following command

```
mkdir playwright-api-testing
```
**Step 4:** Open the directory

```
cd playwright-api-testing
```
**Step 5:** You can install Playwright using npm or yarn, and another way is by VS Code Extension
we can install the Playwright using the npm command

```
npm init playwright@latest
```

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aap7xj6vg88cstcw5585.png)

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf9p8ski356dcf2qgn0i.png)
Now let's create a sample project and see some CRUD (Create, Read, Update, Delete) operations examples for an API using Playwright and TypeScript.

For this example, we'll assume we are interacting with a hypothetical RESTful API for managing bookings. We will implement each of the CRUD operations: creating booking, get booking, updating booking, and delete booking.

Update baseURL in the playwright.config.js file so you can use it in each endpoint testing without specifying them.

`baseURL: 'https://restful-booker.herokuapp.com'`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/65jrft4lnb5tvrwgkb5i.png)

**POST - Booking with static data specified in JSON file:**
Create a folder with the name test-data and then add a JSON file with the name booking-details.json. In the booking-details file, mention all the booking details you must pass while making a POST call.

```
{
    "firstname": "Alex",
    "lastname": "Lee",
    "totalprice": 2000,
    "depositpaid": true,
    "bookingdates": {
        "checkin": "2023-01-01",
        "checkout": "2023-02-15"
    },
    "additionalneeds": "Breakfast"
}
```
To create a new booking, we need to pass the data from JSON in POST request to the /booking endpoint, we need to provide the request body by using a JSON file. 

```
import { test, expect } from '@playwright/test';
import bookingDetails from '../test-data/booking-details.json';

test('should be able to create a booking', async ({ request }) => {
    const response = await request.post(`/booking`, {
        data: bookingDetails
    });
    console.log(await response.json());
    expect(response.ok()).toBeTruthy();
    expect(response.status()).toBe(200);
    const responseBody = await response.json()
    expect(responseBody.booking).toHaveProperty("firstname", "Alex");
    expect(responseBody.booking).toHaveProperty("lastname", "Lee");
    expect(responseBody.booking).toHaveProperty("totalprice", 2000);
    expect(responseBody.booking).toHaveProperty("depositpaid", true);
});
```
Here, we first import the JSON data, store it in variable and then call this in the test under data. Once we receive a response we then assert by using expect condition for the Ok message and status code 200. Then assert the response body to check the key and value.
Run the below mentioned command to execute the test:
`npx playwright test post-req-jsonData.spec.ts`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zmgbr0ja7iagtylq2r5z.png)

**GET all bookings:**
To get all bookings, we will use a GET request to the /booking endpoint

```
import { test, expect } from '@playwright/test';

test('should be get all the booking details', async ({ request }) => {
    const response = await request.get("/booking");
    console.log(await response.json());
    expect(response.ok()).toBeTruthy();
    expect(response.status()).toBe(200);
});
```
Once the request is completed, we will receive the response. Here, we assert by using expect condition for the ok message and status code 200. Here we are also logging the entire output to the console. We can also get only the specific booking details by providing the booking id. 
example: `const response = await request.get('/booking/1');`
Run the following command:
`npx playwright test get_booking_details.spec.js`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5wx3bp75lazug1o8r42a.png)

**Update a resource [PUT]:**
It is used to update the current booking details.
```
import { test, expect } from '@playwright/test';

let token

test('Update the booking details', async ({ request }) => {

    // Create a Token to use in PUT request

    const response = await request.post(`/auth`, {
        data: {
            "username": "admin",
            "password": "password123"
        }
    });
    console.log(await response.json());
    expect(response.ok()).toBeTruthy();
    expect(response.status()).toBe(200);
    const responseBody = await response.json();
    token = responseBody.token;
    console.log("New Token is: " + token);

    // PUT
    const updateRequest = await request.put(`/booking/1`, {
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Cookie': `token=${token}`,
        },
        data: {
            "firstname": "Alex",
            "lastname": "Lee",
            "totalprice": 2000,
            "depositpaid": true,
            "bookingdates": {
                "checkin": "2023-01-01",
                "checkout": "2023-03-15"
            },
            "additionalneeds": "Breakfast"
        }
    });
    console.log(await updateRequest.json());
    expect(updateRequest.ok()).toBeTruthy();
    expect(updateRequest.status()).toBe(200);
    const updatedResponseBody = await updateRequest.json()
    expect(updatedResponseBody).toHaveProperty("firstname", "Alex");
    expect(updatedResponseBody).toHaveProperty("lastname", "Lee");
    expect(updatedResponseBody).toHaveProperty("totalprice", 2000);
    expect(updatedResponseBody).toHaveProperty("depositpaid", true);
});
```
In this test, we make a POST call to an endpoint /auth to generate the token, which needs to be passed along with the PUT request. Once we receive a response we will store it in a variable. Then we make a PUT call to an endpoint /booking/1 and pass the token in the header and body in the data. Then we receive the response and we assert it by using expect condition. We also assert the response body to check the key and value.
Run the following command:
`npx playwright test update_booking_details.spec.js`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9nzqt42764anasczntti.png)

**Delete (DELETE) a Booking:**
This is used to delete the existing booking from the database.
```
import { test, expect } from '@playwright/test';

let token

test('delete the booking details', async ({ request }) => {

    // Create a Token to DELETE request

    const response = await request.post(`/auth`, {
        data: {
            "username": "admin",
            "password": "password123"
        }
    });
    console.log(await response.json());
    expect(response.ok()).toBeTruthy();
    expect(response.status()).toBe(200);
    const responseBody = await response.json();
    token = responseBody.token;
    console.log("New Token is: " + token);

    // DELETE

    const deleteRequest = await request.delete(`/booking/1`, {
        headers: {
            'Content-Type': 'application/json',
            'Cookie': `token=${token}`
        }
    });
    expect(deleteRequest.status()).toEqual(201);
    expect(deleteRequest.statusText()).toBe('Created');
});
```
In this example, we generate a token that needs to be passed with the delete request. Then we store the token in a variable and make a delete call. We then pass the token in the header and receive a response which we can assert by using expect condition.
Run the following command:
`npx playwright test delete_booking_details.spec.js`

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bo1x18xst1ymi56fmycc.png)

These examples demonstrate how to perform CRUD operations on an API using Playwright and TypeScript. You can adapt these scripts to your specific API and application needs.

**Advanced API Testing with Playwright and TypeScript**

Take advantage of TypeScript's features to enhance your API automation:

1. **Type Definitions**: Leverage type definitions and interfaces to define the shape of your API responses, making your code more self-documenting.

2. **Error Handling**: Implement robust error handling strategies using TypeScript's error handling mechanisms to handle unexpected scenarios gracefully.

3. **Parameterization**: Use TypeScript's type-safe parameterization techniques to iterate through different input values and validate API responses.

4. **Integration with Test Runners**: Integrate Playwright and TypeScript-based API tests with popular test runners like Jest or Mocha for structured test organization. 

5. **CI/CD Integration**: Easily incorporate TypeScript-based Playwright API tests into your CI/CD pipelines for continuous testing and deployment.

**Conclusion**

Combining Playwright with TypeScript for API automation enables you to create robust, type-safe tests. TypeScript's static typing catches errors early in the development process, while Playwright offers cross-browser support and a range of features for API testing. By incorporating TypeScript-based Playwright API tests into your development workflow, you can ensure the reliability and quality of your software, leading to a more seamless user experience.