Why Thread.sleep makes tests flaky
A fixed sleep guesses how long the page will take. Guess too short and the element isn't ready yet — the test fails intermittently depending on network and machine load. That's flakiness. Guess too long and every run wastes those seconds, multiplied across hundreds of tests. There is no "right" fixed number because load time varies run to run.
How explicit waits fix it
An explicit wait polls for a condition (element present, clickable, visible) and continues the instant it's met, up to a timeout. It's both faster than a generous sleep and more reliable than a short one, because it adapts to the actual load time every run.
Selenium (Java)
Use WebDriverWait with ExpectedConditions. Avoid Thread.sleep and avoid mixing implicit and explicit waits, which can compound timeouts unpredictably.
Playwright
Playwright auto-waits for actionability before every action, so explicit waits are rarely needed; when they are, use page.waitForSelector or web-first assertions like expect(locator).toBeVisible().
Cypress
Cypress retries commands and assertions automatically. Prefer asserting on state (cy.get(...).should('be.visible')) over cy.wait(ms) with a fixed number.
Rule of thumb
Never wait for time — wait for a condition. If you're typing a millisecond count into a test, you're probably writing a future flake.