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'] },
},
]
7
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:
- Ignore WebKit/IE if it’s not mandatory. Just kidding 🙂
- Write browser-specific code:
test("Example", async ({ browserName }) => {
if (browserName === "webkit") {
// Do something specific for WebKit
}
});
- 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.
- 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();
5