Three interactions that trip up almost every Selenium beginner: uploading a file (the system file dialog cannot be automated by Selenium), downloading a file (Selenium has no built-in download verification), and executing JavaScript directly (for scenarios where Selenium’s API does not have a native method). Mastering these three techniques rounds out your ability to automate any web interaction you encounter.
File Uploads, Downloads and JavaScript Execution
Each of these scenarios requires a technique that goes beyond standard find_element and click.
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
import os
import time
# driver = webdriver.Chrome()
# โโ FILE UPLOAD โโ
# The key: send the file path directly to the element
# Do NOT click the upload button โ that opens the OS file dialog which Selenium cannot control
def upload_file(driver, file_path):
# Find the file input element (may be hidden โ that is OK)
file_input = driver.find_element(By.CSS_SELECTOR, "input[type='file']")
# Send the absolute file path directly โ no click needed
file_input.send_keys(os.path.abspath(file_path))
# Verify upload succeeded (application-specific)
WebDriverWait(driver, 10).until(
EC.visibility_of_element_located((By.CSS_SELECTOR, ".upload-success"))
)
print(f"Uploaded: {file_path}")
# โโ FILE DOWNLOAD โโ
# Configure Chrome to download to a specific directory without prompts
def setup_download_driver(download_dir):
os.makedirs(download_dir, exist_ok=True)
options = webdriver.ChromeOptions()
prefs = {
"download.default_directory": os.path.abspath(download_dir),
"download.prompt_for_download": False,
"download.directory_upgrade": True,
}
options.add_experimental_option("prefs", prefs)
return webdriver.Chrome(options=options)
def download_and_verify(driver, download_dir, expected_filename, timeout=15):
# Click the download link/button
driver.find_element(By.CSS_SELECTOR, "[data-testid='download-report']").click()
# Wait for the file to appear in the download directory
file_path = os.path.join(download_dir, expected_filename)
end_time = time.time() + timeout
while time.time() < end_time:
if os.path.exists(file_path) and not file_path.endswith(".crdownload"):
print(f"Downloaded: {file_path} ({os.path.getsize(file_path)} bytes)")
return file_path
time.sleep(0.5)
raise TimeoutError(f"Download did not complete: {expected_filename}")
# โโ JAVASCRIPT EXECUTION โโ
# Use driver.execute_script() for actions Selenium cannot do natively
JS_EXAMPLES = [
{
"name": "Scroll to bottom of page",
"code": "window.scrollTo(0, document.body.scrollHeight);",
"use": "Trigger lazy-loading content",
},
{
"name": "Scroll element into view",
"code": "arguments[0].scrollIntoView({behavior:'smooth', block:'center'});",
"use": "Make off-screen element visible before interaction",
"needs_element": True,
},
{
"name": "Click via JavaScript (bypass overlay)",
"code": "arguments[0].click();",
"use": "Click element blocked by overlay when normal click fails",
"needs_element": True,
},
{
"name": "Get element attribute",
"code": "return arguments[0].getAttribute('data-value');",
"use": "Read custom data attributes not exposed by Selenium API",
"needs_element": True,
},
{
"name": "Remove element (clear overlay)",
"code": "arguments[0].remove();",
"use": "Remove a blocking overlay or cookie banner for testing",
"needs_element": True,
},
{
"name": "Change input value directly",
"code": "arguments[0].value = arguments[1];",
"use": "Set a date picker value bypassing the calendar UI",
"needs_element": True,
},
{
"name": "Check if jQuery AJAX is complete",
"code": "return jQuery.active === 0;",
"use": "Wait for all AJAX requests to finish",
},
{
"name": "Get browser performance timing",
"code": "return window.performance.timing.loadEventEnd - window.performance.timing.navigationStart;",
"use": "Measure actual page load time from browser metrics",
},
]
# Example usage:
# driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# element = driver.find_element(By.ID, "target")
# driver.execute_script("arguments[0].scrollIntoView({block:'center'});", element)
# driver.execute_script("arguments[0].click();", element)
# value = driver.execute_script("return arguments[0].getAttribute('data-price');", element)
print("JavaScript Execution Examples")
print("=" * 60)
for ex in JS_EXAMPLES:
print(f"\n {ex['name']}")
print(f" JS: {ex['code']}")
print(f" Use: {ex['use']}")
<input type="file"> element using send_keys(). You must NOT click the upload button first โ clicking opens the OS file dialog, which Selenium cannot interact with. Instead, find the file input element (even if it is hidden via CSS) and send the absolute path to it. The browser handles the rest as if the user had selected the file through the dialog. This works across all browsers and operating systems.arguments[0].click() is the nuclear option for clicking elements that Selenium cannot click normally (covered by overlays, hidden behind z-index layers, or intercepted by event handlers). Unlike Selenium's native click, JavaScript click bypasses all visibility checks and fires the click event directly on the element. Use it as a last resort when EC.element_to_be_clickable() plus a normal click still fails โ but document why you needed it, because JavaScript clicks can mask real UI defects.execute_script("arguments[0].click()") to bypass click interception hides real defects. If an overlay is blocking the button for real users, they experience the same problem your test is working around. Before using JavaScript click, ask: is the overlay a legitimate UI element (cookie consent, loading spinner) or a bug? If it is a bug, file a defect instead of working around it. Reserve JavaScript clicks for known, acceptable overlays like cookie banners that you dismiss as part of test setup.Common Mistakes
Mistake 1 โ Clicking the upload button instead of sending keys to the file input
โ Wrong: driver.find_element(By.ID, "upload-btn").click() โ opens the OS file dialog that Selenium cannot control, hanging the test.
โ
Correct: driver.find_element(By.CSS_SELECTOR, "input[type='file']").send_keys("/path/to/file.jpg") โ sends the file path directly without opening the dialog.
Mistake 2 โ Using JavaScript click for every interaction
โ Wrong: Using execute_script("arguments[0].click()", element) for all clicks because "it always works."
โ
Correct: Using Selenium's native .click() by default and reserving JavaScript click for documented cases where native click cannot work (known overlay, framework limitation). Native clicks verify that the element is actually clickable by a user โ JavaScript clicks bypass this verification.