Back to Courses
SELENIUM PYTHON — BUILD A REAL AUTOMATION FRAMEWORK IN 34 DAYS

Selenium Python: Zero to Professional Automation

Learn to automate real websites using Python and Selenium, then structure everything into a clean, professional Pytest framework — the kind employers look for.

30+
Days of Training
14
Modules
100+
Topics Covered
Live
Project

Who Is This Course For?

This course is for QA testers and Python learners who want to automate real websites professionally. You'll start by writing your first browser automation script and finish with a complete, structured Pytest framework covering Selenium Grid, Shadow DOM, parametrized tests, Page Object Model, and HTML reporting — skills that make your CV stand out.

Python Selenium WebDriver Pytest ChromeOptions Selenium Grid Page Object Model Live Projects

Your Learning Journey

First Script
Locators & Actions
Advanced Scenarios
Pytest Framework
Job-Ready Framework
01
Module 1
Introduction & Environment Setup
Days 1–2  |  8 Topics
WHY THIS MODULE

Before writing a single automation line, you need Python, Selenium, and a clean workspace set up correctly. Skipping this causes cryptic errors for weeks. Getting the environment right first means everything after this is smooth.

Tools & Installation
  • Installing Python 3 and setting up PyCharm or VS Code as your editor
  • Creating a virtual environment with python -m venv .venv — keeps packages isolated
  • Installing Selenium: pip install selenium — the core automation library
  • WebDriver Manager: pip install webdriver-manager — auto-handles Chrome version
  • Understanding what lives inside the selenium.webdriver package
Your First Automation Script
  • Importing Selenium and understanding why from selenium import webdriver is the entry point
  • driver = webdriver.Chrome() — launch Chrome under full automation control
  • Running the script and watching Chrome open — this is the moment everything becomes real
02
Module 2
Browser Navigation & Control
Days 3–5  |  10 Topics
WHY THIS MODULE

Every test starts and ends with browser control — open the right page, navigate around it, then shut it cleanly. These five navigation commands are the foundation you'll use in every single test for the rest of the course.

Navigating Like a Real User
  • driver.get(url) — open any URL, like typing an address into the browser bar
  • driver.back() and driver.forward() — simulate the browser Back/Forward buttons
  • driver.refresh() — reload the page, same as pressing F5
  • driver.quit() — close everything and end the session completely
  • driver.close() — close just the current window (keeps session alive)
Reading Browser State
  • driver.title — read the page title to confirm you landed on the right page
  • driver.current_url — verify the URL after navigation or redirect
  • driver.page_source — get the full HTML — useful for debugging
  • driver.maximize_window() — ensures consistent element positions across test runs
  • The lifecycle of an automated test: open → navigate → interact → assert → close
03
Module 3
Locators — Finding Elements on the Page
Days 6–10  |  14 Topics
WHY THIS MODULE

You can't click a button unless you can tell Selenium exactly which button you mean. Locators are how you point at elements. Choosing the right locator strategy means your tests work reliably even when the page changes slightly.

The By Locator Strategies
  • from selenium.webdriver.common.by import By — import the locator helper
  • By.ID — the most stable locator; every element with an ID is uniquely identified
  • By.NAME — works well for form input fields that have a name attribute
  • By.XPATH — the most flexible; can navigate any path through the page structure
  • By.CSS_SELECTOR — shorter than XPath, uses the same rules as CSS stylesheets
  • By.CLASS_NAME — targets elements by their styling class
  • By.LINK_TEXT — find a link by exactly what it says on screen
  • find_elements() (plural) — returns all matching elements as a list
