| OP here. Ordinarily, I would agree with you, because PageObjects themselves are not composable, in languages belonging to the "Kingdom Of Nouns". However, the following design, thanks to Clojure's language design, helped address a rather nasty situation. A tightly scoped Domain Specific Language, over some Types of PageObjects, all of which compose arbitrarily (without breaking value semantics). So, if you wanted the `value` of a Modal box having all sorts of switches, form fields etc., you'd call `value` on it, and it would call `value` on all of its constituents, and return the immutable hash-map snapshot of whatever state it found. Cross-cutting concerns
| v PageObject / DSL -> | open | close | open? | select | deselect | ... |
|-----------------------+------+-------+-------+--------+----------+-----|
| Dropdown | | | | | | |
| Checkbox | | | | | | |
| Switch | | | | | | |
| Modal | | | | | | |
| SearchList | | | | | | |
| ... | | | | | | |
Concrete example (in the deck and demo linked below): (defprotocol IPageObject
"Each PageObject MUST implement the IPageObject protocol."
(page-object [this])
(exists? [this])
(visible? [this]))
And then an implementation like this: (defrecord Checkbox [target-css]
IPageObject
(page-object [this]
this)
(exists? [this]
;; webdriver check if target-css exists
)
(visible? [this]
;; webdriver check if target-css is visible
)
Selectable
(select [this]
;; webdriver select the target
)
(deselect [this]
;; webdriver undo selection
)
(selected? [this]
;; webdriver return true if target selected
)
Value
(get-value [this]
;; webdriver return current selection state
(selected? this)))
Deck: https://github.com/adityaathalye/slideware/blob/master/desig...Talk + Demo: https://www.youtube.com/watch?v=hwoLON80ZzA&list=PLG4-zNACPC... I also commented about it here: https://news.ycombinator.com/item?id=45161410 (Clojure's solution to the Expression problem). That said, UI testing is a hot mess in general (especially for SPAs). I prefer to avoid automating anything but the "happy paths". IME, exploratory testing is better at sussing out corner cases, and "emergent" misbehaviours. So I do that, in addition to the "happy path" suites. Cue: James Bach et. al. https://www.satisfice.com/ Also I am warming up to server-generated HTML, because I can unit-test that, if I can use `hiccup` syntax + HTMX. In that case, I just make all request handlers spit out HTML fragments as Clojure data, and test those responses in my test suite. |