add a unit test
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user