Checkpoint Lab — JavaScript Execution, Browser Capabilities, Profiles, and Preferences
The checkpoint converts Chapter 12 into an auditable browser-configuration record: two equivalent local flows, one WebDriver-native and one using a deliberately narrow JavaScript helper, an isolated Chromium preference, one reversible capability failure, and explicit separation of portable versus vendor-specific assumptions.
Learning objectives
- Build the local fixture from an empty directory and pin Selenium Python 4.47.0.
- Predict browser/session/DOM/event/profile changes before running either flow.
- Run a WebDriver-native interaction and an equivalent small script-helper interaction and compare evidence.
- Configure one isolated Chromium preference and classify standard versus vendor-specific configuration.
- Inject an invalid capability in a separate disposable session attempt and diagnose negotiation failure without weakening trust/security.
- Produce a concise evidence packet and clean profile/files/session state deterministically.
- Bridge the operating model to Chapter 13 page/component abstraction patterns.
1. Checkpoint scenario and acceptance criteria
From an empty directory, build the same loopback fixture. Session A
uses WebDriver-native text entry. Session B uses a narrowly scoped
JavaScript helper to set the same value and dispatch one
input event, but still uses WebDriver for the Apply
business action. Both sessions configure the same isolated Chromium
language preference and standard page-load strategy. A third session
attempt deliberately requests one invalid capability and must fail
before browser use.
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-ch12-checkpoint
cd selenium-ch12-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 Lesson 2's fixture generator as make_fixture.py
python make_fixture.py
python -m http.server 8777 --bind 127.0.0.1 --directory site
Preflight: Python 3.10+; Selenium 4.47.0; supported local Chromium-family browser; Selenium Manager allowed to resolve the driver; port 8777 free; no proxy credentials/personal profiles/production targets; filesystem permission for temporary profiles.
3. Write predictions before execution
- Session A native typing will create more focus/key/input events than Session B's scripted value helper.
-
Both flows will end with the same visible
saved:academyapplication state if the helper dispatches the requiredinputevent and Apply remains a native click. -
Both valid sessions will report standard
pageLoadStrategy=eager; the Chromium preference belongs under vendor options and its runtime effect is checked separately vianavigator.language. - The invalid unprefixed capability session should fail during session creation and must not trigger any fallback such as JS bypass, insecure TLS, or browser restart loops.
-
Each valid session owns its own disposable profile, which is
deleted only after
quit().
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 json
import shutil
import tempfile
import selenium
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
URL = "http://127.0.0.1:8777/"
root = Path(tempfile.mkdtemp(prefix="selenium-ch12-checkpoint-"))
evidence = root / "evidence"
evidence.mkdir()
packet = {"selenium": selenium.__version__, "runs": {}}
def new_options(profile: Path):
options = webdriver.ChromeOptions()
options.page_load_strategy = "eager" # standard capability
options.add_argument(f"--user-data-dir={profile.resolve()}")
options.add_experimental_option("prefs", {"intl.accept_languages": "en-US"})
return options
def run_flow(name: str, scripted: bool):
profile = root / f"profile-{name}"
profile.mkdir()
options = new_options(profile)
requested = options.to_capabilities()
driver = webdriver.Chrome(options=options)
try:
driver.get(URL)
WebDriverWait(driver, 2).until(lambda d: d.find_element(By.ID, "ready").text == "app:ready")
field = driver.find_element(By.ID, "nickname")
if scripted:
# Deliberately narrow helper: state injection for comparison only.
driver.execute_script("""
arguments[0].value = arguments[1];
arguments[0].dispatchEvent(new Event('input', {bubbles:true}));
""", field, "academy")
else:
field.send_keys("academy")
before_apply_events = int(driver.find_element(By.ID, "events").text.split(":")[1])
driver.find_element(By.ID, "apply").click() # always native business interaction
WebDriverWait(driver, 2).until(
lambda d: d.find_element(By.ID, "status").text == "saved:academy"
)
caps = driver.capabilities
result = {
"requested_standard": {"pageLoadStrategy": requested.get("pageLoadStrategy")},
"requested_vendor": requested.get("goog:chromeOptions", {}),
"returned": {
"browserName": caps.get("browserName"),
"browserVersion": caps.get("browserVersion"),
"pageLoadStrategy": caps.get("pageLoadStrategy"),
},
"session_id": driver.session_id,
"before_apply_events": before_apply_events,
"language": driver.execute_script("return navigator.language"),
"status": driver.find_element(By.ID, "status").text,
}
driver.save_screenshot(str(evidence / f"{name}.png"))
return result
finally:
driver.quit()
shutil.rmtree(profile)
packet["runs"]["native"] = run_flow("native", scripted=False)
packet["runs"]["script_helper"] = run_flow("script-helper", scripted=True)
assert packet["runs"]["native"]["status"] == "saved:academy"
assert packet["runs"]["script_helper"]["status"] == "saved:academy"
assert packet["runs"]["native"]["before_apply_events"] > packet["runs"]["script_helper"]["before_apply_events"]
# Reversible failure injection: an invalid, unprefixed capability.
bad = webdriver.ChromeOptions()
bad.set_capability("academyMadeUpCapability", True)
packet["invalid_capability_request"] = bad.to_capabilities()
try:
bad_driver = webdriver.Chrome(options=bad)
except WebDriverException as exc:
packet["invalid_capability_result"] = type(exc).__name__
else:
bad_driver.quit()
raise AssertionError("Expected the invalid capability to be rejected")
# Preserve only synthetic configuration/evidence metadata outside disposable profiles.
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())
5. Compare observability and meaning
The following table organizes the key choices and evidence for Compare observability and meaning. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.
| Dimension | Native flow | Script-helper flow |
|---|---|---|
| text entry semantics | focus/key/input behavior exercised | value property + one synthetic input event only |
| interactability | WebDriver element/input checks apply | helper can change state without typing semantics |
| business action | native Apply click | native Apply click |
| final visible state | saved:academy |
saved:academy |
| correct use case | user-entry requirement | explicit fixture/state-injection comparison only |
6. Portable versus browser-specific configuration record
The following table organizes the key choices and evidence for Portable versus browser-specific configuration record. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.
| Item | Classification | Reason |
|---|---|---|
Selenium/WebDriver session +
pageLoadStrategy=eager
|
standard/portable request | defined by WebDriver |
goog:chromeOptions language preference |
Chromium-specific | vendor namespace/preference |
--user-data-dir profile argument |
Chromium-specific implementation detail | browser argument |
execute_script transport |
standard WebDriver command; page code is app-specific | command portable, script contract may not be |
navigator.language runtime check |
web-platform observation | verifies vendor preference effect |
| invalid unprefixed capability | intentionally invalid | must not be normalized into production config |
7. Evidence packet
- Selenium version and one session ID per valid flow.
- Requested standard capability subset and requested vendor options.
- Returned browser/version/page-load strategy.
- Native versus scripted event counts and final visible application status.
- Runtime language observation.
- First invalid-capability exception type and the exact synthetic capability request.
- Two screenshots from the synthetic fixture.
- No full personal profile, proxy credential, cookie token, or cloud secret capture.
8. Verification checklist
- Exactly two successful valid sessions, each with its own disposable profile.
- Native flow produces a richer input-event path than the scripted helper.
- Both valid flows reach the same visible business outcome through a native Apply click.
- Standard and Chromium-specific configuration are recorded separately.
- Runtime behavior is checked rather than assuming requested preferences were honored.
- Invalid capability fails at session negotiation; no retry/JS/TLS workaround is introduced.
- Profiles are deleted only after browser quit.
- Loopback fixture contains no real credentials/accounts/files.
9. Cleanup and rollback
The checkpoint deletes each profile immediately after its browser quits, then deletes the evidence root after writing the small synthetic summary. Stop the loopback server and remove the project directory when finished. No system browser profile/preferences or OS trust settings were changed.
10. What Chapter 12 adds to the production operating model
The browser-automation operating model now has explicit control-plane rules: WebDriver-first user behavior, bounded page-script helpers, standard versus vendor capability classification, per-session profile ownership, runtime verification of preferences, security review for trust/proxy settings, and configuration evidence for CI diagnosis.
Chapter 13 moves from browser configuration to maintainable test structure: Page Object, Page Component, Screenplay, and other abstraction patterns. The configuration boundaries learned here should remain outside page abstractions unless they are genuinely part of page behavior.
11. Summary
Browser-specific power is safe when its scope and lost semantics are explicit. A passing scripted shortcut is not automatically equivalent to user behavior, and a requested capability is not proof of runtime effect. Keep configuration minimal, isolated, observable, and reviewable.
Knowledge check
Why can two flows end with the same DOM state but test different behavior?
The native flow exercises focus/key/input/interactability semantics; the scripted helper directly changes page state and therefore proves less about user interaction.
Which checkpoint configuration is standard and which is Chromium-specific?
pageLoadStrategy is standard WebDriver;
goog:chromeOptions preferences and
--user-data-dir are Chromium-specific.
Why intentionally request an invalid capability?
To prove capability negotiation is an explicit contract and that unsupported configuration should fail visibly rather than be masked by retries or unrelated workarounds.
Why keep the Apply click native in both flows?
The business interaction remains part of the user-facing behavior, so the checkpoint isolates only the text-state helper difference.
What architectural topic follows in Chapter 13?
Page Object, Page Component, Screenplay, and test abstraction patterns, with browser/session configuration kept as a separate concern.
Official references and version notes
- Selenium 4.47 release notes — stable baseline pinned for this chapter.
- Selenium downloads — stable bindings/Grid versus 4.48 snapshot artifacts.
- Python WebDriver API — synchronous/asynchronous JavaScript execution and session capabilities.
- Browser options — standard capabilities including page-load strategy and insecure-certificate behavior.
- Chrome-specific functionality — Chromium option/configuration boundary.
-
Python Chrome Options API
— arguments, experimental options, capabilities, and
to_capabilities(). - Python common Options API — page-load strategy and cross-browser option properties.
- Avoid sharing state — fresh-session isolation guidance.
Version-sensitive behavior was rechecked against current Selenium
primary documentation on 2026-08-28. Mandatory examples pin
Selenium Python 4.47.0 and Python 3.10+, use a supported locally
installed Chromium-family browser with Selenium Manager, and
target only
127.0.0.1. Selenium 4.48 material currently exposed
in generated API pages/download snapshots is treated as
development/nightly, not the stable lesson baseline.
Browser-specific preferences are labeled as such. JavaScript state
mutation is used only in explicit comparison/safety examples;
user-facing business interactions remain WebDriver-native. No
mandatory example enables insecure certificates or changes
system/enterprise browser policy.
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.