Testing with API Mocking

Understanding API Mocking

In the last lesson, we tested the login form using a real test user account. That worked because logging in doesn’t change anything in the database.

But registration is different - it creates new users in the database. This means:

  • We can’t use real API calls in our tests
  • Each test would create a new user
  • The database would quickly fill up with test users
  • Tests would fail when trying to register the same email twice

This is where API mocking comes in. Instead of letting our test actually call the API, we:

  • Intercept the request before it reaches the API
  • Send back a fake response that looks like the real API
  • Test how our app handles these responses

It’s like having a fake API that we control completely.

How Mocking Works in Playwright

javascript
	// This catches any request to our registration endpoint
	await page.route("*/**/holidaze/auth/register", (route) =>
	  // We send back a fake successful response
	  route.fulfill({
	    status: 200,
	    json: { name: "Test", email: "test@noroff.no" },
	  })
	);

When the registration form makes its API call:

  • Playwright catches it using the URL pattern
  • Instead of sending it to the real API it immediately returns our fake response

Complete Test Example

javascript
	import { test, expect } from "@playwright/test";
	
	test.describe("registration", () => {
	  test("successful registration shows success message", async ({ page }) => {
	    await page.route("*/**/holidaze/auth/register", (route) =>
	      route.fulfill({
	        status: 200,
	        json: { name: "Test", email: "test@noroff.no" },
	      })
	    );
	
	    // Go to register page
	    await page.goto("/auth/register");
	
	    // Fill the form
	    await page.locator('input[name="name"]').fill("Test User");
	    await page.locator('input[name="email"]').fill("success@stud.noroff.no");
	    await page.locator('input[name="password"]').fill("password123");
	
	    // Click register button
	    await page.getByRole("button", { name: "Register" }).click();
	
	    // Check for success message
	    await expect(page.locator("#message-container")).toContainText(
	      "Registration successful"
	    );
	  });
	
	  test("failed registration shows error message", async ({ page }) => {
	    await page.route("*/**/holidaze/auth/register", (route) =>
	      route.fulfill({
	        status: 400,
	        json: { message: "Registration failed" },
	      })
	    );
	    await page.goto("/auth/register");
	
	    // Fill the form with an email that will trigger a failure
	    await page.locator('input[name="name"]').fill("Test User");
	    await page.locator('input[name="email"]').fill("fail@stud.noroff.no");
	    await page.locator('input[name="password"]').fill("password123");
	
	    await page.getByRole("button", { name: "Register" }).click();
	
	    // Check for error message
	    await expect(page.locator("#message-container")).toContainText(
	      "Registration failed"
	    );
	  });
	});

Let’s break down what’s happening:

  1. Setting up the Mock Response:
javascript
	await page.route("*/**/holidaze/auth/register", (route) =>
	  route.fulfill({
	    status: 200,
	    json: { name: "Test", email: "test@noroff.no" },
	  })
	);
  • The URL pattern */**/holidaze/auth/register catches the API call your registration form makes
  • When the form submits, instead of going to the real API, Playwright catches it
  • route.fulfill() sends back a fake response immediately
  • We set status: 200 to simulate a successful API response
  1. Testing When Things Go Wrong:
javascript
	test("failed registration shows error message", async ({ page }) => {
	  await page.route("*/**/holidaze/auth/register", (route) =>
	    route.fulfill({
	      status: 400,
	      json: { message: "Registration failed" },
	    })
	  );
	
	  // Rest of the test...
	});
  • Uses the same URL pattern to catch the API call
  • This time we set status: 400 to simulate a failed registration

Why This Approach Works

  1. Reliability:

    • Tests don’t depend on API availability
    • No real users created
  2. Speed:

    • Mock responses are instant
    • No waiting for real API
    • Tests run faster
  3. Control:

    • We can easily test both success and error cases
    • Same results every time

Running the Tests

bash
	npx playwright test

What We Learned

In this lesson, we:

  • Learned why API mocking is needed for registration tests (to avoid creating real users)
  • Used page.route() to catch API calls and send back fake responses
  • Created tests for both successful and failed registration
  • Discovered how mocking makes tests faster and more reliable

Remember:

  • Test both success and error cases
  • Mock APIs when testing features that create or change data