from unittest.mock import MagicMock from selenium.common.exceptions import NoSuchElementException from wabot.fields import CheckField, NullField, SelectField, TextField from wabot.pacing import NoPacing from wabot.page import Page class BasePage(Page): elements = { "username": ("el", ("id", "username")), "state": ("select", ("id", "state")), "agree": ("checkbox", ("id", "agree")), "rows": ("els", ("css selector", "tr.row")), } class ChildPage(BasePage): elements = { "username": ("el", ("id", "user_name_v2")), # override "extra": ("el", ("id", "extra")), } def make_browser(): browser = MagicMock(name="browser") browser.pacing = NoPacing() return browser class TestElementResolution: def test_own_elements_found(self): page = BasePage(make_browser()) assert page.find_element_locators("username") == ("el", ("id", "username")) def test_mro_walk_inherits_parent_elements(self): page = ChildPage(make_browser()) assert page.find_element_locators("state") == ("select", ("id", "state")) assert page.find_element_locators("extra") == ("el", ("id", "extra")) def test_child_overrides_parent(self): page = ChildPage(make_browser()) assert page.find_element_locators("username") == ("el", ("id", "user_name_v2")) def test_missing_key_returns_none(self): assert BasePage(make_browser()).find_element_locators("nope") is None def test_empty_override_still_inherits_ancestors(self): class Grandchild(ChildPage): elements = {} # declares nothing; must still resolve ancestor keys page = Grandchild(make_browser()) assert page.find_element_locators("state") == ("select", ("id", "state")) assert page.find_element_locators("extra") == ("el", ("id", "extra")) class TestGetProxy: def test_typed_dispatch(self): page = BasePage(make_browser()) assert isinstance(page["username"], TextField) assert isinstance(page["agree"], CheckField) def test_select_dispatch(self, monkeypatch): import wabot.fields as fields_mod monkeypatch.setattr(fields_mod, "Select", MagicMock()) page = BasePage(make_browser()) assert isinstance(page["state"], SelectField) def test_els_returns_find_elements_result(self): browser = make_browser() page = BasePage(browser) result = page["rows"] browser.driver.find_elements.assert_called_once_with( by="css selector", value="tr.row" ) assert result is browser.driver.find_elements.return_value def test_unknown_key_returns_falsy_nullfield(self): el = BasePage(make_browser())["nope"] assert isinstance(el, NullField) assert not el def test_element_not_on_page_returns_nullfield(self): browser = make_browser() browser.driver.find_element.side_effect = NoSuchElementException("gone") el = BasePage(browser)["username"] assert isinstance(el, NullField) def test_custom_field_class_dispatch(self): class MyField(TextField): pass class CustomPage(Page): elements = {"thing": (MyField, ("id", "thing"))} assert isinstance(CustomPage(make_browser())["thing"], MyField) def test_malformed_locator_missing_accessors_returns_nullfield(self): class BadPage(Page): elements = {"x": ("el",)} # missing the accessors half el = BadPage(make_browser())["x"] assert isinstance(el, NullField) assert not el def test_malformed_accessors_arity_returns_nullfield(self): class BadPage(Page): elements = {"x": ("els", ("id",))} # accessors not a (by, value) pair assert isinstance(BadPage(make_browser())["x"], NullField) def test_unknown_type_returns_nullfield(self): class BadPage(Page): elements = {"x": ("selct", ("id", "x"))} # typo'd type string assert isinstance(BadPage(make_browser())["x"], NullField) class TestVerify: def test_default_verify_is_true(self): assert BasePage(make_browser()).verify() is True