Rayrun
← Back to Discord Forum

Modifying network requests and saving to HAR

I am setting up our testing on Playwright. The idea is to only test behaviour of the front-end with given HTTP responses, so I'm saving HTTP requests to a HAR file on first run and then routing everything from a file on successive test runs.

I read from documentation (https://playwright.dev/docs/mock#replaying-from-har) that

HAR replay matches URL and HTTP method strictly. For POST requests, it also matches POST payloads strictly. If multiple recordings match a request, the one with the most matching headers is picked.

So I want to make sure that calls to the same resource (i.e. get collection) are matched to the correct responses (for example if one is done before and one after making a modification to a resource.

My thought was to append a unique header to each request.

But looking at the resulting HAR file, the new header is not added to any requests. What am I doing wrong? Here's the full code to the fixture I'm using:

This thread is trying to answer question "Why is the new header not added to any requests in the resulting HAR file when testing on Playwright?"

1 reply
import { test as base } from '@playwright/test';
import { existsSync } from 'fs';

import getTestFileName from './getTestFileName';
import sanitizeHar from './sanitizeHar';

const apiUrlsGlob = '**/api/portal/**';

/**
 * Overwrites the default `page` fixture with our custom one that checks for the existence of a HAR file in a given location
 * If that file exists, it's used to mock HTTP requests during the test
 * If it doesn't exist, new browser context is created that records network activity into a new HAR file
 */
export const test = base.extend({
  page: async ({ page, browser, browserName }, use, testInfo) => {
    /**
     * Assign a unique header to each request so that they're matched to their mocks in HAR files in the correct order
     */
    let requestIndex = 1;
    await page.route(apiUrlsGlob, async (route) => {
      route.continue({
        headers: {
          ...route.request().headers(),
          'Playwright-Request-Index': (requestIndex++).toString(),
        },
      });
    });

    const harFilePath = getTestFileName(testInfo.title, browserName);
    console.debug(`Checking HAR file at: ${harFilePath}`);

    if (existsSync(harFilePath)) {
      console.debug('HAR file found, using it for the test');
      await page.routeFromHAR(harFilePath, {
        notFound: 'abort',
        url: apiUrlsGlob,
      });

      await use(page);
    } else {
      console.debug(
        'HAR file not found, running test without it and recording answers to a new HAR file'
      );
      const browserContext = await browser.newContext({
        recordHar: {
          path: harFilePath,
          mode: 'minimal',
          urlFilter: apiUrlsGlob,
        },
      });
      const page = await browserContext.newPage();

      // Run the test
      await use(page);

      await browserContext.close();

      await sanitizeHar(harFilePath);
    }
  },
});

Related Discord Threads

TwitterGitHubLinkedIn
AboutQuestionsDiscord ForumBrowser ExtensionTagsQA Jobs

Rayrun is a community for QA engineers. I am constantly looking for new ways to add value to people learning Playwright and other browser automation frameworks. If you have feedback, email luc@ray.run.