The two styles of synchronization
The way I teach Page Objects is that things are divided into Elements and Actions. One trait of an Action is that the thing it is action-ing often requires some sort of synchronization event — a wait_for_page_to_load or wait_for_element_present type thing.
One advantage of being a consultant is you get to see lots of code and solve problems in a variety of way. But I’ve realized that there are two main patterns for doing this synchronization.
In-Object Blocking
The first pattern, which is prevalent in the sites that use page changes as a means of moving through the application or when the action triggers something on the current page (like applying a filter on a dataset).
<pre lang="python">def go_to_some_page(self):
self.se.click(locators['some_locator'])
self.se.wait_for_page_to_load(string_timeout)
return NewPage()
def apply_filter(self):
self.se.click(locators['some_other_locator'])
self.wait_for_element_not_present(locators['spinner'])
Out-of-Object Blocking
The second pattern is needed when you need to rely on an element in an element that is in a different Page Object. Recall that an element should be referenced directly in one, and only one, Page Object. If you think you need to in more than one, you should think really hard about whether you need to refactor your object model and/or synchronization method.
In this pattern you create the Page Object for the new page, call a self-synchronization method and then return the object back to the caller.
<pre lang="python">def go_to_some_page(self):
self.se.click(locators['some_locator'])
o = NewPage()
o.wait_until_loaded()
return o
<pre lang="python">def wait_until_loaded(self):
self.wait_for_element_not_present(locators['spinner'])
There are almost certainly other patterns for doing synchronization, but these two I use a tonne an can solve pretty much any problem.