AppDeveloper
AppDeveloper

Reputation: 2210

Race Conditions in running tests across browsers

I came across a scenario where I'm getting race conditions even with workers = 1 if testing with multiple browsers.

Firefox and Chrome work fine but it's the WebKit that's failing/passing at random.

Consider a record to be inserted via a form following a delete. All 3 browsers will be inserting and deleting a record in sequence but I feel browsers (webkit is the one) are jumping ahead in parallel instead of in a sequence. username is the primary key.

await page.goto("http://localhost:4173/");

// insert
const random = Math.random();
await page.locator('input[id="first"]').fill('John');
await page.locator('input[id="last"]').fill('Doe');
await page.locator('input[id="username"]').fill('johndoe' + random);
await page.waitForFunction(() => {
    const button = document.querySelector('#form button.primary');
    return button && !button.disabled;
});
await page.locator('#form button.primary').click();

// delete
await page.getByText('johndoe' + random).click();
await page.locator('#list footer button[id="delete"]').click();

Consider if we remove the random part; then for all 3 browsers (maybe just webkit), this becomes a single shared record that they are racing to insert and delete.

If you assign a random number, then essentially each browser works to insert and delete it's own individual record, and the unit test passes reliably.

For the time being, I solved it using a random number joining with the username but I feel there has to be a better solution.

Playwright config

workers: process.env.CI ? 1 : undefined,
projects: [
    {
        name: 'chromium',
        use: { ...devices['Desktop Chrome'] },
    },
    {
        name: 'firefox',
        use: { ...devices['Desktop Firefox'] },
    },
    {
        name: 'webkit',
        use: { ...devices['Desktop Safari'] },
    },
]

Upvotes: 5

Views: 268

Answers (1)

unickq
unickq

Reputation: 3418

Welcome to the cross-browser test automation, this is how it works here ;)

At least for WebKit. Before it was much worse, with IE and specific driver for it.

What you can do:

  1. Ignore WebKit/IE if it's not mandatory. Just kidding :)
  2. Write browser-specific code:
test("Example", async ({ browserName }) => {
  if (browserName === "webkit") {
    // Do something specific for WebKit
  } 
});
  1. Use better locators as Playwright docs suggests, locate by role and following - https://playwright.dev/docs/locators . No xpath/css, as WebKit may fail for some reason there.
  2. Use native waiters and assertions https://playwright.dev/docs/test-assertions instead of waitForFunction.
await page.waitForFunction(() => {
    const button = document.querySelector('#form button.primary');
    return button && !button.disabled;
});
await page.locator('#form button.primary').click();

In your example, it's not needed. PW click ensures that the button exists and is enabled before the click - see https://playwright.dev/docs/api/class-locator#locator-click.

It is still not clear why you need random - but if you need browser unique value try user_${browserName}

await page.getByText(`johndoe_${browserName}`).click();

Upvotes: 5

Related Questions