From 9e825ffd803d2db9f895b5084cecaa830aa19f27 Mon Sep 17 00:00:00 2001 From: Mathew Sir Guest the best Date: Tue, 7 Jul 2026 22:45:46 -0600 Subject: [PATCH] test: assert field pacing wiring; simplify NullField --- .../plans/2026-07-07-wabot-modernization.md | 51 +++++++++++++++++-- src/wabot/fields.py | 3 +- tests/unit/test_fields.py | 44 ++++++++++++++++ 3 files changed, 92 insertions(+), 6 deletions(-) diff --git a/docs/superpowers/plans/2026-07-07-wabot-modernization.md b/docs/superpowers/plans/2026-07-07-wabot-modernization.md index 94e6ac3..949bbc0 100644 --- a/docs/superpowers/plans/2026-07-07-wabot-modernization.md +++ b/docs/superpowers/plans/2026-07-07-wabot-modernization.md @@ -1370,6 +1370,50 @@ class TestNullField: el = NullField(name="missing") if el: pytest.fail("NullField must be falsy") + + +class TestPacingWiring: + def _spy_page(self, page): + page.pacing = MagicMock() + page.pacing.delay.return_value = 0.0 + return page + + def test_text_set_value_paces_text(self, page): + self._spy_page(page) + TextField(page, accessors=ACCESSORS, name="username").set_value("x") + page.pacing.delay.assert_called_once_with("text") + + def test_select_set_value_paces_select(self, page, monkeypatch): + import wabot.fields as fields_mod + + monkeypatch.setattr(fields_mod, "Select", MagicMock()) + self._spy_page(page) + SelectField(page, accessors=("id", "state"), name="state").set_value(value="CO") + page.pacing.delay.assert_called_once_with("select") + + def test_select_by_index_paces_select(self, page, monkeypatch): + import wabot.fields as fields_mod + + monkeypatch.setattr(fields_mod, "Select", MagicMock()) + self._spy_page(page) + SelectField(page, accessors=("id", "state"), name="state").select_by_index(2) + page.pacing.delay.assert_called_once_with("select") + + def test_set_checked_paces_checkbox(self, page): + self._spy_page(page) + CheckField(page, accessors=("id", "agree"), name="agree").set_checked(True) + page.pacing.delay.assert_called_once_with("checkbox") + + def test_click_and_go_paces_navigate(self, page): + self._spy_page(page) + PageObject(page, accessors=ACCESSORS, name="username").click_and_go() + page.pacing.delay.assert_called_once_with("navigate") + + +class TestTruthiness: + def test_real_field_is_truthy(self, page): + # locks the other end of the `if el:` guard contract (NullField is falsy) + assert bool(TextField(page, accessors=ACCESSORS, name="username")) is True ``` - [ ] **Step 2: Run tests to verify they fail** @@ -1478,8 +1522,7 @@ class NullField: """Falsy placeholder for an element that was not found.""" def __init__(self, name=None): - # bypass __getattr__ tricks: plain attribute set - object.__setattr__(self, "name", name) + self.name = name def __bool__(self): return False @@ -1493,7 +1536,7 @@ class NullField: - [ ] **Step 4: Run tests to verify they pass** Run: `uv run pytest tests/unit/test_fields.py -v` -Expected: 11 passed +Expected: 17 passed - [ ] **Step 5: Commit** @@ -2787,7 +2830,7 @@ Run: `uv run pytest tests/unit/test_api.py -v` Expected: 11 passed Run: `uv run pytest` -Expected: full unit suite passes (107 tests: pacing 7, sessions 14, hosts 19, reattach 6, fields 11, page 23, screenshot 3, browser 13, api 11) +Expected: full unit suite passes (113 tests: pacing 7, sessions 14, hosts 19, reattach 6, fields 17, page 23, screenshot 3, browser 13, api 11) - [ ] **Step 5: Commit** diff --git a/src/wabot/fields.py b/src/wabot/fields.py index 172a1ec..1d93676 100644 --- a/src/wabot/fields.py +++ b/src/wabot/fields.py @@ -94,8 +94,7 @@ class NullField: """Falsy placeholder for an element that was not found.""" def __init__(self, name=None): - # bypass __getattr__ tricks: plain attribute set - object.__setattr__(self, "name", name) + self.name = name def __bool__(self): return False diff --git a/tests/unit/test_fields.py b/tests/unit/test_fields.py index f757850..9c6b758 100644 --- a/tests/unit/test_fields.py +++ b/tests/unit/test_fields.py @@ -85,3 +85,47 @@ class TestNullField: el = NullField(name="missing") if el: pytest.fail("NullField must be falsy") + + +class TestPacingWiring: + def _spy_page(self, page): + page.pacing = MagicMock() + page.pacing.delay.return_value = 0.0 + return page + + def test_text_set_value_paces_text(self, page): + self._spy_page(page) + TextField(page, accessors=ACCESSORS, name="username").set_value("x") + page.pacing.delay.assert_called_once_with("text") + + def test_select_set_value_paces_select(self, page, monkeypatch): + import wabot.fields as fields_mod + + monkeypatch.setattr(fields_mod, "Select", MagicMock()) + self._spy_page(page) + SelectField(page, accessors=("id", "state"), name="state").set_value(value="CO") + page.pacing.delay.assert_called_once_with("select") + + def test_select_by_index_paces_select(self, page, monkeypatch): + import wabot.fields as fields_mod + + monkeypatch.setattr(fields_mod, "Select", MagicMock()) + self._spy_page(page) + SelectField(page, accessors=("id", "state"), name="state").select_by_index(2) + page.pacing.delay.assert_called_once_with("select") + + def test_set_checked_paces_checkbox(self, page): + self._spy_page(page) + CheckField(page, accessors=("id", "agree"), name="agree").set_checked(True) + page.pacing.delay.assert_called_once_with("checkbox") + + def test_click_and_go_paces_navigate(self, page): + self._spy_page(page) + PageObject(page, accessors=ACCESSORS, name="username").click_and_go() + page.pacing.delay.assert_called_once_with("navigate") + + +class TestTruthiness: + def test_real_field_is_truthy(self, page): + # locks the other end of the `if el:` guard contract (NullField is falsy) + assert bool(TextField(page, accessors=ACCESSORS, name="username")) is True