Chapter 11Lesson 05~210 minutes

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.

Checkpoint labExact bytesTeardownEvidence packetChapter 12 bridge

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

  1. The clean download directory should contain zero files. The injected stale file should make that precondition fail before any browser click.
  2. After removing contamination and triggering the real download, exactly one transformed.txt should exist with bytes equal to source.upper() + b"TRANSFORMED\n".
  3. The browser should contain the synthetic cookie and two storage keys only after explicit mutation.
  4. 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?

Why is the download hash retained but the downloaded file deleted?

Why remove cookie/storage before driver.quit()?

What changes for a remote Grid upload?

What production topic follows in Chapter 12?

Next chapter

JavaScript Execution, Browser Capabilities, Profiles, and Preferences: Core Concepts and Mental Model

Continue with JavaScript Execution, Browser Capabilities, Profiles, and Preferences: Core Concepts and Mental Model. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

Official references and version notes

Version and compatibility note

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.