add a unit test

This commit is contained in:
Kilian Schuettler
2026-08-25 10:31:00 +02:00
parent 8383405865
commit 8807ac5908
+162
View File
@@ -0,0 +1,162 @@
import os
import sys
import unittest
from datetime import datetime, time
from pathlib import Path
from unittest.mock import patch
PROJECT_DIR = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(PROJECT_DIR / "stempelbot"))
os.environ.setdefault("USERNAME", "test-user")
os.environ.setdefault("PASSWORD", "test-password")
os.environ.setdefault("SMART_TIME_PASSWORD", "smarttime-password")
os.environ.setdefault("AUTOSTAMP_FILE", "autostamps.json")
os.environ.setdefault("STAMPHISTORY_FILE", "timestamp_history.json")
os.environ.setdefault("LOG_LEVEL", "CRITICAL")
import smarttime_client as smarttime # noqa: E402
class FakeInput:
def __init__(self) -> None:
self.filled_with = None
self.pressed = None
def fill(self, value: str) -> None:
self.filled_with = value
def press(self, key: str) -> None:
self.pressed = key
class FakeLocator:
def __init__(self, page: "FakePage") -> None:
self.page = page
def inner_text(self, timeout: int) -> str:
index = min(self.page.body_reads, len(self.page.body_texts) - 1)
self.page.body_reads += 1
return self.page.body_texts[index]
class FakePage:
def __init__(self, body_texts: list[str], login_on_read: int | None = None) -> None:
self.body_texts = body_texts
self.login_on_read = login_on_read
self.body_reads = 0
self.user_input = FakeInput()
self.password_input = FakeInput()
self.goto_calls = 0
self.dashboard_opens = 0
def goto(self, *args, **kwargs) -> None:
self.goto_calls += 1
def evaluate(self, expression: str) -> None:
self.dashboard_opens += 1
def locator(self, selector: str) -> FakeLocator:
return FakeLocator(self)
def query_selector(self, selector: str):
if self.login_on_read == self.body_reads:
if "useraccount" in selector:
return self.user_input
if "password" in selector:
return self.password_input
return None
class SmartTimeLoadingTests(unittest.TestCase):
def test_waits_for_parseable_values_and_handles_delayed_login(self) -> None:
page = FakePage(
[
"SmartTime wird geladen",
"Anmeldung",
"Dashboard wird geladen",
"Letzte Buchung 08:42\nAktueller Status: Anwesend",
],
login_on_read=2,
)
with (
patch.object(smarttime, "DASHBOARD_LOAD_TIMEOUT_SEC", 1.0),
patch.object(smarttime, "DASHBOARD_POLL_INTERVAL_SEC", 0.0),
):
result = smarttime.SmartTimeClient._fetch_status(page)
self.assertEqual(result.last_stamp, time(8, 42))
self.assertEqual(result.status_text, "Anwesend")
self.assertEqual(page.user_input.filled_with, smarttime.settings.USERNAME)
self.assertEqual(
page.password_input.filled_with, smarttime.settings.SMART_TIME_PASSWORD
)
self.assertEqual(page.password_input.pressed, "Enter")
self.assertEqual(page.dashboard_opens, 2)
def test_incomplete_dashboard_raises_instead_of_returning_empty_snapshot(self) -> None:
page = FakePage(["Letzte Buchung\nAktueller Status"])
with (
patch.object(smarttime, "DASHBOARD_LOAD_TIMEOUT_SEC", 0.0),
patch.object(smarttime, "DASHBOARD_POLL_INTERVAL_SEC", 0.0),
):
with self.assertRaisesRegex(RuntimeError, "did not finish loading"):
smarttime.SmartTimeClient._fetch_status(page)
class SmartTimeVerificationTests(unittest.TestCase):
def test_verification_checks_status_once(self) -> None:
client = smarttime.SmartTimeClient()
snapshot = smarttime.SmartTimeStatus(time(9, 0), "Anwesend", datetime.now())
calls = 0
def get_status():
nonlocal calls
calls += 1
return snapshot
client.get_status = get_status
ok, message, returned_snapshot = client.verify_stamp(
datetime(2026, 8, 25, 10, 0), initial_delay=0
)
self.assertFalse(ok)
self.assertEqual(calls, 1)
self.assertIs(returned_snapshot, snapshot)
self.assertIn("Nicht verifiziert", message)
def test_stopped_worker_is_replaced_for_next_explicit_check(self) -> None:
expected = smarttime.SmartTimeStatus(time(11, 30), "Anwesend", datetime.now())
class DeadWorker:
ident = 1
@staticmethod
def is_alive() -> bool:
return False
class ReplacementWorker:
ident = None
@staticmethod
def is_alive() -> bool:
return False
@staticmethod
def submit(fn):
return expected
client = smarttime.SmartTimeClient()
client._worker = DeadWorker()
with patch.object(smarttime, "_PlaywrightWorker", ReplacementWorker):
result = client.get_status()
self.assertIs(result, expected)
self.assertIsInstance(client._worker, ReplacementWorker)
if __name__ == "__main__":
unittest.main()