Automatic waiting (autowait) to common Selenium Interactions in Python

By obrizan on August 14, 2026

Anyone who has written Selenium tests has encountered the same frustrating problem: the test tries to interact with an element a fraction of a second before the page is ready.

The button may already exist but not yet be clickable. An input may appear only after JavaScript finishes updating the page. A test that passes locally may fail in CI because the application responds a little more slowly. These small timing differences are among the most common causes of flaky browser tests — and they waste valuable time. Instead of working on new tests or fixing real defects, engineers can spend hours reproducing failures, studying logs, and rerunning pipelines only to discover that the application simply needed another fraction of a second.

Selenium provides explicit waits to solve this problem, but they add repetitive synchronization code to tests. A simple interaction can quickly become much more verbose:

button = WebDriverWait(driver, 10).until(
    expected_conditions.element_to_be_clickable((By.ID, "submit"))
)
button.click()

The wait is necessary, but it distracts from what the test is actually trying to express: find the submit button and click it.

I created selenium-autowait to make these common interactions simpler. Once enabled, it automatically waits when Selenium finds an element, clicks it, types into it, or clears it. The test can remain focused on user behavior:

driver.find_element(By.ID, "submit").click()

The waiting still happens—it is simply handled consistently behind the scenes.

Motivation

My main motivation was to reduce the amount of synchronization code required in everyday Selenium tests without falling back to fixed delays.

Using time.sleep() may appear to solve timing problems, but it introduces a difficult trade-off. If the delay is too short, the test remains unreliable. If it is too long, every run wastes time even when the application is already ready. As a test suite grows, these delays accumulate and make the entire suite slower.

I have also seen engineers respond to flaky tests by adding WebDriverWait calls or even time.sleep() almost everywhere. This can hide the underlying synchronization problem while making the test suite several times slower. A single unnecessary delay may seem harmless, but repeated across hundreds of interactions and test cases, these waits can turn a fast feedback loop into a long-running pipeline.

Explicit waits are a much better solution because they stop as soon as the required condition is satisfied. However, writing the same wait around every routine interaction creates another problem: test code becomes dominated by implementation details.

I wanted the most common Selenium operations to wait for the conditions they naturally require:

  • Finding an element should wait until the element exists.
  • Clicking an element should wait until it is clickable.
  • Typing into or clearing an element should also wait until it can be interacted with.

That is the idea behind selenium-autowait. It adds automatic waiting to familiar Selenium methods rather than introducing a new browser API or requiring tests to use a custom page-object hierarchy.

My goal is not to eliminate explicit waits. Complex interfaces will always have application-specific states that a general-purpose library cannot infer. Instead, selenium-autowait handles the repetitive cases so that explicit waits can be reserved for conditions that actually deserve explicit attention.

The result I am aiming for is straightforward: tests that are less repetitive, easier to read, and more resilient to ordinary timing differences between the browser and the application.

Try it out and get involved

If this approach sounds useful, I encourage you to try selenium-autowait in your own test suite (see docs below). It is designed to be lightweight and easy to integrate into existing Selenium projects.

You can find the project here: https://github.com/obrizan/selenium-autowait

If you do try it, your feedback would be extremely valuable. Issues, suggestions, and real-world usage reports help improve the library and shape its future development.

And if you find it helpful, please consider giving it a ⭐ on GitHub. It really helps others discover the project and supports continued development.

Installation

Install the base package from PyPI:

pip install selenium-autowait

Or with uv:

uv add selenium-autowait

The base package requires Python 3.11 or newer and depends on Selenium. Pytest support is optional.

To use the bundled pytest fixture, install the pytest extra:

pip install "selenium-autowait[pytest]"

Or with uv:

uv add "selenium-autowait[pytest]"

Usage

Autowait works by globally monkey-patching Seleniumʼs WebDriver and WebElement classes. Enable it before the Selenium interactions that should wait automatically, and disable it when that behavior is no longer needed.

The default timeout is 10.0 seconds. To change it, pass timeout when enabling autowait:

from selenium_autowait import enable_autowait


enable_autowait(timeout=5.0)

Plain Python

Enable autowait before interacting with Selenium elements:

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium_autowait import disable_autowait, enable_autowait


driver = webdriver.Chrome()
enable_autowait()

driver.get("https://example.com")
button = driver.find_element(By.ID, "submit")

# Will wait until the button is clickable.
button.click()
disable_autowait()
driver.quit()

unittest

Enable autowait once for the test class in setUpClass, then disable it in tearDownClass:

import unittest

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver
from selenium_autowait import disable_autowait, enable_autowait


class SubmitTests(unittest.TestCase):
    driver: WebDriver

    @classmethod
    def setUpClass(cls) -> None:
        enable_autowait()
        cls.driver = webdriver.Chrome()

    @classmethod
    def tearDownClass(cls) -> None:
        cls.driver.quit()
        disable_autowait()

    def test_submit(self) -> None:
        self.driver.get("https://example.com")
        self.driver.find_element(By.ID, "submit").click()

pytest

If installed with the pytest extra, the package exposes an autowait fixture through pytestʼs plugin entry point. Use the fixture in tests that should wait automatically:

from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webdriver import WebDriver


def test_submit(driver: WebDriver, autowait: None) -> None:
    driver.get("https://example.com")
    driver.find_element(By.ID, "submit").click()

You can also define the fixture yourself if you prefer local control:

from collections.abc import Generator

import pytest

from selenium_autowait import disable_autowait, enable_autowait


@pytest.fixture
def autowait() -> Generator[None, None, None]:
    enable_autowait(timeout=10.0)
    yield
    disable_autowait()

To enable autowait once for the whole pytest session, define a session-scoped fixture in conftest.py:

from collections.abc import Generator

import pytest

from selenium_autowait import disable_autowait, enable_autowait


@pytest.fixture(scope="session", autouse=True)
def autowait_session() -> Generator[None, None, None]:
    enable_autowait(timeout=10.0)
    yield
    disable_autowait()

Analyze test results with Testinel

selenium-autowait helps reduce flaky Selenium failures caused by elements that are not ready yet. When failures still happen, Testinel can help you understand them faster.

Testinel is a web-based analytics platform for automated testing. It turns test runs, logs, and failures into actionable reports, helping teams identify recurring root causes, review historical stability trends, and navigate from high-level test health to exact failing tests and logs.

Testinel supports Python, pytest, Selenium, and Playwright-based test workflows.

Telegram
LinkedIn
Reddit
Viber
WhatsApp
← Back to blog