Checkpoint Lab — Selenium Ecosystem, Installation, and First WebDriver Session
Build a disposable Selenium project from scratch, prove exactly what ran, repeat the minimal session, break driver discovery safely, recover, and leave behind a compact evidence packet that another engineer can interpret.
Learning objectives
- Create a Chapter 02 project from an empty directory using an isolated Python virtual environment.
- Pin Selenium 4.47.0 and verify Python 3.10+ before browser startup.
- Run the same loopback browser session twice and prove fresh session IDs with stable environment provenance.
- Inject a reversible missing-driver Service override and classify the resulting failure at the correct layer.
- Restore the default Selenium Manager path and prove a clean recovery run.
- Produce a sanitized evidence packet and cleanup/rollback record suitable for a CI installation runbook.
1. Checkpoint acceptance contract
The checkpoint is complete only when you can show all of the following:
-
an isolated environment with Selenium exactly
4.47.0; -
a loopback-only fixture bound to
127.0.0.1:8008; - two successful runs with different session IDs;
- recorded browser, browser version, platform, and reported driver version;
- one deterministic failure caused by an explicit nonexistent driver path;
- a written diagnosis explaining why the failure occurs before session creation;
- a restored default Manager run that passes;
- screenshots and JSON/text evidence containing no secrets, PII, or personal browser profile;
- clean teardown and removal of the disposable project when finished.
2. Setup from an empty directory
PowerShell
The following example makes the Setup from an empty directory behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
$LAB = Join-Path $PWD "selenium-ch02-checkpoint"
Remove-Item -Recurse -Force $LAB -ErrorAction SilentlyContinue
New-Item -ItemType Directory $LAB | Out-Null
Set-Location $LAB
py -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install selenium==4.47.0
python -c "import sys,selenium; assert sys.version_info >= (3,10); assert selenium.__version__ == '4.47.0'; print(sys.version); print(selenium.__version__)" | Set-Content evidence-python-selenium.txt
POSIX shell
The following example makes the Setup from an empty directory behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
LAB="$PWD/selenium-ch02-checkpoint"
rm -rf "$LAB"
mkdir -p "$LAB" && cd "$LAB"
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install selenium==4.47.0
python -c "import sys,selenium; assert sys.version_info >= (3,10); assert selenium.__version__ == '4.47.0'; print(sys.version); print(selenium.__version__)" | tee evidence-python-selenium.txt
If your machine already has a reviewed environment you cannot delete, choose a new lab directory rather than reusing it. The checkpoint should never change a personal browser profile or system driver installation.
3. Create the fixture and runner
Create fixture/index.html:
The following example makes the Create the fixture and runner behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
<!doctype html>
<html lang="en">
<head><meta charset="utf-8"><title>Selenium Chapter 02 Fixture</title></head>
<body>
<main>
<h1 id="status">Local fixture ready</h1>
<button id="confirm" type="button">Confirm session</button>
<p id="result" aria-live="polite">not confirmed</p>
</main>
<script>
document.querySelector('#confirm').addEventListener('click', () => {
document.querySelector('#result').textContent = 'confirmed';
});
</script>
</body>
</html>
Create fixture_server.py:
The following example makes the Create the fixture and runner behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
from functools import partial
from pathlib import Path
ROOT = Path(__file__).parent / "fixture"
server = ThreadingHTTPServer(("127.0.0.1", 8008), partial(SimpleHTTPRequestHandler, directory=str(ROOT)))
print("fixture=http://127.0.0.1:8008/")
try:
server.serve_forever()
except KeyboardInterrupt:
pass
finally:
server.server_close()
Create run_session.py:
The following example makes the Create the fixture and runner behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
import json
import sys
from pathlib import Path
from urllib.parse import urlparse
from selenium import __version__ as selenium_version
from selenium import webdriver
from selenium.webdriver.common.by import By
URL = "http://127.0.0.1:8008/"
run_name = sys.argv[1] if len(sys.argv) > 1 else "run"
out = Path("evidence") / run_name
out.mkdir(parents=True, exist_ok=True)
if urlparse(URL).hostname not in {"127.0.0.1", "localhost", "::1"}:
raise RuntimeError("checkpoint refuses non-loopback target")
driver = None
try:
driver = webdriver.Chrome()
caps = driver.capabilities
chrome = caps.get("chrome", {})
public = {
"selenium": selenium_version,
"session_id": driver.session_id,
"browserName": caps.get("browserName"),
"browserVersion": caps.get("browserVersion"),
"platformName": caps.get("platformName"),
"driverVersion": chrome.get("chromedriverVersion", "not-reported"),
}
print(json.dumps(public, indent=2))
(out / "session.json").write_text(json.dumps(public, indent=2), encoding="utf-8")
driver.get(URL)
assert driver.title == "Selenium Chapter 02 Fixture"
assert driver.find_element(By.ID, "result").text == "not confirmed"
driver.find_element(By.ID, "confirm").click()
assert driver.find_element(By.ID, "result").text == "confirmed"
driver.save_screenshot(str(out / "final.png"))
finally:
if driver is not None:
driver.quit()
Create break_driver.py:
The following example makes the Create the fixture and runner behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
from pathlib import Path
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
missing = Path("disposable-missing-driver") / "chromedriver"
service = webdriver.ChromeService(executable_path=str(missing))
try:
webdriver.Chrome(service=service)
except WebDriverException as exc:
Path("evidence").mkdir(exist_ok=True)
summary = f"{type(exc).__name__}: {str(exc).splitlines()[0]}\n"
Path("evidence/broken-driver.txt").write_text(summary, encoding="utf-8")
print(summary, end="")
The broken script does not remove or rename any real executable. It only injects a path that cannot exist inside the disposable directory.
4. Predict before execution
Write evidence/predictions.txt before running:
Prediction 1 — successful run
A fresh WebDriver session ID will be created; the fixture DOM will change from "not confirmed" to "confirmed"; one screenshot and one session JSON file will be written; the session will be closed at process exit.
Prediction 2 — second successful run
The second session ID will differ from the first; binding/browser/driver identity should remain stable unless the environment changed; the fixture begins again at "not confirmed".
Prediction 3 — broken explicit driver path
Session creation will fail before a session ID exists because the configured local driver executable does not exist. No AUT command should run.
Prediction 4 — recovery
Removing the explicit Service override and returning to webdriver.Chrome() will restore the default Selenium Manager path and the loopback session will pass again.
5. Run two clean sessions
Start the fixture server in a separate terminal:
python fixture_server.py
Then run:
The following example makes the Run two clean sessions behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
python run_session.py run-1
python run_session.py run-2
Compare evidence/run-1/session.json and
evidence/run-2/session.json. Session IDs must differ.
Browser/driver versions should be recorded for both. If they
unexpectedly differ, preserve that fact and investigate
environment/browser updates instead of editing the evidence.
6. Inject and diagnose the reversible failure
The following example makes the Inject and diagnose the reversible failure behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
python break_driver.py
Expected evidence is an exception summary indicating that the configured driver path is invalid/unavailable. Exact wording may vary by binding/platform. Your diagnosis must state:
- the failure occurs during local driver-service setup;
- no valid WebDriver session ID exists;
- the loopback fixture was not the cause because navigation never began;
- the deliberate explicit Service path bypassed the normal Manager-selected driver path;
- the recovery is to remove that override, not to copy/delete arbitrary system drivers.
7. Optional Manager diagnostic comparison
If the default path itself fails, rerun one small probe with current Manager debug and PATH-skip controls. Keep raw logs private until sanitized.
POSIX
The following example makes the Optional Manager diagnostic comparison behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
SE_DEBUG=true SE_SKIP_DRIVER_IN_PATH=true SE_AVOID_STATS=true python run_session.py manager-probe 2> evidence/manager-debug.log || true
PowerShell
The following example makes the Optional Manager diagnostic comparison behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
$env:SE_DEBUG="true"
$env:SE_SKIP_DRIVER_IN_PATH="true"
$env:SE_AVOID_STATS="true"
python run_session.py manager-probe 2> evidence\manager-debug.log
Remove-Item Env:SE_DEBUG,Env:SE_SKIP_DRIVER_IN_PATH,Env:SE_AVOID_STATS
Do not upload the raw log until paths, usernames, proxy endpoints/credentials, and other environment-specific details are reviewed.
8. Prove recovery
The following example makes the Prove recovery behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
python run_session.py recovered
A successful recovery must produce a new session ID and fresh
evidence/recovered/session.json plus screenshot. Do not
claim recovery merely because the browser window appears; the
assertions and evidence files must complete and teardown must run.
9. Verification checklist
-
evidence-python-selenium.txtproves Python 3.10+ and Selenium 4.47.0. - Run 1 and Run 2 have different session IDs.
- Both successful JSON files record browser name/version, platform, and reported driver version.
- Both screenshots show only the synthetic loopback fixture.
-
broken-driver.txtrecords the injected Service-path failure. - The diagnosis correctly states that no WebDriver session existed for the broken run.
- The recovered run passes with a fresh session ID.
- No production URL, credential, personal profile, Authorization header, proxy password, or PII appears in evidence.
- No browser is intentionally left open after the scripts exit.
10. Cleanup and rollback
Stop the fixture server with Ctrl+C. Preserve only the evidence you actually need, then remove the disposable directory.
PowerShell
The following example makes the Cleanup and rollback behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
deactivate
Set-Location ..
Remove-Item -Recurse -Force selenium-ch02-checkpoint
POSIX
The following example makes the Cleanup and rollback behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
deactivate
cd ..
rm -rf selenium-ch02-checkpoint
No system browser, PATH entry, Selenium Manager cache, corporate proxy, or global Python installation should have been modified by the checkpoint. If your environment downloaded a Manager-managed driver/browser asset into its normal cache, that cache is shared environment state; do not delete it automatically as “cleanup.”
11. What Chapter 02 adds to the operating model
You now have an installation contract: project dependency identity, browser source, driver-management ownership, session provenance, safe target boundary, guaranteed teardown, and a reproducible startup diagnostic path. Chapter 03 deepens the protocol boundary by examining W3C WebDriver architecture, session negotiation, capabilities, and the command/response model that the Chapter 02 constructor hides behind one line.
Knowledge check
What proves the two successful runs were fresh sessions?
Their session IDs differ, each starts from the fixture’s initial DOM state, and each creates separate evidence before its own teardown.
Why is the broken-driver test safer than renaming a real chromedriver?
It injects failure only through the disposable script configuration, so system PATH, caches, shared build agents, and real executables remain untouched.
What observation proves the broken run failed before AUT interaction?
No WebDriver session ID is created and navigation to the loopback fixture never begins; the exception comes from driver-service setup.
Why should the Manager cache not be blindly deleted during cleanup?
It is environment-level shared state used for performance and repeatability. The lab did not create it as a disposable project resource, and clearing it can affect unrelated runs.
What is the Chapter 03 bridge?
Moving from installation/lifecycle into W3C WebDriver session negotiation, capabilities, command routing, and protocol-level reasoning.
Official references and version notes
- Selenium 4.47 release notes — release baseline for this chapter.
- Selenium downloads — current stable language bindings and Selenium Server/Grid status.
-
Install a Selenium library
— project dependency installation and the current
selenium==4.47.0example. - WebDriver getting started and first script — browser/driver roles and first-session lifecycle.
- Selenium Manager — automated driver/browser discovery, download, cache, configuration, proxy, offline, PATH-skip, debug, and cache settings.
- Driver Service class — explicit local driver-service configuration and logging.
- Browser options — W3C capabilities and browser-specific options.
- Unable to locate driver — supported driver-location troubleshooting.
- Selenium Python 4.47.0 — Python 3.10+ requirement and package metadata.
Version-sensitive behavior was rechecked against current Selenium primary documentation on 2026-08-27. The mandatory path pins the Python binding to Selenium 4.47.0, requires Python 3.10+, uses one supported local Chromium-family browser for the runnable workflow, relies on Selenium Manager as the default driver-management path, and targets only a loopback fixture. The exact browser and driver versions are intentionally discovered from the created session rather than hard-coded. Selenium Grid, WebDriver BiDi, paid browser clouds, enterprise identity, and hosted CI are not required in Chapter 02.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.