The other day, a friend messaged me, a bit stuck on a Playwright test:
“I’m trying to add all 3 products to the cart, but only 2 are getting added, and then it crashes! 🤯”
“I’m trying to add all 3 products to the cart, but only 2 are getting added, and then it crashes! 🤯”
I couldn’t resist helping out and it turned into a fun little debugging adventure. Let me share how we cracked it!
🌟 The Scenario
It was a practice website with exactly 3 products. My friend’s mission:
👉 Log in
👉 Add all 3 items to the cart
👉 Validate that everything worked smoothly.
👉 Add all 3 items to the cart
👉 Validate that everything worked smoothly.
🐛 The Initial Problem
Here’s what he was using at first:
const addToCartButtons = page.locator('button:has-text("Add to Cart")');for (let i = 0; i < 3; i++) {await addToCartButtons.nth(i).click();}
But… it would only add 2 items and then fail with a timeout error!
Turns out, Playwright was trying to click a button that no longer existed after the page updated.
🔍 What Was Happening?
When you click “Add to Cart” on a product, the page dynamically removes that product from the list. But the for loop was working with the original static list of buttons — which quickly became outdated.Turns out, Playwright was trying to click a button that no longer existed after the page updated.
💡 The Fix: Fresh Searches with a while Loop
I explained to my friend:Dynamic pages require dynamic approaches! Instead of relying on a stale list, let’s search fresh for the button each time we want to click.
Here’s what we changed it to:
let added = 0;while (added < 3) {await page.locator('button:has-text("Add to Cart")').first().click({ force: true });added++;}
✅ Why the while Loop Worked
🔹 Fresh search every timePlaywright looked at the page as it was in that moment, clicking the first visible “Add to Cart” button each time.
🔹 No stale references
No more “clicking” on buttons that had been removed.
🔹 Perfect for dynamic UIs
This makes it robust for dynamic sites where the UI updates after each interaction.
🎉 The Win!
With this simple tweak, we got the script working perfectly:✅ All 3 products added!
✅ No timeouts!
✅ And a happy friend! 😁
💻 Here’s the Full Working Script
const { test, expect } = require('@playwright/test');
test('Add 3 items to cart using while loop', async ({ page }) => { await page.goto("https://freelance-learn-automation.vercel.app/login");
// Login await page.getByPlaceholder('Enter Email').fill('example@example.com'); await page.getByPlaceholder('Enter Password').fill('example'); await page.getByRole('button', { name: 'Sign in' }).click();
// Wait for page to load await page.waitForLoadState('networkidle'); await expect(page).toHaveURL("https://freelance-learn-automation.vercel.app/");
// Wait for products to load await page.locator('button:has-text("Add to Cart")').first().waitFor({ state: 'visible' });
let added = 0;
while (added < 3) { await page.locator('button:has-text("Add to Cart")').first().click({ force: true }); added++; }
console.log(`Added ${added} items to the cart.`);
// Check that the number of items in the cart is 3 await page.locator('span.count').waitFor({ state: 'visible' }); const countText = await page.locator('span.count').textContent(); console.log("the count is " + countText); const count = parseInt(countText.trim(), 10); expect(count).toBe(3);
//Go to cart await page.locator('.cartBtn').click(); await expect(page).toHaveURL('https://freelance-learn-automation.vercel.app/cart'); await page.locator('button:has-text("Enroll Now")').click(); await page.locator('textarea#address').fill('Bingley'); await page.locator('input#phone').fill('0123456789'); await page.locator('button.action-btn').last().click(); //capture the text const text = await page.locator('h4.uniqueId').textContent(); console.log(text);
// Assert that the uniqueId is not empty expect(text).toBeTruthy();
//Click on cancel button await page.locator('button.action-btn.white-action-btn', { hasText: 'Cancel' }).click();
});
const { test, expect } = require('@playwright/test');
test('Add 3 items to cart using while loop', async ({ page }) => {
await page.goto("https://freelance-learn-automation.vercel.app/login");
// Login
await page.getByPlaceholder('Enter Email').fill('example@example.com');
await page.getByPlaceholder('Enter Password').fill('example');
await page.getByRole('button', { name: 'Sign in' }).click();
// Wait for page to load
await page.waitForLoadState('networkidle');
await expect(page).toHaveURL("https://freelance-learn-automation.vercel.app/");
// Wait for products to load
await page.locator('button:has-text("Add to Cart")').first().waitFor({ state: 'visible' });
let added = 0;
while (added < 3) {
await page.locator('button:has-text("Add to Cart")').first().click({ force: true });
added++;
}
console.log(`Added ${added} items to the cart.`);
// Check that the number of items in the cart is 3
await page.locator('span.count').waitFor({ state: 'visible' });
const countText = await page.locator('span.count').textContent();
console.log("the count is " + countText);
const count = parseInt(countText.trim(), 10);
expect(count).toBe(3);
//Go to cart
await page.locator('.cartBtn').click();
await expect(page).toHaveURL('https://freelance-learn-automation.vercel.app/cart');
await page.locator('button:has-text("Enroll Now")').click();
await page.locator('textarea#address').fill('Bingley');
await page.locator('input#phone').fill('0123456789');
await page.locator('button.action-btn').last().click();
//capture the text
const text = await page.locator('h4.uniqueId').textContent();
console.log(text);
// Assert that the uniqueId is not empty
expect(text).toBeTruthy();
//Click on cancel button
await page.locator('button.action-btn.white-action-btn', { hasText: 'Cancel' }).click();
});
Final Takeaways
✅ Dynamic pages? Dynamic tests!
✅ Always think about how the DOM changes after each action.
✅ And don’t be afraid to swap out a for loop for a fresh approach like while!
✅ Always think about how the DOM changes after each action.
✅ And don’t be afraid to swap out a for loop for a fresh approach like while!
Have you faced similar challenges testing dynamic pages?
Drop a comment below and let’s chat about it — I’d love to hear your tips and tricks!
Drop a comment below and let’s chat about it — I’d love to hear your tips and tricks!
Comments
Post a Comment