Multiple Windows and Tabs — Opening, Switching and Managing Browser Contexts

Some workflows open new browser windows or tabs — clicking a “Terms and Conditions” link that opens in a new tab, OAuth login flows that open a popup, or print previews that launch a separate window. Selenium can only interact with one window at a time, so you must explicitly switch between window handles to interact with content in different windows. Managing these handles correctly is essential for testing any multi-window workflow.

Window Handles — Opening, Switching and Closing Windows

Every browser window or tab has a unique handle — a string identifier that Selenium uses to track and switch between windows. The driver always has one “current” window; all commands apply to that window until you switch.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# driver = webdriver.Chrome()

# ── Basic window handle management ──
def demonstrate_window_handles(driver):
    # Get the current (original) window handle
    original_window = driver.current_window_handle
    print(f"Original window: {original_window}")
    print(f"Total windows: {len(driver.window_handles)}")

    # Click a link that opens a new tab/window
    driver.find_element(By.CSS_SELECTOR, "a[target='_blank']").click()

    # Wait for the new window to appear
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))

    # Get all window handles
    all_windows = driver.window_handles
    print(f"After click — total windows: {len(all_windows)}")

    # Switch to the new window (the one that is NOT the original)
    for handle in all_windows:
        if handle != original_window:
            driver.switch_to.window(handle)
            break

    # Now interacting with the NEW window
    print(f"New window title: {driver.title}")
    print(f"New window URL: {driver.current_url}")

    # Interact with elements in the new window
    # ... driver.find_element(...) ...

    # Close the new window
    driver.close()

    # Switch back to the original window
    driver.switch_to.window(original_window)
    print(f"Back to original: {driver.title}")


# ── Open a new window or tab programmatically (Selenium 4) ──
def open_new_window_selenium4(driver):
    original = driver.current_window_handle

    # Open a new tab
    driver.switch_to.new_window("tab")
    driver.get("https://www.example.com")
    print(f"New tab: {driver.title}")

    # Open a new window (separate browser window)
    driver.switch_to.new_window("window")
    driver.get("https://www.google.com")
    print(f"New window: {driver.title}")

    # Clean up: close extras and return to original
    for handle in driver.window_handles:
        if handle != original:
            driver.switch_to.window(handle)
            driver.close()
    driver.switch_to.window(original)


# ── OAuth popup workflow ──
def handle_oauth_popup(driver):
    original = driver.current_window_handle

    # Click "Login with Google" — opens OAuth popup
    driver.find_element(By.CSS_SELECTOR, "[data-testid='google-login']").click()

    # Wait for popup
    WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2))

    # Switch to popup
    popup = [h for h in driver.window_handles if h != original][0]
    driver.switch_to.window(popup)

    # Interact with OAuth form in the popup
    driver.find_element(By.ID, "identifierId").send_keys("test@gmail.com")
    driver.find_element(By.CSS_SELECTOR, "[data-testid='next-btn']").click()

    # After OAuth completes, popup closes automatically
    WebDriverWait(driver, 15).until(EC.number_of_windows_to_be(1))

    # Switch back to original window
    driver.switch_to.window(original)

    # Verify login succeeded on the original page
    WebDriverWait(driver, 10).until(
        EC.visibility_of_element_located((By.CSS_SELECTOR, ".user-avatar"))
    )


# ── Window management reference ──
WINDOW_COMMANDS = [
    ("driver.current_window_handle",           "Get the active window's handle"),
    ("driver.window_handles",                  "Get list of all open window handles"),
    ("driver.switch_to.window(handle)",        "Switch to a specific window"),
    ("driver.switch_to.new_window('tab')",     "Open and switch to a new tab (Selenium 4)"),
    ("driver.switch_to.new_window('window')",  "Open and switch to a new window (Selenium 4)"),
    ("driver.close()",                         "Close the CURRENT window only"),
    ("driver.quit()",                          "Close ALL windows and end the session"),
]

print("Window Management Reference")
print("=" * 65)
for cmd, desc in WINDOW_COMMANDS:
    print(f"  {cmd}")
    print(f"    → {desc}")
Note: driver.close() and driver.quit() are fundamentally different. close() closes only the current window — if other windows are open, the session continues. quit() closes all windows and terminates the WebDriver session entirely. After calling close(), you must switch to another window handle; after calling quit(), any further driver commands will throw InvalidSessionIdException. In multi-window tests, use close() for popup cleanup and quit() only in teardown.
Tip: Save the original window handle before clicking the link that opens a new window. The handle does not change, but the order of window_handles is not guaranteed to be consistent across browsers. By saving the original handle first, you can reliably identify the new window as “the handle that is not the original” — regardless of order.
Warning: After closing a window with driver.close(), the driver’s context becomes invalid — it is pointing to a window that no longer exists. You must immediately call driver.switch_to.window(some_handle) to switch to a valid window. Any find_element or navigation command between close() and switch_to.window() will throw NoSuchWindowException.

Common Mistakes

Mistake 1 — Not waiting for the new window before switching

❌ Wrong: link.click(); driver.switch_to.window(driver.window_handles[1]) — the new window may not have opened yet, causing an IndexError.

✅ Correct: link.click(); WebDriverWait(driver, 10).until(EC.number_of_windows_to_be(2)); ... — wait for the window to exist before accessing its handle.

Mistake 2 — Using driver.quit() when only the popup should close

❌ Wrong: Calling driver.quit() to close a popup window — this kills the entire browser session including the main window.

✅ Correct: Switching to the popup, calling driver.close() (closes only the popup), then switching back to the original window.

🧠 Test Yourself

After clicking “Login with Google,” a popup opens for OAuth authentication. After the user authenticates, the popup closes automatically. Which sequence correctly handles this workflow?