{"id":79227,"date":"2025-04-29T11:07:54","date_gmt":"2025-04-29T05:37:54","guid":{"rendered":"https:\/\/www.guvi.in\/blog\/?p=79227"},"modified":"2025-09-03T16:02:09","modified_gmt":"2025-09-03T10:32:09","slug":"guide-to-python-selenium-fluent-waits","status":"publish","type":"post","link":"https:\/\/www.guvi.in\/blog\/guide-to-python-selenium-fluent-waits\/","title":{"rendered":"The Ultimate Guide to Python Selenium Fluent Waits"},"content":{"rendered":"\n<p>In web automation, Python Selenium is a powerful tool enabling developers to interact with web pages programmatically. However, the dynamic nature of modern web applications presents a significant challenge: elements often load asynchronously, rendering traditional, static waiting strategies unreliable. This is where Selenium&#8217;s FluentWait Shines, offering a flexible and robust solution to handle dynamic element loading and enhance the stability of your automated tests.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The Downfall of Using <code>time.sleep()<\/code>!<\/strong><\/h2>\n\n\n\n<p>Before diving into <code>FluentWait<\/code>, it is crucial to understand the limitations of simpler waiting methods. <code>time.sleep()<\/code> introduces arbitrary delays, making tests slow and inefficient. While implicitly_wait() sets a global timeout, it applies to all element searches, potentially leading to unnecessary delays or premature failures if elements load at varying speeds.<\/p>\n\n\n\n<p>The core issue lies in their static nature. These methods do not account for the dynamic behavior of web applications, whereas elements might appear, disappear, or change state at unpredictable times. Consequently, tests relying on these methods are prone to flakiness, failing intermittently due to timing issues.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Fluent Wait: A Symphony of Flexibility:<\/strong><\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-1200x630.png\" alt=\"Key components of Fluent Waits\" class=\"wp-image-80841\" srcset=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-1200x630.png 1200w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-300x158.png 300w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-768x403.png 768w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-1536x806.png 1536w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-2048x1075.png 2048w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/2@2x-3-150x79.png 150w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" title=\"\"><\/figure>\n\n\n\n<p>FluentWait, which is a part of Selenium&#8217;s webdriver. support.wait module addresses these shortcomings by providing a dynamic and customizable waiting mechanism. It allows you to define a condition to be repeatedly checked until it is met, along with a timeout and polling interval.<\/p>\n\n\n\n<p><strong>Key Components of Fluent Wait:<\/strong><\/p>\n\n\n\n<ol>\n<li><strong><code>WebDriverWait<\/code>: <\/strong>The primary class that orchestrates the waiting process. It takes the WebDriver instance and the maximum timeout as arguments.<br><\/li>\n\n\n\n<li><strong><code>until()<\/code> method:<\/strong> This method accepts a callable (a function or lambda expression) that defines the condition to be checked. This callable should return a truthy value when the condition is met.<br><\/li>\n\n\n\n<li><strong><code>Polling_frequency<\/code>:<\/strong> This parameter specifies the interval (in seconds) between consecutive checks of the condition.<br><\/li>\n\n\n\n<li><strong><code>Ignored_exceptions<\/code> <\/strong>This parameter allows you to specify exceptions that should be ignored during the waiting process. This is particularly useful for handling situations where elements might not be present initially or might throw temporary exceptions.<\/li>\n<\/ol>\n\n\n\n<p><em>Are you interested in starting a career in Python? Kickstart your Python journey using Guvi\u2019s FREE E-book on<\/em><a href=\"https:\/\/www.guvi.in\/mlp\/python-ebook?utm_source=blog&amp;utm_medium=hyperlink&amp;utm_campaign=The+Ultimate+Guide+to+Python+Selenium+Fluent+Waits\" target=\"_blank\" rel=\"noreferrer noopener\"><em> Python: A Beginner\u2019s Guide to Coding<\/em><\/a> and Beyond. It covers all the necessary concepts you need to know, starting from <a href=\"https:\/\/www.guvi.in\/hub\/python\/how-to-install-python-on-windows\/\" target=\"_blank\" rel=\"noreferrer noopener\">installing<em> Python<\/em><\/a><em> on your machine.<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>The Power of Custom Conditions:<\/strong><\/h2>\n\n\n\n<p>The true strength of <code>FluentWait<\/code> lies in its ability to handle custom conditions. You can create complex conditions tailored to your specific application&#8217;s behavior. For instance, you might want to wait until an element is visible, clickable, or contains specific text.<\/p>\n\n\n\n<p>Let us look at the code given below and try to understand the power of Fluent Wait.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code># main.py\n\n\nfrom selenium import webdriver\nfrom selenium.webdriver.common.by import By\nfrom selenium.webdriver.firefox.service import Service\nfrom webdriver_manager.firefox import GeckoDriverManager\nfrom selenium.webdriver.support.wait import WebDriverWait\nfrom selenium.webdriver.support import expected_conditions as EC\nfrom selenium.common.exceptions import *\n\n\n\n\nclass Suman_Fluent_Wait:\n    # Create a new instance of the Firefox driver\n    driver = webdriver.Firefox(service=Service(GeckoDriverManager().install()))\n\n\n    # Wait for the username field to be visible for up to 30 seconds, polling every 5 seconds\n    wait = WebDriverWait(driver, 10, poll_frequency=5, ignored_exceptions=&#91;NoSuchElementException, NoSuchDriverException])\n\n\n    def __init__(self, url, username, password):\n        self.url = url\n        self.username = username\n        self.password = password\n\n\n    # Navigate to OrangeHRM login page\n    def start(self):\n        self.driver.maximize_window()\n        self.driver.get(self.url)\n\n\n    def login(self):\n        try:\n            # Find the username field and enter the username\n            self.wait.until(EC.presence_of_element_located((By.NAME, \"username\"))).send_keys(self.username)\n\n\n            # Find the password field and enter the password\n            self.wait.until(EC.presence_of_element_located((By.NAME, \"password\"))).send_keys(self.password)\n\n\n            # Find the login button and click it\n            self.wait.until(EC.presence_of_element_located((By.XPATH, \"\/\/div&#91;@class='oxd-form-actions orangehrm-login-action']\/button\"))).click()\n        except:\n            print(\"Error\")\n        finally:\n            self.driver.quit()\n\n\n\n\nif __name__ == '__main__':\n    url = \"https:\/\/opensource-demo.orangehrmlive.com\/web\/index.php\/auth\/login\"\n    username = \"Admin\"\n    password = \"admin123\"\n    suman = Suman_Fluent_Wait(url, username, password)\n    suman.start()\n    suman.login()\n<\/code><\/pre>\n\n\n\n<p>The code automates logging into the <code>OrangeHRM<\/code> demo site (<a href=\"https:\/\/opensource-demo.orangehrmlive.com\/web\/index.php\/auth\/login\" target=\"_blank\" rel=\"noreferrer noopener nofollow\">https:\/\/opensource-demo.orangehrmlive.com\/web\/index.php\/auth\/login<\/a>) using the Firefox browser. It uses <a href=\"https:\/\/www.guvi.in\/blog\/python-selenium-page-object-model-explained\/\" target=\"_blank\" rel=\"noreferrer noopener\">Python Selenium<\/a> WebDriver with explicit waits to interact with the webpage reliably, entering a username and password, clicking the login button, and then closing the browser.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><strong>Imports<\/strong><\/h3>\n\n\n\n<h4 class=\"wp-block-heading\">The code begins with several imports from the Selenium library and related modules:<\/h4>\n\n\n\n<ul>\n<li><strong>from selenium import webdriver<\/strong>: Provides the WebDriver class to control the browser.<\/li>\n\n\n\n<li><strong>from selenium.webdriver.common.by import By<\/strong>: Allows specifying how to locate elements (e.g., by name or XPath).<\/li>\n\n\n\n<li><strong>from selenium.webdriver.firefox.service import Service<\/strong>: Manages the Firefox driver service.<\/li>\n\n\n\n<li><strong>from webdriver_manager.firefox import GeckoDriverManager<\/strong>: Automatically downloads and sets up the GeckoDriver for Firefox.<\/li>\n\n\n\n<li><strong>from selenium.webdriver.support.wait import WebDriverWait<\/strong>: Enables explicit waits to pause execution until conditions are met.<\/li>\n\n\n\n<li><strong>from selenium.webdriver.support import expected_conditions as EC<\/strong>: Provides conditions like &#8220;element is present&#8221; for waits.<\/li>\n\n\n\n<li><strong>from selenium.common.exceptions import *<\/strong>: Imports all Selenium exceptions (e.g., NoSuchElementException) for error handling.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>These imports set up the tools needed for browser automation.<\/strong><\/h4>\n\n\n\n<h3 class=\"wp-block-heading\">Class Definition: Suman_Fluent_Wait<\/h3>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>The code defines a class  <code>Suman_Fluent_Wait<\/code> to encapsulate the automation logic.<\/strong><\/h4>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>Class Variables<\/strong><\/h4>\n\n\n\n<ul>\n<li><strong>driver<\/strong>:\n<ul>\n<li>Initialized as <code>webdriver.Firefox(service=Service(GeckoDriverManager().install()))<\/code>.<\/li>\n\n\n\n<li>Creates a Firefox browser instance using GeckoDriver, which is automatically managed and installed by GeckoDriverManager.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>wait<\/strong>:\n<ul>\n<li>Initialized as <code>WebDriverWait(driver, 10, poll_frequency=5, ignored_exceptions=[NoSuchElementException, NoSuchDriverException])<\/code>.<\/li>\n\n\n\n<li>A &#8220;fluent wait&#8221; that:\n<ul>\n<li>Waits up to 10 seconds for a condition to be met.<\/li>\n\n\n\n<li>Checks every 5 seconds (polling frequency).<\/li>\n\n\n\n<li>Ignored <code>NoSuchElementException<\/code> (element not found) and <code>NoSuchDriverException<\/code> (driver unavailable) During the wait.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\"><strong>These are defined at the class level, meaning all instances share the same browser and wait object.<\/strong><\/h4>\n\n\n\n<h4 class=\"wp-block-heading\"><code>Constructor (__init__)<\/code><\/h4>\n\n\n\n<ul>\n<li><strong>Parameters<\/strong>: url, username, password.<\/li>\n\n\n\n<li><strong>Functionality<\/strong>: Stores these parameters as instance variables (self.url, self.username, self.password) for use in other methods.<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Method: start<\/h4>\n\n\n\n<ul>\n<li><strong>Purpose<\/strong>: Opens the browser and navigates to the login page.<\/li>\n\n\n\n<li><strong>Steps<\/strong>:\n<ul>\n<li><code>self.driver.maximize_window()<\/code>: Maximizes the browser window.<\/li>\n\n\n\n<li><code>self.driver.get(self.url)<\/code>: Loads the provided URL (OrangeHRM login page).<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Method: login<\/h4>\n\n\n\n<ul>\n<li><strong>Purpose<\/strong>: Performs the login actions on the webpage.<\/li>\n\n\n\n<li><strong>Steps<\/strong>:\n<ul>\n<li><strong>Username Field<\/strong>:\n<ul>\n<li><code>self.wait.until(EC.presence_of_element_located((By.NAME, \"username\"))).send_keys(self.username)<\/code><\/li>\n\n\n\n<li>Waits until the username field (identified by name=&#8221;username&#8221;) is present, then enters the username.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Password Field<\/strong>:\n<ul>\n<li><code>self.wait.until(EC.presence_of_element_located((By.NAME, \"password\"))).send_keys(self.password)<\/code><\/li>\n\n\n\n<li>Waits until the password field (identified by name=&#8221;password&#8221;) is present, then enters the password.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Login Button<\/strong>:\n<ul>\n<li><code>self.wait.until(EC.presence_of_element_located((By.XPATH, \"\/\/div[@class='oxd-form-actions orangehrm-login-action']\/button\"))).click()<\/code><\/li>\n\n\n\n<li>Waits until the login button (identified by an XPath) is present, then clicks it.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Error Handling<\/strong>:\n<ul>\n<li>Wrapped in a try-except block:\n<ul>\n<li>If any error occurs (e.g., element not found), it prints &#8220;Error&#8221;.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li>Finally block:\n<ul>\n<li><code>self.driver.quit()<\/code>: Closes the browser, ensuring resources are released even if an error occurs.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Variables:<\/h4>\n\n\n\n<ul>\n<li>url: The OrangeHRM login page URL.<\/li>\n\n\n\n<li>username: Set to &#8220;Admin&#8221; (default for the demo site).<\/li>\n\n\n\n<li>password: Set to &#8220;admin123&#8221; (default for the demo site).<\/li>\n<\/ul>\n\n\n\n<h4 class=\"wp-block-heading\">Execution:<\/h4>\n\n\n\n<ul>\n<li>Creates an instance of Suman_Fluent_Wait with the specified URL, username, and password.<\/li>\n\n\n\n<li>Calls <code>start()<\/code> to open the browser and navigate to the URL.<\/li>\n\n\n\n<li>Calls <code>login()<\/code> to perform the login actions.<\/li>\n<\/ul>\n\n\n\n<p>Want to learn more about Selenium in Python? Enroll in Guvi&#8217;s wonderful course on<a href=\"https:\/\/www.guvi.in\/courses\/software-testing-and-automation\/selenium-automation-with-python?utm_source=blog&amp;utm_medium=hyperlink&amp;utm_campaign=The+Ultimate+Guide+to+Python+Selenium+Explicit+Waits\" target=\"_blank\" rel=\"noreferrer noopener\"> Selenium Automation with Python<\/a>. This course covers everything you need to know about Selenium automation using Python from beginner to advanced level. You can gain hands-on experience with the guided projects along with an industry-recognized certification.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">How It Works<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"630\" src=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-1200x630.png\" alt=\"How Fluent Waits Works\" class=\"wp-image-80842\" srcset=\"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-1200x630.png 1200w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-300x158.png 300w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-768x403.png 768w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-1536x806.png 1536w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-2048x1075.png 2048w, https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/3@2x-150x79.png 150w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" title=\"\"><\/figure>\n\n\n\n<ol>\n<li><strong>Browser Setup<\/strong>:\n<ul>\n<li>The Firefox browser is launched using <code>GeckoDriver<\/code>, managed by <code>GeckoDriverManager<\/code>.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Navigation<\/strong>:\n<ul>\n<li>The start method opens the <code>OrangeHRM<\/code> Log in page and maximize the window.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Login Process<\/strong>:\n<ul>\n<li>The login method uses explicit waits to ensure elements (username field, password field, login button) are loaded before interacting with them.<\/li>\n\n\n\n<li>It enters &#8220;Admin&#8221; as the username, &#8220;admin123&#8221; as the password, and clicks the login button.<\/li>\n<\/ul>\n<\/li>\n\n\n\n<li><strong>Cleanup<\/strong>:\n<ul>\n<li>The browser closes after the login attempt, whether successful or not, due to the finally block.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n\n\n\n<h3 class=\"wp-block-heading\">Key Features<\/h3>\n\n\n\n<ul>\n<li><strong>Fluent Waits:<\/strong> The use of <code>WebDriverWait<\/code> a 10-second timeout and 5-second polling makes the script robust against delays in page loading.<br><\/li>\n\n\n\n<li><strong>Error Tolerance:<\/strong> Ignores specific exceptions during waits and includes basic error handling in the login method.<br><\/li>\n\n\n\n<li><strong>Modularity: <\/strong>Encapsulates the automation logic in a class, making it reusable with different URLs, usernames, or passwords.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>Fluent Wait, implemented via <code>WebDriverWait<\/code> In Python, Selenium is an indispensable tool for managing the unpredictability of web applications. Its ability to fine-tune waiting parameters \u2014 timeout, polling frequency, and exception handling empowers developers and testers to craft automation scripts that are both robust and efficient. Whether waiting for a button to enable, an element to appear, or a custom state to occur, Fluent Wait ensures interactions happen at the right moment. By incorporating Fluent Wait into your Python Selenium <a href=\"https:\/\/www.guvi.in\/blog\/automation-testing-project-ideas\/\" target=\"_blank\" rel=\"noreferrer noopener\">automation testing projects,<\/a> you can significantly enhance script reliability and performance, thus making it a best practice for tackling dynamic web content. For deeper exploration, the official Selenium documentation offers extensive guidance on waits and advanced automation techniques.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In web automation, Python Selenium is a powerful tool enabling developers to interact with web pages programmatically. However, the dynamic nature of modern web applications presents a significant challenge: elements often load asynchronously, rendering traditional, static waiting strategies unreliable. This is where Selenium&#8217;s FluentWait Shines, offering a flexible and robust solution to handle dynamic element [&hellip;]<\/p>\n","protected":false},"author":38,"featured_media":80840,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[717,40],"tags":[],"views":"3087","authorinfo":{"name":"Suman Gangopadhyay","url":"https:\/\/www.guvi.in\/blog\/author\/suman-gangopadhyay\/"},"thumbnailURL":"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/1-5-300x116.png","jetpack_featured_media_url":"https:\/\/www.guvi.in\/blog\/wp-content\/uploads\/2025\/06\/1-5.png","_links":{"self":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/79227"}],"collection":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/users\/38"}],"replies":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/comments?post=79227"}],"version-history":[{"count":7,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/79227\/revisions"}],"predecessor-version":[{"id":86292,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/posts\/79227\/revisions\/86292"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/media\/80840"}],"wp:attachment":[{"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/media?parent=79227"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/categories?post=79227"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.guvi.in\/blog\/wp-json\/wp\/v2\/tags?post=79227"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}