XPath — The Power Locator
  • Relative XPath (//tag[@attr='value']) vs absolute XPath — why relative is better
  • XPath axes — moving up (parent::), sideways (following-sibling::) in the page tree
  • Partial matching with contains() and starts-with() for dynamic elements
  • Elements with changing IDs — how XPath text matching keeps your locator stable
  • CSS Selector patterns: input#id, div.class > span — concise and fast
  • Test your locator in DevTools (F12 → Console → $x("your-xpath")) before coding
04
Module 4
Interacting with Elements — Click, Type, Read
Days 11–14  |  12 Topics
WHY THIS MODULE

Finding an element is step one. Actually doing something with it — clicking, typing, reading its value — is what makes automation useful. These methods are what turn your locators into real test actions, and you'll use every one of them daily.

Standard Interactions
  • element.click() — the most-used action in automation: buttons, links, checkboxes
  • element.send_keys("text") — type into any input field or text area
  • element.clear() — wipe existing text before typing new content
  • element.submit() — submit the parent form without clicking Submit explicitly
  • is_displayed(), is_enabled(), is_selected() — verify element state before acting
Reading What the Page Shows
  • element.text — read the visible text inside a label, button, or paragraph
  • element.get_attribute("value") — read the current value of an input field
  • get_attribute("href"), "class", "src" — read any HTML attribute
  • element.tag_name — confirm which HTML tag you're dealing with
JavaScript as a Fallback
  • driver.execute_script("alert('hello')") — trigger browser popups through JS
  • execute_script("return arguments[0].value;", el) — read value when .get_attribute fails
  • execute_script("arguments[0].click();", el) — click hidden or overlapping elements
05
Module 5
Mouse & Keyboard — Simulating Real Gestures
Days 15–16  |  10 Topics
WHY THIS MODULE

Many websites require hover menus, drag-and-drop, or keyboard shortcuts that a simple .click() can't handle. ActionChains lets you simulate exactly what a real user does — even complex multi-step mouse gestures.

ActionChains — Advanced Mouse Gestures
  • from selenium.webdriver.common.action_chains import ActionChains
  • ActionChains(driver) — create a gesture builder that queues multiple actions
  • .move_to_element(el) — hover over an element to reveal a dropdown or tooltip
  • .double_click(el) — double-click to edit inline text or open items
  • .context_click(el) — right-click to open a context menu
  • .drag_and_drop(source, target) — drag one element and drop it onto another
  • .click_and_hold(el) + .release(el) — for sliders and custom drag behaviour
  • .perform() — execute all queued actions at once, in order
Keyboard Shortcuts
  • from selenium.webdriver.common.keys import Keys
  • Special keys: Keys.ENTER, Keys.TAB, Keys.ESCAPE, Keys.BACKSPACE
  • Key combinations: ActionChains(driver).send_keys(Keys.CONTROL, 'a').perform()
06
Module 6
Frames & iFrames
Days 16–17  |  8 Topics
WHY THIS MODULE

iFrames are web pages embedded inside web pages — like a separate document loaded into a window. Selenium treats each frame as a separate context. Without switching into the frame first, your element search will fail silently, and you'll waste hours wondering why.

Switching into Frames
  • An iFrame is a mini web page inside the main page — payment widgets, maps, rich text editors
  • driver.switch_to.frame("frame-name") — switch by name or ID attribute
  • driver.switch_to.frame(0) — switch by index (0 = first frame on the page)
  • driver.switch_to.frame(element) — switch by passing the iFrame WebElement directly
  • driver.switch_to.default_content() — return to the main page document
  • driver.switch_to.parent_frame() — step one level out of a nested frame
Nested Frames
  • Switching into a frame inside another frame: switch to outer first, then switch to inner
  • Always switch back to default_content() when you're done — prevents test interference
07
Module 7
Shadow DOM — Automating Hidden Components
Day 17  |  7 Topics
WHY THIS MODULE

Modern websites increasingly use Shadow DOM to build reusable components with encapsulated styling. If you hit a page where every locator mysteriously returns "element not found", Shadow DOM is usually why. Knowing how to pierce it separates junior from senior automation engineers.

Understanding and Accessing Shadow DOM
  • Shadow DOM — a hidden subtree attached to an element, invisible to normal DOM queries
  • Why find_element(By.CSS_SELECTOR, ...) returns nothing inside a Shadow DOM
  • Step 1: find the shadow host — the outer element that "contains" the hidden content
  • shadow_root = host_element.shadow_root — access the hidden subtree
  • shadow_root.find_element(By.CSS_SELECTOR, "inner-tag") — search inside the shadow
  • Nested shadow DOM — chaining .shadow_root across multiple levels
  • JavaScript fallback: execute_script("return arguments[0].shadowRoot", host) for older Chrome versions
08
Module 8
Dropdowns, Alerts & Special Widgets
Days 18–19  |  11 Topics
WHY THIS MODULE

Dropdowns and alerts can't be handled with a regular .click(). The Select class gives you a clean API for HTML dropdowns, while switch_to.alert lets you respond to browser popups that block everything else on the page.

Select Class — HTML Dropdowns & Listboxes
  • from selenium.webdriver.support.ui import Select
  • select = Select(driver.find_element(By.ID, "dropdown-id")) — wrap the dropdown
  • select.select_by_visible_text("Canada") — choose by what users see on screen
  • select.select_by_value("CA") — choose by the hidden HTML value attribute
  • select.select_by_index(2) — choose by position in the list (0-based)
  • select.options — list of all available options as WebElements
  • Multi-select listboxes — calling select_by_* multiple times selects multiple items
Alert & Confirm Popup Handling
  • A JavaScript alert blocks the entire page until you respond — Selenium must handle it
  • alert = driver.switch_to.alert — switch focus to the popup
  • alert.accept() — click OK (also dismisses a simple alert)
  • alert.dismiss() — click Cancel on a confirm dialog
09
Module 9
Multiple Windows & File Downloads
Days 20–21  |  9 Topics
WHY THIS MODULE

Real-world applications open new tabs for payment confirmations, document previews, and external links. Without switching window context, Selenium stays stuck on the original page. File downloads are another daily automation task in e-commerce and reporting tools.

Handling Multiple Windows & Tabs
  • driver.window_handles — returns a list of all currently open window handles
  • driver.current_window_handle — get the handle for the current active window
  • driver.switch_to.window(handle) — switch focus to another window or tab
  • driver.close() — close the active window, then switch_to.window(original) to go back
  • Best practice: save the original handle before any action that opens new windows
Automating File Downloads
  • Setting a custom download folder using ChromeOptions preferences
  • prefs = {"download.default_directory": "/your/path"} — tell Chrome where to save
  • options.add_experimental_option("prefs", prefs) — apply before creating the driver
  • After downloading, use os.path.exists(filepath) to assert the file arrived
10
Module 10
Browser Options, Waits & Real Applications
Days 22–24  |  13 Topics
WHY THIS MODULE

Test flakiness — tests that randomly pass and fail — is the biggest frustration in automation. Most flakiness comes from not waiting for the page to be ready. Understanding waits is what separates scripts that work once from frameworks that work every time.

ChromeOptions — Customising the Browser
  • from selenium.webdriver.chrome.options import Options
  • options.add_argument("--headless") — run without a visible browser window (CI/CD friendly)
  • options.add_argument("--start-maximized") — full screen for consistent element positions
  • options.add_experimental_option("excludeSwitches", ["enable-automation"]) — remove "controlled by automation" banner
  • options.add_experimental_option("useAutomationExtension", False) — improve site compatibility
Smart Waiting Strategies
  • Why tests fail on fast-loading apps — your Python runs faster than the browser renders
  • driver.implicitly_wait(10) — global patience: retry every element find for up to 10 seconds
  • WebDriverWait(driver, 10).until(...) — smart wait: wait for exactly one condition
  • EC.visibility_of_element_located — wait until element is both present AND visible
  • EC.element_to_be_clickable — wait until element is ready to receive a click
  • driver.set_page_load_timeout(30) — don't wait forever if a page hangs
  • OrangeHRM live project — real login automation with proper waits applied
11
Module 11
Selenium Grid — Remote & Parallel Testing
Day 25  |  8 Topics
WHY THIS MODULE

Running 500 tests one by one on your laptop takes hours. Selenium Grid distributes tests across multiple machines or browsers simultaneously, cutting that time down dramatically. Every enterprise QA team uses Grid in their pipeline.

What Is Selenium Grid?
  • Grid = one coordinator + many worker machines running tests in parallel
  • Selenium Grid 4 — simplified setup, worker nodes self-register automatically
  • Starting the Grid server: java -jar selenium-server.jar standalone
  • Grid UI at http://localhost:4444 — see available browsers and test sessions
Remote WebDriver — Connecting Your Test to the Grid
  • from selenium.webdriver import Remote
  • driver = Remote(command_executor="http://localhost:4444/wd/hub", options=options)
  • Your test code is almost identical — only the driver creation line changes
  • Why Grid matters for CI/CD — tests run on a server without any display
12
Module 12
Pytest — The Industry-Standard Test Runner
Days 26–27  |  12 Topics
WHY THIS MODULE

A Selenium script that opens a browser is not a test — it has no pass/fail result. Pytest turns your automation code into real tests with structured results, categories, and the ability to run hundreds of tests with one command and see exactly which ones failed.

Pytest Fundamentals
  • Installing Pytest: pip install pytest
  • Test discovery — Pytest automatically finds files named test_*.py without any config
  • Test functions must start with test_ — Pytest's naming contract
  • Running all tests: pytest  |  Running one file: pytest test_login.py
  • pytest -v — verbose output showing each test name and result
  • assert statements — how Pytest decides pass or fail
Markers — Grouping Tests by Category
  • @pytest.mark.smoke, @pytest.mark.regression — tag any test with a label
  • pytest -m smoke — run only the tagged tests, ignore everything else
  • pytest.ini — project settings file: register markers to keep the project warning-free
  • [pytest] section with markers = list — one line per custom marker
  • lib.py — shared utility functions file; keeps common logic out of test files
  • Class-based tests: class Test_Login: with methods — clean grouping for related tests
13
Module 13
Fixtures & conftest.py — Reusable Test Setup
Days 27b–28  |  14 Topics
WHY THIS MODULE

Without fixtures, every test file opens and closes its own browser — 200 tests means 200 browser launches. Fixtures centralise setup so you write it once and reuse it everywhere. conftest.py shares that setup across all test files without a single import.

Pytest Fixtures
  • @pytest.fixture — decorator that marks a function as reusable setup code
  • The fixture's return value is injected into the test as a parameter — no manual call needed
  • yield in a fixture — code before yield runs as setup, code after runs as teardown
  • autouse=True — apply this fixture to all tests automatically, without listing it
conftest.py — The Shared Setup File
  • conftest.py — a special file Pytest always reads, no configuration required
  • Fixtures defined here are available to every test in the same directory and all subdirectories
  • No import needed — Pytest injects them by parameter name matching (magic injection)
  • This is where you put your browser setup fixture so every test file can use it
Fixture Scope — How Long Does the Browser Stay Open?
  • scope="function" (default) — fresh browser for every single test (safest, slowest)
  • scope="class" — one browser shared across all tests in a class
  • scope="module" — one browser shared across all tests in a file
  • scope="session" — one browser for the entire test run (fastest, most efficient)
  • Subpackages: __init__.py makes a folder a Python package — organise large test suites
14
Module 14
Full Framework — POM, Parametrize & Reporting
Days 28b–34  |  14 Topics
WHY THIS MODULE

This is the module that turns a collection of Selenium scripts into a professional framework you can put on your CV. Parametrize removes test duplication, Page Object Model makes your code maintainable, and reporting makes your results shareable with the team.

Data-Driven Testing with Parametrize
  • params in fixtures — pass a list of inputs, fixture runs once per item automatically
  • @pytest.mark.parametrize("username,password", [("admin","pass"),("user","123")])
  • One test function → many test cases — runs for every row of data in the list
  • request.param — access the current data set inside a parametrized fixture
Page Object Model — Professional Code Structure
  • The problem POM solves: one website change breaks dozens of test files — unmanageable
  • One page class per page — locators and actions live together, tests call methods only
  • Test files become readable: login_page.enter_username("admin") not raw locators
  • page/ folder — a dedicated home for all page classes
  • Base page class — shared find(), click(), type() methods inherited by all pages
Reporting & CI/CD
  • pytest --html=report.html — generate a visual HTML report you can share with the team
  • Screenshot on failure — driver.get_screenshot_as_file("failure.png") captured in conftest
  • Allure reporting — professional dashboard with pass/fail trends and step details
  • Complete project structure: conftest.py + page/ + tests/ + pytest.ini + reports/
  • CI/CD integration — running your full framework automatically on every code push
Bonus
Interview Preparation — Selenium Python

Locator Strategy Questions

Be ready to explain which locator you choose and why. Interviewers want to hear: "I prefer By.ID when available, fall back to By.XPATH with contains() for dynamic elements." Know when CSS Selector beats XPath for speed.

Test Flakiness Questions

The most common interview topic. Know the difference between implicitly_wait (global, less precise) and WebDriverWait with expected conditions (per-element, precise). Explain when each one is appropriate and why mixing them causes problems.

Frame & Alert Questions

Explain that Selenium has one active context at a time. You must switch_to.frame() before finding elements inside it, and switch_to.default_content() to return. For alerts, the entire page is blocked until you accept() or dismiss().

Pytest & conftest Questions

Explain conftest.py as the shared fixture file that Pytest reads automatically. Describe fixture scopes with a real example: scope="session" opens the browser once for 200 tests vs scope="function" which opens it 200 times.

POM Architecture Questions

Explain POM in plain language: "Each page class holds all locators and actions for that page. Tests only call methods like login_page.submit(). When the UI changes, I update one page class instead of every test file." This answer impresses every interviewer.

Grid & Remote Questions

Describe Grid as the system that runs tests in parallel across machines. Your code changes by just one line: webdriver.Chrome() becomes Remote("http://grid-host:4444/wd/hub", options). Everything else stays the same.