API Testing with Postman (Manual and Automated)

Manual API Testing with Postman API testing is crucial to ensure that APIs are functioning correctly and as expected. Postman is one of the most popular tools for manual API testing due to its ease of use and flexibility. Here’s how you can manually test an API with Postman:

  1. Set Up Postman
    • Download and install Postman.
    • Create a new request by selecting the appropriate HTTP method (GET, POST, PUT, DELETE).
    • Enter the endpoint URL, headers, parameters, and body (if applicable).
  2. Make the API Request
    • Hit the “Send” button and review the response, ensuring that the status code and response body match expectations.
    • Validate response headers, body structure, and values to ensure correctness.
  3. Testing Common API Assertions
    • Status Codes: Ensure the correct HTTP status code is returned (e.g., 200 for success, 404 for not found).
    • Response Time: Verify that the API responds within an acceptable timeframe.
    • Response Structure: Confirm the body contains the correct data and structure (e.g., JSON, XML).

Automated API Testing with Newman Once you’ve manually tested your API, you can automate the tests using Newman, the command-line tool that runs Postman collections.

  1. Export Postman Collection
    • After creating and testing your API requests, export your collection to a JSON file in Postman.
  2. Install Newman
    • Install Newman globally using npm: npm install -g newman
  3. Run Tests with Newman
    • Run the collection in your CI pipeline or locally: newman run /path/to/your/collection.json
    • You can specify environments, data files, and other options to customize the test run.
  4. Integrating with CI/CD
    • Integrate Newman into your CI/CD pipeline (e.g., Jenkins, GitHub Actions) to run automated API tests after each deployment.

API Testing with Selenium, Cypress, and Playwright (Happy and Sad Paths)

API Testing with Selenium Selenium is primarily used for UI testing, but it can also be leveraged for API testing by making HTTP requests and verifying responses. Here’s a simple scenario for both happy and sad paths:

  • Happy Path: Test that a correct request returns the expected response.
  • Sad Path: Simulate invalid requests to ensure the API returns the correct error codes (e.g., 400 or 404).

Example Scenario:

  1. Happy Path Test (GET request)
    • Send a GET request to the endpoint /api/v1/users.
    • Expected Result: Status code 200 and a JSON body with a list of users.
  2. Sad Path Test (GET request)
    • Send a GET request to the endpoint /api/v1/users/9999999 (non-existent user).
    • Expected Result: Status code 404 and an error message stating the user doesn’t exist.

API Testing with Cypress Cypress is another tool primarily designed for end-to-end testing but can also be used for API requests. Cypress makes it easy to test both happy and sad paths using its cy.request() command.

Example Scenario:

  1. Happy Path Test (POST request)
    • Send a POST request to /api/v1/users with a valid JSON body: { "name": "John Doe", "email": "john@example.com" }
    • Expected Result: Status code 201 and a JSON response with the created user’s details.
  2. Sad Path Test (POST request)
    • Send a POST request to /api/v1/users with missing or invalid data (e.g., no email).
    • Expected Result: Status code 400 and an error message indicating the validation failure.

API Testing with Playwright Playwright is another powerful tool that can handle API requests in addition to UI tests. Its approach to API testing is similar to Selenium and Cypress but with added performance benefits.

  1. Happy Path Test (PUT request)
    • Send a PUT request to update an existing user’s details, e.g., /api/v1/users/12345 with valid data.
    • Expected Result: Status code 200 and updated user data in the response.
  2. Sad Path Test (PUT request)
    • Send a PUT request to /api/v1/users/12345 with invalid or incomplete data.
    • Expected Result: Status code 400 and an error message for invalid data.

Combined UI and API Testing: Manual and Automated (Happy and Sad Paths)

Manual Combined UI and API Testing

For manual testing, we will simulate a user action (e.g., login) and validate both the UI behavior and API response.

Test Scenario 1 (Happy Path):

  1. UI Interaction:
    • The user enters valid credentials and clicks the “Login” button.
  2. API Verification:
    • The API should return a success response with status code 200 and relevant user data.

Example of UI Interaction (Login Form):

  • Fill in the username and password fields in the web UI, click the submit button.

Example API Verification:

  • Verify the API response using Postman or any tool of choice.

Expected Result:

  • The user is logged in successfully, and the API returns the correct user data.

Test Scenario 2 (Sad Path):

  1. UI Interaction:
    • The user enters invalid credentials and clicks the “Login” button.
  2. API Verification:
    • The API should return an error with status code 401 (Unauthorized) and an error message.

Example of UI Interaction (Login Form):

  • Enter an incorrect username or password in the UI.

Example API Verification:

  • The API should respond with a 401 Unauthorized status.

Expected Result:

  • The login fails with an appropriate error message shown on the UI, and the API returns a proper error response.

Automated Combined UI and API Testing

Let’s now move to automated testing, where we can perform both UI actions and API calls within a test script.


1. Automated Combined UI and API Testing with Selenium

For Selenium, we’ll use the WebDriver to interact with the UI and also use libraries like HttpURLConnection or RestAssured to call the API.

Example:

Happy Path:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import io.restassured.RestAssured;
import io.restassured.response.Response;

