Mobile devices are becoming important platform for customers and it plays crucial role when it comes for organisation’s digital strategy. And when it’s mobile, there are bunch of variations present; iOS, android, iPad, windows, blackberry, mobile web and so on! With such rapid development going on around these many platforms, we need to have refined end to end high level functional tests for these number of platforms. If such is a case, we would like to have some mechanism in place where we write once and get free for others, unlike Java. The blog post talks about the exact problem and solution we came up with!
Cross platform tests
“Cross platform” refers to idea that means, same test(scenario) can be executed on multiple platforms. This does not have anything to do with your app is pure native/hybrid or combination of both.
One can decide to go for writing cross platform tests, if:
- Similar functionality is present across the different platforms.
- Test suite is covering high level end to end flows. (Minimal number of tests are present at UI layer.)
When any automation suite we go for writing, we have following expectation and cross platform automation is not an exception for this.
- It should take very minimal time to add any new tests.
- It should be very easy accommodate any new changes and hence maintenance.
- It should be very simple and allow us to reuse the code.
Well, Page Object Pattern is natural fit for any application which has workflow and it satisfies above expectations if used in proper way. But how can we have one test which will work for all platforms? And well, we are not the first one to face this problem. People have already faced this problem and came up with solutions like:
These are some of the ways people have tried to write their automation suite. But if we look at all these examples, scenario and step definition(in context with Cucumber features) are common and rest of the part is specific to each platform implementation.
The problem with this approaches is, we are not able to reuse the code as much as possible. Whenever any new test we need to implement, we will need to duplicate same service for respective page object and thus, violating DRY.
Surely, we saw problem with this approach and the root cause of this was different pages being used for different platforms. Solution we came up with is, “One page to test them all!”
The challenge with this approach was, how we can have one page being all different platforms and their behavior is different. We solved these challenges in an iterative way taking one challenge at a time. If we consider android, iOS and mobile web platforms, following are the challenges:
Locating UI elements mechanism is different
As each platform eco-system is different itself, mechanism for identifying each locator is different.
Different UI interaction
UI gesture for each platform is different and so does an API varies provided for same ui interaction.
Different Automation Tools
Currently there is no single tool which can be used for all platforms.
Different UI navigation patterns
Each platform recommends some style guide and UI varies from platform to platform.
We solved above problems one by one and keeping basic automation expectations in mind.
- Locators for each platform
It’s just way of specifying for each platform is different., where I see platform as key and locator as it’s value. Simply as follows, if in Ruby:
- Different UI interaction
Platform specific behaviour will change for each of the ui component on the device. Entering text for textbox will vary for the platform. Well, again it’s just way of specifying the element on the page for different platforms. We have solved specifying locator for each platform already; all we need is an abstraction for each of the UI component.
Eventually there will be other elements like checkbox, button, table, dialog and so on. We can define different behavior as per each component and common behavior for all this can be extracted out to element class.
- Different automation tools
Currently there is no single API which exposes a common API for all these platforms. Although the name seems similar on each of the API, underneath actions are different. This can be solved by defining a module which will do all UI actions and whose responsibility will be defining a common interface for different platform.
With this design in place, our page objects will be platform agnostic and any change in the corresponding API upgrade will not affect the behavior of page objects.
- Different UI Navigation patterns
A classic example of this being Navigation drawer on android, tab bar on ios and menu bar on web. This can be solved by defining abstraction for menu representation and delegating UI actions to common API module. We can have menu as page and menuItems can be a special element type. You can look at the implementation here.
So even if UI elements are different and UI gestures are different, we can define a similar component as an abstraction which will represent all the platform. For example,
Tab bar layout
We can model this in different ways, either we can have each tab as a page and base page will have functionality to navigate to each of the tab or it can be special type of element, where click on each tab will be a transition element.
There are different types of dialog: alert, confirmation, prompt etc. If there are standard dialogs and the behavior is consistent, we can define dialog as element, where any user action on that dialog will be different transition. If dialogs are doing more than just being information, then we can model dialog as different page itself.
Abstracting wait and transition
We saw that set of actions are getting repeated when we are navigating from one page to another page.
- Click on button.
- Wait for next page to load.
- Return the next page when loading is complete.
And whenever we repeat, there is an opportunity of abstracting it. Here, all we need to do is identify the correct class, where we can have this responsibility. We definitely can’t put it in driver as it is responsible for interaction. If we go one level higher, element seem to be correct place for this. Again every element click action does not lead to transition and what we can have in this case is another element type, Transition Aware element!
This element in addition to locator will have knowledge of transition it can lead to. Transition can be of two type, success and error and each can very well have multiple transition in itself. Considering all these requirements, we can specify like this:
One page for all in action
Here we go with one page for all platform, end to end implementation will look like:
Accommodating change in Functional test
We have solved all the concerns we had when we started to think about one page for all platforms. Let’s see how it’s easy to incorporate any change in this approach. In any case, at functional UI layer test, your automation should change only in two of the cases:
- Any change any UI elements. (Element locator change)
- Any change in the existing flow. (Transition change)
“If we want to accommodate these changes in our current framework, it’s a change at single place for all the platforms!”
I presented at Selenium conference on the very similar topic. Find slides here.
Aroj and I paired to build this framework for cross platforms.