Rayrun
← Back to Discord Forum

route.fulfill within a page.route becomes onSuccess only after expect

I have written a parameterized test to validate my React contexts. I have two contexts, 1️⃣ for a list of tenants provided via a fetch of a json file, 2️⃣ for a list of feature flags per tenant.

In my test, I mock the returned data by providing it through the following instructions :

await page.route("**/tenants.json", route => route.fulfill({ json: tenants });
await page.route("**/featureFlags.json", route => route.fulfill({ json: featureFlags });

Unfortunately, my test always fails due to timeout:

1) [chromium] › App.test.ts:14:3 › App should have the howTo section ─────────────────────────────

    Error: Timed out 5000ms waiting for expect(received).toHaveCount(expected) // deep equality

    Expected: 1
    Received: 0
    Call log:
      - expect.toHaveCount with timeout 5000ms
      - waiting for getByTestId('howTo__container')
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"
      -   locator resolved to 0 elements
      -   unexpected value "0"


      24 |
      25 |     const section = page.getByTestId(`${sectionName}__container`);
    > 26 |     await expect(section).toHaveCount(1);
         |                           ^
      27 |   });
      28 |
      29 |   test(`App should not have the ${sectionName} section`, async ({ page }) => {

        at H:\git\makemesweat\frontend\tests\e2e\App.test.ts:26:27

line.js:78
  1 failed
    [chromium] › App.test.ts:14:3 › App should have the howTo section
image.png
image.png
image.png
image.png
image.png

This thread is trying to answer question "Why does the test always fail due to timeout when mocking returned data?"

4 replies

I have tried to :

  • add a waitFor on the locator but it never passes it, always waiting for it.
  • increase the timeout and the expect’s timeout but it does not change the outcome
  • put every page.route result into a Promise.all but same issue at the end

The routes are always not fulfilled in time or wrongly

image.png
image.png

The code : ```ts const sections = ['howTo', 'aboutMe', 'showcase']; for (const sectionName of sections) { test(App should have the ${sectionName} section, async ({ page }) => { const tenant: Tenant = 'makemesweat'; const tenants: Tenant[] = [tenant]; const featureFlags: Partial<TenantsFlags> = { [tenant]: { [sectionName]: true } }; await page.route('/tenants.json', route => route.fulfill({ status: 200, json: tenants })); await page.route('/featuresFlags.json', route => route.fulfill({ status: 200, json: featureFlags }));

await page.goto(homePageURL);

const section = page.getByTestId(`${sectionName}__container`);
await expect(section).toHaveCount(1);

}); }

Isn't

page.getByTestId(`${sectionName}__container`)

should be

page.locator(`.${sectionName}__container`)

instead?

Answer

Handling Test Failures in @playwright/test

Test failures when mocking returned data using page.route and route.fulfill in @playwright/test can be due to a few reasons.

Timeout Issues

One common reason is that the operation is taking longer than the maximum operation time set. By default, this value is set to 0, which means no timeout. If your operation exceeds this limit, it will result in a test failure.

// Set the default navigation timeout
browserContext.setDefaultNavigationTimeout(5000);

You can adjust the timeout settings using methods like setDefaultNavigationTimeout() or setDefaultTimeout().

Event Completion

Another reason could be related to when you consider an operation succeeded. The 'waitUntil' option allows you to specify when an operation should be considered successful. It defaults to 'load', but there are other options available such as 'domcontentloaded', 'networkidle', and 'commit'.

// Wait until the DOM is fully loaded
page.goto('https://ray.run', { waitUntil: 'domcontentloaded' });

Mocking Responses

Lastly, while mocking responses with route.fulfill(), ensure the response object passed has all necessary fields filled correctly, especially the status code which defaults to 200.

// Mock a response
await page.route('https://ray.run/api/data', route => route.fulfill({
  status: 200,
  body: JSON.stringify({ key: 'value' })
}));

Remember to set an appropriate timeout limit and carefully choose what event should signify successful completion of an operation. For more tips on handling flaky tests in Playwright, check out this blog post.

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.