Correcting Wrong ‘Playwright’s Advantage over Selenium” Part 3: “Playwright has Native Auto-Waiting Mechanism”
A wrong approach that brings confusion.

Let’s continue to correct the third wrong claim in this YouTube video, “Playwright vs Selenium: What Advantages Make Playwright the Winner in Automation Testing Battle 🏆”.
This article series:
- “Playwright is Modern and Faster than Selenium” 😒
- “Playwright has Parallel Execution Support” 👎🏽
- “Playwright has Native Auto-Waiting Mechanism” 👎🏽
- “Playwright has a native test runner” 👎🏽 (coming soon)
- “Playwright has native HTML Reporters” 👎🏽
- “Playwright Features Can be Configured in one Configuration” 👎🏽
- “Playwright supports a range of Testing Types, e.g. API Testing, Component Testing, …” 👎🏽
- “Playwright ARIA locator support” 👎🏽
- “Playwright UI Mode, CodeGen, Debugging support.” 👎🏽
Table of Contents: · Claim 3. “Playwright has Native Auto-Waiting Mechanism” · Playwright waiting is generally applied · My Selenium Test Script for the Payment Test · FAQ
Claim 3. “Playwright has Native Auto-Waiting Mechanism”

This so-called “Auto-Waiting” is no good, as it can cause confusion unnecessarily. Remind you that Cypress has a similar thing, and its marketing team sang for it for quite some time. Did it actually win over Selenium? No, Cypress.io is dying.
“Auto-Waiting” is more like a marketing term (not sure invented by whom? Maybe Cypress marketing team?). It is, in fact, a kind of fake auto-waiting. I have written three articles on this topic:
- Playwright’s Auto-Waiting is Wrong
- Waiting Strategies for Test Steps in Web Test Automation (Medium’s curators recommended this as a ‘Boosted’)
- Auto-Waiting in Web Test Automation Clarified
The above explained, from a technical perspective,
- why ‘auto-waiting’ is unnecessary and causes problems
- Selenium WebDriver waiting is sufficient, maybe a bit verbose
- A simple solution to overcome that minor ‘verbose’ issue.
In this article, I will clarify from a manual testing (or end-user) perspective. After all, Web test automation is a form of end-user testing.

It is better illustrated with an example. Assume a manual tester (or business analyst or end-user) is about to test a credit card payment page on a dynamic site (i.e. with AJAX).

There are 7 steps in his test design (the happy path):
- Select the card type: Visa or Master
- Enter the holder's name
- Enter card number
- Select expiry month
- Select expiry year
- Click the ‘Pay Now’ button
- Verify the payment success (i.e. checking receipt number)
The ‘Pay now’ is an AJAX operation, i.e., the payment result (needed for Step 7) is not returned immediately. Now, consider the waiting requirement in the test design.
Steps 1–5: No waiting is required at all.
Step 6: Need to wait after performing the step.
Step 7: Wait! (some testers will write the maximum waiting time is allowed)
See, only one step requires waiting.
A Test Automation Engineer’s job is to convert the above test design into reliable test automation scripts.
Playwright waiting is generally applied
In the Playwright configuration file, playwright.config.ts , there is an entry timeouts . (see Playwright official doc)
// Maximum time expect() should wait for the condition to be met.
timeout: 5000,Because this is generally applied, it is wrong. Why? See the test design.
Some Playwright fans might argue, “Even so, because test execution is fast, checking every condition is OK”. I disagree; it deviated from the thinking of end-user testing. Furthermore, that approach brings side effects (see my articles listed earlier).
What would you say if I conformed to the original test design (wait once) and the test scripts ran super reliably with little effort?
My Selenium Test Script for the Payment Test
The payment test script below is in raw Selenium WebDriver + RSpec.
it "[5] Book flight with payment" do
# ... navigate to the payment page
payment_page = PaymentPage.new(driver)
payment_page.select_card_type("master")
payment_page.enter_holder_name("Bob the Tester")
payment_page.enter_card_number("4242424242424242")
payment_page.enter_expiry_month("04")
payment_page.enter_expiry_year("2024")
payment_page.click_pay_now
# wait up to 6 seconds for the booking number
try_for(6) { expect(driver.page_source).to include("Booking number")}
puts("booking number: " + driver.find_element(:id, 'booking_number').text)
endThe try_for is a function I created using Ruby Block.





