Checkpoint Lab — File Uploads, Downloads, Cookies, Storage, and Session State
Checkpoint: create one fully isolated browser-state test, verify exact bytes and synthetic session state, inject one deterministic state failure, and prove teardown leaves no reusable files, cookies, storage, or profile directory.
Learning objectives
- Build the chapter fixture from an empty directory with exact Selenium/browser assumptions.
- Predict and verify upload selection, deterministic download bytes, cookie state, and Web Storage state.
- Intentionally introduce a stale-file or cookie-scope failure and diagnose it from preserved evidence.
- Produce a compact evidence packet without secrets or personal data.
- Clean browser state before quit and remove every disposable filesystem artifact after quit.
- Explain how this state-isolation model prepares the course for browser preferences and JavaScript capability boundaries in Chapter 12.
1. Checkpoint scenario and acceptance criteria
Starting from an empty directory, create the same synthetic state
fixture, generate input.txt, select it in the browser,
download an uppercase transformed result, verify exact bytes, create
one synthetic cookie and one local/session storage value, then prove
cleanup.
The checkpoint also injects one reversible fault: a stale
transformed.txt is placed in the download directory
before the real action. The test must detect and remove
this contamination rather than silently passing against it.
2. Setup and preflight
The following example makes the Setup and preflight behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.
mkdir selenium-ch11-checkpoint
cd selenium-ch11-checkpoint
python -m venv .venv
# Windows PowerShell: .\.venv\Scripts\Activate.ps1
# Linux/macOS: source .venv/bin/activate
python -m pip install "selenium==4.47.0"
# Save the fixture generator from Lesson 2 as make_fixture.py
python make_fixture.py
python -m http.server 8776 --bind 127.0.0.1 --directory site
Preflight: supported local Chromium-family browser installed;
Selenium 4.47.0; Python 3.10+; 127.0.0.1:8776 free; no
real accounts/files; sufficient permission to create/delete the
checkpoint directory.
3. Write predictions before execution
- The clean download directory should contain zero files. The injected stale file should make that precondition fail before any browser click.
-
After removing contamination and triggering the real download,
exactly one
transformed.txtshould exist with bytes equal tosource.upper() + b"TRANSFORMED\n". - The browser should contain the synthetic cookie and two storage keys only after explicit mutation.
- Before quit, those browser keys should be removed. After quit, the entire disposable profile/input/download directory tree should be removable.
4. Run the checkpoint
The following example makes the Run the checkpoint 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
import hashlib
import json
import shutil
import tempfile
import selenium
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
URL = "http://127.0.0.1:8776/"
root = Path(tempfile.mkdtemp(prefix="selenium-ch11-checkpoint-"))
uploads = root / "uploads"
downloads = root / "downloads"
profile = root / "profile"
evidence = root / "evidence"
for p in (uploads, downloads, profile, evidence):
p.mkdir()
source = uploads / "input.txt"
source_bytes = b"checkpoint browser state\n"
expected_bytes = source_bytes.upper() + b"TRANSFORMED\n"
source.write_bytes(source_bytes)
target = downloads / "transformed.txt"
# Reversible failure injection: a stale artifact exists before browser action.
target.write_bytes(b"STALE FROM PREVIOUS RUN\n")
preflight_manifest = {p.name: p.stat().st_size for p in downloads.iterdir()}
assert "transformed.txt" in preflight_manifest
(target).unlink() # least-destructive correction after evidence was captured
assert list(downloads.iterdir()) == []
options = webdriver.ChromeOptions()
options.add_argument(f"--user-data-dir={profile.resolve()}")
options.add_experimental_option("prefs", {
"download.default_directory": str(downloads.resolve()),
"download.prompt_for_download": False,
"download.directory_upgrade": True,
"safebrowsing.enabled": True,
})
driver = webdriver.Chrome(options=options)
packet = {"preflight_download_manifest": preflight_manifest}
try:
driver.get(URL)
caps = driver.capabilities
packet["provenance"] = {
"selenium": selenium.__version__,
"session_id": driver.session_id,
"browser": caps.get("browserName"),
"browser_version": caps.get("browserVersion"),
"url": driver.current_url,
}
# Upload selection + visible AUT state.
driver.find_element(By.ID, "upload").send_keys(str(source.resolve()))
WebDriverWait(driver, 3).until(
lambda d: d.find_element(By.ID, "upload-state").text.startswith("upload:input.txt:")
)
# Controlled browser download + exact bytes.
driver.find_element(By.ID, "prepare").click()
WebDriverWait(driver, 3).until(
lambda d: d.find_element(By.ID, "download-state").text.startswith("download:ready:")
)
driver.find_element(By.ID, "download").click()
WebDriverWait(driver, 5).until(
lambda _: target.is_file() and target.stat().st_size == len(expected_bytes)
)
actual = target.read_bytes()
assert actual == expected_bytes
# One synthetic cookie + storage values.
driver.add_cookie({"name": "checkpoint_mode", "value": "synthetic", "sameSite": "Lax"})
driver.execute_script("localStorage.setItem('checkpoint.local','synthetic')")
driver.execute_script("sessionStorage.setItem('checkpoint.session','synthetic')")
packet["verified_state"] = {
"upload_state": driver.find_element(By.ID, "upload-state").text,
"download_state": driver.find_element(By.ID, "download-state").text,
"download_size": len(actual),
"download_sha256": hashlib.sha256(actual).hexdigest(),
"cookie_present": driver.get_cookie("checkpoint_mode") is not None,
"local_value": driver.execute_script("return localStorage.getItem('checkpoint.local')"),
"session_value": driver.execute_script("return sessionStorage.getItem('checkpoint.session')"),
}
driver.save_screenshot(str(evidence / "final.png"))
# Browser-state cleanup before session destruction.
driver.delete_cookie("checkpoint_mode")
driver.execute_script("localStorage.removeItem('checkpoint.local')")
driver.execute_script("sessionStorage.removeItem('checkpoint.session')")
packet["browser_cleanup"] = {
"cookie_absent": driver.get_cookie("checkpoint_mode") is None,
"local_absent": driver.execute_script("return localStorage.getItem('checkpoint.local')") is None,
"session_absent": driver.execute_script("return sessionStorage.getItem('checkpoint.session')") is None,
}
assert all(packet["browser_cleanup"].values())
(evidence / "run.json").write_text(json.dumps(packet, indent=2), encoding="utf-8")
finally:
driver.quit()
# Preserve a small checkpoint summary outside the disposable root before deletion.
summary = Path("checkpoint-summary.json")
summary.write_text(json.dumps(packet, indent=2), encoding="utf-8")
shutil.rmtree(root)
assert not root.exists()
print("PASS", summary.resolve())
The retained checkpoint-summary.json contains only
synthetic metadata, hashes, and state booleans. The browser profile
and downloaded bytes are intentionally deleted after verification.
5. Evidence packet requirements
The following table organizes the key choices and evidence for Evidence packet requirements. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.
| Evidence | Purpose | Privacy rule |
|---|---|---|
| Selenium/session/browser versions | provenance | no credentials or full capability dumps with secret vendor metadata |
| preflight download manifest | proves stale-file injection was detected | synthetic filename/size only |
| upload/download visible states | connects DOM/AUT behavior to file transition | synthetic names only |
| download size + SHA-256 | proves exact output without retaining file | hash is sufficient after deterministic byte assertion |
| cookie/storage presence booleans + synthetic values | proves browser-state mutation/cleanup | never record real auth tokens |
| final screenshot | visual support | fixture contains no customer/identity data |
6. Interpret the injected failure
If the checkpoint had asserted only target.exists(), it
would have passed before the browser started. The preflight manifest
turns that silent contamination into a deterministic failure signal.
The repair removes only the known disposable stale artifact,
reasserts an empty directory, and proceeds with a clean causal test.
7. Remote/Grid adaptation checklist
- Keep source-file generation on the runner and prove it exists.
- Use RemoteWebDriver file detection/transfer rather than assuming a shared runner path.
- If using Selenium remote downloadable files, explicitly enable downloads and collect/delete the remote files.
- Do not expose Grid publicly or place secrets in capabilities/profile paths.
- Treat node-local profile/download cleanup and CI artifact retention as separate responsibilities.
8. Cleanup/rollback proof
The test removes cookie/storage while the origin/session still exists, then quits the browser, then deletes the profile/input/download/evidence tree. That order matters: browser APIs cannot clean storage after session destruction, while the profile directory may still be locked until the browser exits.
9. Verification checklist
- Exact Selenium/browser/session provenance captured.
- Generated upload source used; no personal file.
- Stale download artifact detected before browser action.
- Real download verified by exact bytes and SHA-256.
- Synthetic cookie and local/session storage values observed only in the intended origin/session.
- Browser state removed before
quit(). -
Disposable root/profile/download/upload directories removed after
quit(). - No fixed sleeps, shared Downloads folder, personal profile, real credentials, or production target.
10. What Chapter 11 adds to the production operating model
The Selenium operating model now tracks non-DOM state explicitly: runner files, browser-selected uploads, download destinations, remote transfer boundaries, cookie scope, Web Storage, profile lifetime, sensitive artifact policy, and deterministic teardown. This makes parallel and rerun behavior explainable instead of dependent on machine residue.
Chapter 12 moves into JavaScript execution, browser capabilities, profiles, and preferences. The state discipline from this chapter is the prerequisite: browser-specific power must remain bounded by observable configuration and cleanup contracts.
11. Summary
Reliable file and session-state automation is an ownership problem.
Generate minimal data, keep directories/profiles per test, verify
exact outcomes, avoid retaining secrets, and prove teardown rather
than assuming quit() cleaned every external artifact.
Knowledge check
Why does the checkpoint inject a stale file before starting Selenium?
To prove that filename/existence-only download assertions can false-pass and to force an observable preflight cleanliness contract.
Why is the download hash retained but the downloaded file deleted?
The deterministic byte assertion already proved correctness; the hash provides compact evidence without retaining unnecessary file content.
Why remove cookie/storage before
driver.quit()?
Those browser state APIs require a live session and correct origin/context. Files/profile directories are then deleted after quit releases browser locks.
What changes for a remote Grid upload?
The runner-to-node file boundary becomes explicit; RemoteWebDriver file detection/transfer handles the source rather than relying on runner paths existing on the node.
What production topic follows in Chapter 12?
JavaScript execution, browser capabilities, profiles, and preferences—using the state ownership/cleanup discipline established here.
Official references and version notes
- Selenium 4.47 release notes — stable baseline pinned for this chapter.
- Selenium downloads — current stable bindings and Selenium Server/Grid versions.
- File upload — use a file input and send the full path; do not automate the OS chooser.
- Working with cookies — WebDriver cookie create/read/delete semantics.
- Python RemoteWebDriver API — LocalFileDetector default plus remote downloadable-file methods.
-
Python common Options API
—
enable_downloadscapability surface. - File downloads guidance — browser-triggered downloads do not provide portable progress semantics; prefer lower-layer verification where appropriate.
- Selenium API deprecations — Web Storage — local/session storage are not W3C WebDriver commands; use page-context script when storage inspection is required.
-
Python exceptions
— includes
InvalidCookieDomainException.
Version-sensitive behavior was rechecked against current primary
documentation on 2026-08-28. Mandatory examples pin Selenium
Python 4.47.0, require Python 3.10+, use a supported locally
installed Chromium-family browser with Selenium Manager for driver
resolution, and target only 127.0.0.1. Chromium
download preferences are intentionally labeled browser-specific.
Remote/Grid file-transfer and downloadable-file APIs are optional
extensions to the local path. JavaScript execution appears only
for Web Storage access, where Selenium explicitly notes
local/session storage are not W3C WebDriver commands. UI
interactions remain native WebDriver interactions.
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.