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.