By Zac Campbell
Mobile phone users don’t have the patience to click and wait for a page to load. The less powerful phone CPU combined with unreliable cell network internet means waiting for pages to load is a very poor user experience.
Finally, we have a tiny screen to work with so app developers can’t show large volumes of data at once. We either have to switch pages or pan to reach the off-screen content.
This diagram depicts the Firefox OS Music app if we were able to see it as one big webpage. The blue box represents the viewport of the smartphone. Each display panel is a <div>. The list, sublist and player <div> are all loaded in one HTML page and scrolled in and out of the phone’s viewport using CSS3 transformX. The CSS3 transition attribute animates each of these transitions so it looks smooth.
How does this affect UI testing on Firefox OS? The main problem is that we are missing are the page loading events. WebDriver is very good at detecting these events and automatically pausing itself while loading a new page. When testing the Music app on Firefox OS we’re not loading a new page so there is no clear delineation of the page load starting or ending. Instead, we need to be very precise in telling Marionette to wait for the CSS transition to complete before we can continue the test.
In this example of the Music app, when we change into the list mode view the <body> tag of the app is set with the CSS tag “list-mode” which shifts the body -100%. Waiting for an element that matches the CSS locator “body.list-mode” to be visible on the page is how we know the content we need is on screen and the test is ready to continue.
Here is a Python code snippet for waiting for an element to be displayed:
def wait_for_element_displayed(self, by, locator, timeout=30): timeout = float(timeout) + time.time() while time.time() < timeout: time.sleep(0.5) try: if self.marionette.find_element(by, locator).is_displayed(): break except NoSuchElementException: pass else: raise TimeoutException('Element %s not visible before timeout' % locator)
Which is called (with the example’s locator) like this:
wait_for_element_displayed(‘css selector’, ‘body.list-mode’)
Another thing you may need to be careful of is the checking of HTML elements. As the App is one large web page there are many many more HTML elements on the page than are visible in the viewport. For interactions like click and tap Marionette will check the visibility of the element before allowing the interaction to take place. However when checking attributes of elements you need to be sure that you are checking the correct element. You could easily be checking an element that’s outside the viewport and irrelevant and in the worst case produce a false positive. Avoiding this is a matter of carefully crafting locators and waits and cross-checking your work before committing running your test.