This episode covers minimizing flaky tests with reliable selectors, retry strategies and flaky test detection, monitoring execution stability, and best practices for keeping an automation suite stable in the long term.

Nothing drains a team's trust in automation faster than flaky tests — tests that sometimes pass and sometimes fail with no changes at all. A team constantly haunted by random failures starts ignoring CI results, and the suite loses its entire value. Episode 13 covers eradicating flakiness at its root.
We'll dissect the sources of flakiness, build reliable selectors, apply proper retry and flaky detection, and monitor suite stability as a metric guarded like any other.
Before fixing, know the causes. The five most common sources of flakiness in Selenium automation:
timing -> selector -> shared state -> environment -> test ordertiming -> selector -> shared state -> environment -> test order is the recommended checking order: inspect the most frequent causes first.
Selector quality determines most of a suite's stability. These are the rules we apply in every project:
div[2] that are brittle to structure changes.# Strong: test-specific attribute
driver.find_element("css selector", "[data-testid='tombol-beli']")
# Weak: position and generic classes
driver.find_element("css selector", "div.wrapper > div:nth-child(2) > button.btn")The [data-testid='tombol-beli'] pattern is far more stable than div.wrapper > div:nth-child(2) > button.btn. If the product team is willing to add data-testid, that investment pays off many times over in suite stability.
The same selector for the same element should be used in all tests. This isn't just tidiness — it prevents two tests from referencing the same element in two different ways, so one layout change only breaks a single point.
Retry isn't a permanent solution, but it can save the pipeline while the root cause is hunted. The pytest-rerunfailures plugin provides per-test retries:
pip install pytest-rerunfailuresAfter pip install pytest-rerunfailures, mark tests that need retries:
@pytest.mark.flaky(reruns=2, reruns_delay=1)
def test_checkout():
...@pytest.mark.flaky(reruns=2, reruns_delay=1) retries the test up to twice with a one-second pause. Important: every test needing a retry must have a fix ticket — retry without investigation only hides the problem.
The most effective way to detect flakiness: run the test repeatedly and watch for occasional failures:
pytest tests/test_checkout.py -n 4 --count 3pytest tests/test_checkout.py -n 4 --count 3 (with the pytest-repeat plugin) runs the test many times. Tests that occasionally fail are flaky candidates that must be investigated before they pollute the suite.
Stability is a measurable metric. Track three numbers on every CI run:
Store these numbers in reports or a simple dashboard. The threshold we recommend: pass rate above 99% and flaky rate near zero — when it slips, the team's priority is stabilization, not adding new tests.
A summary of habits that keep a suite stable long-term:
@pytest.fixture
def data_test():
pengguna = buat_pengguna_unik()
yield pengguna
hapus_pengguna(pengguna.id)buat_pengguna_unik() guarantees every test has its own data. This create-use-delete pattern prevents the data collisions that breed flakiness.
Tip
Set a cultural rule: tests detected as flaky must be fixed or temporarily skipped with an open ticket within one week. Without this rule, flaky tests pile up silently.
Episode 13 changes how teams view flaky tests: not random noise to tolerate, but bugs to hunt. You can now recognize the five sources of flakiness, build reliable data-testid-based selectors, apply retry as a temporary net, and monitor pass rate as a team metric.
Key takeaways:
In episode 14 next, we'll cover cross-browser testing strategies — running tests in Chrome, Firefox, Edge, and Safari, compatibility testing patterns, managing browser-specific quirks, and using cloud browser farms like BrowserStack and Sauce Labs.