skip to content

How would you remove a Selenium suite's session-wide implicit wait without silently breaking the tests that depend on it?

level: principalimportance: nice to knowfreq 31%

answer

  1. You cannot grep for the dependency
  2. Ask the session, do not trust the setup
  3. Two set sites, one of them a capability
  4. Flip a bounded slice, not the suite
  5. Each new not-found names its own line

basics

~20 s

Setting a suite-wide implicit wait to zero is an experiment, not a refactor: flip one bounded slice, run it repeatedly, and treat each new not-found failure as a test that was leaning on it. Replace those with explicit waits.

solid answer

~40 s

The dependence is invisible in source, so you surface it with runs rather than review. In Selenium 4 the value can arrive from two places — `driver.manage().timeouts().implicitlyWait(Duration)` mid-session, and the `timeouts` capability's `implicit` member written by `options.setImplicitWaitTimeout(Duration)` — so first assert what the live session actually holds using `getImplicitWaitTimeout()`. Then flip one package or tag to `Duration.ZERO` while the rest keeps the old value; the setting is per session, so both can coexist in one run and the blast radius stays bounded. Each new `NoSuchElementException` names the exact locator and line that was racing, and you replace it with a `WebDriverWait` on a condition that states the readiness signal. Finish by moving the zero into the shared factory, deleting both set sites, and keeping the assertion so it cannot drift back.

code

java · 22 lines
java
import java.time.Duration;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;

public final class RinkDriverFactory {

  private RinkDriverFactory() {}

  public static WebDriver create() {
    ChromeOptions options = new ChromeOptions();
    options.setImplicitWaitTimeout(Duration.ZERO);
    WebDriver driver = new ChromeDriver(options);
    driver.manage().timeouts().implicitlyWait(Duration.ZERO);
    Duration actual = driver.manage().timeouts().getImplicitWaitTimeout();
    if (!actual.isZero()) {
      driver.quit();
      throw new IllegalStateException("implicit wait is " + actual);
    }
    return driver;
  }
}

go deeper

for a junior

Know that a suite-wide implicit wait is usually one line in a shared driver factory, and that removing it can make tests fail which never had a wait of their own.

for a middle

Be ready to name both places Selenium 4 can set the value and to show the read-back with getImplicitWaitTimeout, plus what an explicit wait replacing a removed implicit one should actually poll on.

for a senior

An interviewer expects the diagnostic sequencing: bound the slice, run it repeatedly, separate deterministic races from slow paths, and explain why the resulting failures are cheaper to fix than the mixed configuration was.

for a principal

Own the tradeoff between how fast you flip and how much failure you absorb at once, and the standard you set afterwards so the value cannot return through a capability nobody reviews.

## Why the dependence is invisible In most Selenium suites the implicit wait is a single line in a shared driver factory or a base-class setup hook, and nothing in an individual test records that it depends on that line. A booking test that clicks **next week** and then calls `driver.findElement(By.id("book-friday-1830")).click()` looks identical whether the slot list renders synchronously or 800 ms later. The implicit wait absorbs the difference silently, which is precisely why you cannot find the dependent tests by reading code — you buy that information with runs, not with grep. That is the shape of the problem: removing a session-wide implicit wait is not a refactor with a reviewable diff, it is an experiment whose result set is a list of failing tests. ## Where Selenium 4 sets the implicit wait There are two places, and a suite can carry both: | Set site | Call | When it applies | How it is easy to miss | |---|---|---|---| | Session command | `driver.manage().timeouts().implicitlyWait(Duration)` | immediately, and again any time it is called | usually visible in a factory or a setup hook | | New-session capability | `options.setImplicitWaitTimeout(Duration)` on `ChromeOptions` or any other `AbstractDriverOptions` subclass | from the moment the session is created | it writes the `implicit` member of the `timeouts` capability, so it never appears as a wait call at all | The only reliable audit is to ask the live session: `driver.manage().timeouts().getImplicitWaitTimeout()` issues a **Get Timeouts** command and returns the `implicit` value the remote end actually holds. Assert on that in the factory before you change anything, so you are measuring the real starting state rather than the one the code appears to set. ## A staged flip 1. Add the `getImplicitWaitTimeout()` assertion to the driver factory and record the value the suite really runs with. 2. Flip **one** package, tag or module to `Duration.ZERO` while the rest keeps the old value. The setting is per session, so two values can coexist inside a single parallel run — this is what bounds the blast radius. 3. Run that subset several times. Every new `NoSuchElementException` names the locator and the line that was leaning on the implicit wait. 4. Replace each one with a `WebDriverWait` on a condition that states what the test is really waiting for — the slot list populated, the confirmation banner present — rather than a bare presence check. 5. Move the zero into the shared factory, delete the old setting from both set sites, and keep the assertion so the value cannot drift back. ## Reading the fallout The failures that appear are not noise; they are the information the mixed configuration was destroying, and they come in two shapes: - **Deterministic** — the find fails on every run at the same line. That step always raced; the implicit wait was the only thing making it pass, and it now needs an explicit condition. - **Intermittent** — the find fails on some runs only. The page is sometimes slower on that path, and the honest fix is a condition that describes the readiness signal, not a longer blanket timeout. Both are cheaper to diagnose now than they were before, because a zero implicit wait makes the failure point exact: the stack names the find that was too early, instead of a `TimeoutException` on an unrelated outer wait 20 seconds later. ## What the zero setting buys beyond determinism - **Negative checks stop paying.** Any condition that succeeds by *not* finding an element — an assertion that a cancelled Friday-evening slot no longer shows a booked badge — costs the entire implicit wait per poll while the wait is set, and effectively nothing once it is zero. - **Timeouts start meaning what they say.** With one mechanism doing the retrying, a 15-second wait fails at about 15 seconds, so the numbers in a run report can be reasoned about. - **The waits become local.** Each `WebDriverWait` sits next to the step that needs it and names its condition, so the next reader can see which step is asynchronous. The judgment a lead owns here is the sequencing, not the end state: the end state is a zero implicit wait in every session, and the only real decision is how large a slice you flip at a time and whether the failures each slice surfaces are fixed in the same change or captured as work before the next slice is flipped.

  • How do you tell a test that genuinely raced from one that is merely slow on that path?
    Run the flipped slice several times. A find that fails on every run was always racing and needs a condition naming the readiness signal. One that fails on some runs points at a slower path, and the fix is still a condition rather than restoring the blanket wait — you just need the right signal to wait on.
  • Why assert getImplicitWaitTimeout instead of reading the setup code?
    Because the value can be set twice from different places — a session command and the `timeouts` capability in the browser options — and the capability form never looks like a wait call. `getImplicitWaitTimeout()` issues a Get Timeouts command and returns what the remote end actually holds, which is the only reading that cannot be stale.
  • What keeps an implicit wait from creeping back in later?
    Leave the factory assertion in place so any session created with a non-zero implicit wait fails immediately with the offending value in the message. That turns a silent regression into a loud one at the point of creation, before a single test has run.

saying these in an interview costs you the question

  • Flips the whole suite to zero in one change and triages the wreckage
  • Assumes the dependent tests can be found by reading the code
  • Trusts the setup code instead of reading the live session value
  • Keeps a small implicit wait as a safety net alongside explicit waits
  • Replaces the implicit wait with a fixed sleep in the base class