Files
Tirsvad 9a9ea53cc1 Add headless Docker run, screenshots per lecture step and README
Dockerfile with Chromium, capture_steps module, Chrome environment
support, stale-element retries, owned-amount purchase check, the five
screenshots from a 300 second run (16.6 cookies per second) and the README
from the framework template. Reviewed in RC-013.

Task: MIL-004#1
Task: MIL-004#2
Task: MIL-004#3
Task: MIL-004#4
Task: MIL-004#5
Closes #19
Closes #20
Closes #21
Closes #22
Closes #23
2026-10-28 17:00:38 +08:00

65 lines
2.0 KiB
Python

"""@file
@brief Fakes of the ports for tests that must not start a browser or sleep.
"""
from collections.abc import Callable
class FakeGame:
"""@brief Records what the bot does and answers reads from dictionaries."""
def __init__(
self,
texts: dict[str, str] | None = None,
attributes: dict[tuple[str, str], str] | None = None,
on_click: Callable[[str], None] | None = None,
text_sequences: dict[str, list[str]] | None = None,
) -> None:
self.texts: dict[str, str] = texts or {}
self.attributes: dict[tuple[str, str], str] = attributes or {}
self.on_click = on_click
## Texts returned one per read, before the plain text applies.
self.text_sequences: dict[str, list[str]] = text_sequences or {}
self.reads: dict[str, int] = {}
self.opened: list[str] = []
self.waited: list[str] = []
self.clicked: list[str] = []
self.close_calls = 0
def open_page(self, url: str) -> None:
self.opened.append(url)
def wait_for_element(self, element_id: str) -> None:
self.waited.append(element_id)
def click_element(self, element_id: str) -> None:
self.clicked.append(element_id)
if self.on_click is not None:
self.on_click(element_id)
def read_text(self, element_id: str) -> str:
self.reads[element_id] = self.reads.get(element_id, 0) + 1
queued = self.text_sequences.get(element_id)
if queued:
return queued.pop(0)
return self.texts[element_id]
def read_attribute(self, element_id: str, attribute: str) -> str:
return self.attributes.get((element_id, attribute), "")
def close(self) -> None:
self.close_calls += 1
class FakeClock:
"""@brief A clock that moves forward by a fixed step on every reading."""
def __init__(self, step: float = 1.0) -> None:
self.now = 0.0
self.step = step
def monotonic(self) -> float:
reading = self.now
self.now += self.step
return reading