public class CombinedUITest {
    public static void main(String[] args) {
        // Set up WebDriver and open the login page
        WebDriver driver = new ChromeDriver();
        driver.get("http://yourapp.com/login");

        // Enter valid credentials in the login form
        driver.findElement(By.id("username")).sendKeys("validUser");
        driver.findElement(By.id("password")).sendKeys("validPassword");
        driver.findElement(By.id("loginButton")).click();

        // Verify that the UI navigates to the homepage
        Assert.assertTrue(driver.getTitle().contains("Home"));

        // API Request to verify the user
        Response response = RestAssured.given()
            .header("Authorization", "Bearer validToken")
            .get("http://yourapp.com/api/v1/users/validUser");

        // Assert the API response status and body
        Assert.assertEquals(response.statusCode(), 200);
        Assert.assertTrue(response.body().asString().contains("validUser"));

        driver.quit();
    }
}

Sad Path:

import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.Assert;
import io.restassured.RestAssured;
import io.restassured.response.Response;

public class CombinedUITest {
    public static void main(String[] args) {
        // Set up WebDriver and open the login page
        WebDriver driver = new ChromeDriver();
        driver.get("http://yourapp.com/login");

        // Enter invalid credentials in the login form
        driver.findElement(By.id("username")).sendKeys("invalidUser");
        driver.findElement(By.id("password")).sendKeys("invalidPassword");
        driver.findElement(By.id("loginButton")).click();

        // Verify the error message in the UI
        Assert.assertTrue(driver.findElement(By.id("errorMessage")).getText().contains("Invalid credentials"));

        // API Request to verify failed login
        Response response = RestAssured.given()
            .get("http://yourapp.com/api/v1/users/invalidUser");

        // Assert that the API returns 404 error
        Assert.assertEquals(response.statusCode(), 404);
        
        driver.quit();
    }
}

2. Automated Combined UI and API Testing with Cypress

Cypress allows easy interaction with both the UI and API. Here’s an example using Cypress.

Happy Path:

describe('Login UI + API Test', () => {
    it('should log in and verify the user via API', () => {
        // Visit the login page
        cy.visit('http://yourapp.com/login');
        
        // Interact with the login form
        cy.get('#username').type('validUser');
        cy.get('#password').type('validPassword');
        cy.get('#loginButton').click();
        
        // Verify UI navigates to home page
        cy.url().should('include', '/home');
        
        // API Request to verify the user
        cy.request({
            method: 'GET',
            url: 'http://yourapp.com/api/v1/users/validUser',
            headers: {
                'Authorization': 'Bearer validToken'
            }
        }).then((response) => {
            expect(response.status).to.eq(200);
            expect(response.body).to.include({ username: 'validUser' });
        });
    });
});

Sad Path:

describe('Login UI + API Test', () => {
    it('should show error on invalid credentials and verify via API', () => {
        // Visit the login page
        cy.visit('http://yourapp.com/login');
        
        // Interact with the login form
        cy.get('#username').type('invalidUser');
        cy.get('#password').type('invalidPassword');
        cy.get('#loginButton').click();
        
        // Verify UI displays error message
        cy.get('#errorMessage').should('contain.text', 'Invalid credentials');
        
        // API Request to verify failed login
        cy.request({
            method: 'GET',
            url: 'http://yourapp.com/api/v1/users/invalidUser',
            failOnStatusCode: false  // to prevent Cypress from failing the test on 404
        }).then((response) => {
            expect(response.status).to.eq(404);
        });
    });
});

3. Automated Combined UI and API Testing with Playwright

Playwright offers robust support for API calls in addition to UI tests.

Happy Path:

const { chromium } = require('playwright');
const fetch = require('node-fetch');

(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();

    // Visit the login page
    await page.goto('http://yourapp.com/login');

    // Fill the login form
    await page.fill('#username', 'validUser');
    await page.fill('#password', 'validPassword');
    await page.click('#loginButton');

    // Verify the UI navigates to the homepage
    await page.waitForSelector('text=Welcome Home');
    
    // API Request to verify the user
    const response = await fetch('http://yourapp.com/api/v1/users/validUser', {
        headers: { 'Authorization': 'Bearer validToken' }
    });
    const body = await response.json();
    console.log(body);
    console.assert(response.status === 200, 'Expected status code 200');
    console.assert(body.username === 'validUser', 'Expected user to be validUser');

    await browser.close();
})();

Sad Path:

const { chromium } = require('playwright');
const fetch = require('node-fetch');

(async () => {
    const browser = await chromium.launch();
    const page = await browser.newPage();

    // Visit the login page
    await page.goto('http://yourapp.com/login');

    // Fill the login form with invalid credentials
    await page.fill('#username', 'invalidUser');
    await page.fill('#password', 'invalidPassword');
    await page.click('#loginButton');

    // Verify the error message on the UI
    const errorMessage = await page.textContent('#errorMessage');
    console.assert(errorMessage.includes('Invalid credentials'), 'Expected error message for invalid login');
    
    // API Request to verify failed login
    const response = await fetch('http://yourapp.com/api/v1/users/invalidUser');
    console.assert(response.status === 404, 'Expected status code 404');

    await browser.close();
})();

Conclusion By integrating both UI and API testing (manual and automated) with proper handling of happy and sad paths, you can ensure a seamless user experience, reliable backend functionality, and a robust, well-tested application.

To know how I expanded the happy and sad paths for greater testing coverage check this post out: The Happy and Sad Path: Key Concepts in QA Testing.

Leave a Reply