📜 ⬆️ ⬇️

Winium: now for Windows Phone


To automate testing under Windows Phone and Windows, there are no convenient and open tools that can be easily adapted to your needs. Those that are closed, limited and offer their own approach, different from the generally accepted standards like Selenium WebDriver.

My colleague skyline-gleb recently wrote on Habré , as we developed our selenium-like tool to automate the functional testing of desktop applications under Windows. In parallel, we have developed a similar tool, only for mobile platforms from Microsoft.

About why we started writing it, what benefits we received from using a single platform to automate testing for all mobile platforms and how to implement it on your project, read this article.

A bit of history



Literally, we introduced our toolkit to Codefest 2015 , where the idea of ​​Winium CodedUi, the implementation of a CodedUI based Selenium driver that supports native and hybrid applications and, most importantly, device testing, was born from a discussion on the sidelines of Badoo from Sathish Gogineni.
')
At the start of the project, there was one open tool - Expensify / WindowsPhoneTestFramework, which did not work for us because it was incompatible with Selenium and had a non-standard API. Moreover, he was sharpened by BDD. During the development of the project, Microsoft managed to release its version of the toolkit - CodedUI, which again had its non-standard API, was sharpened by writing tests in Visual Studio in C #, was closed and paid (which does not scale well).

So, we remembered how events developed. Let's go back to Winium. Since the above tools did not suit us, we decided to write our own. This is how the Winium project was born, which began as a test automation tool for Windows Phone Silverlight applications and soon turned into a whole set of test automation tools for the Windows platform:


About Winium.Desktop and Winium.Cruciatus we already told on habr. And today we will talk about Winium for Store Apps (the successor to Windows Phone Driver) and Winium.StoreApps.CodedUi.

Winium.StoreApps


Main features and driver restrictions

Winium.StoreApps - the main implementation of the driver for mobile devices. We use it and develop it. The source code is open and available on Github .

Main features:


Limitations:


Winium.StoreApps supports all basic Selenium commands and can be embedded into the existing testing infrastructure built on the basis of Selenium / Appium. In general, it can already be actively used in a continuous process, which we are doing.

How it all works

In essence, Winium.StoreApps.Driver.exe is an HTTP server running via the REST protocol JsonWire / WebDriver. If necessary, the incoming driver commands will be proxied to the InnerServer test server embedded in the application under test.


The structure of the interaction between the tests, the driver and the application under test.

How to prepare the application and write tests

To run tests against our application, you must perform three simple steps:


Preparing the application

Everything is simple here: we connect the Winium.StoreApps.InnerServer nuget-package and initialize the automation server on the main thread after the UI is created. For example, in the MainPageOnLoaded method. The server is initialized on the main thread only to get the correct dispatcher. The server will operate on a different thread, except for directly accessing the UI.

After that, it would be good to ensure the testability of the application by writing names and identifiers for those elements that you plan to use in the tests, but this is not necessary.

That's all, it remains only to build the appx-package with your application.

We write tests

Tests are written the same way as for the web or mobile devices using selenium- or appium-bindings.

The first thing we need to do is create a new session. When creating a session, we can specify various desired properties. Here are some basic driver-supported (full list available on wiki ).

dc = { 'deviceName': 'Emulator 8.1 WVGA 4 inch 512MB', 'app': r'C:\YorAppUnderTest.appx', 'files': { { 'C:\AppFiles\file1.png': 'download\file1.png', 'C:\AppFiles\file2.png': 'download\file2.png' } }, 'debugConnectToRunningApp': False } 


So, the session was created, the application was launched. Now we need to somehow find the elements if we want to interact with them. The driver supports the following locators:


To make it easier to find locators and a general understanding of the UI structure of the application under test, we made an inspector who can connect to the application and display the current state of the UI, as the driver sees it.


The main inspector window

The inspector is still able to do a little, but you can already see the screen shot, the UI tree, how the driver sees it, find out the element locators and their main properties: position, visibility, text.

So, we found the element, now we can do anything with it.

 #     element.text #       element.click() #    -   element.send_keys('Hello!'+Keys.ENTER) #       element.get_attribute('Width') #     element.get_attribute('DesiredSize.Width') #     ,      JSON element.get_attribute('DesiredSize') # '{"Width":300.0,"Height":114.0,"IsEmpty":false}' 

In the world of mobile phones, the usual click can not do, here we need gestures. We support the old and proven API from JSWP (but we will soon add support for the new Mobile WebDriver API). Already you can make flick and scrolls.

 TouchActions(driver).flick_element(element, 0, 500, 100).perform() TouchActions(driver).scroll(200,200).perform() #       ActionChains(driver) \ .click_and_hold() \ .move_by_offset(100, 100) \ .release().perform() 

And since we are introducing an automation server into the application, we can also do more interesting things. For example, call MS Acessability API commands:

 # direct use of Windows Phone automation APIs app_bar_button = driver.find_element_by_id('GoAppBarButton') driver.execute_script('automation: invoke', app_bar_button) list_box = driver.find_element_by_id('MyListBox') si = {'v': 'smallIncrement', 'count': 10} driver.execute_script('automation: scroll', list_box, si) 

This allows you to use the exact means of scrolling items instead of simulating gestures if necessary.
And you can also set the value of the public property, although we do not recommend doing this in tests:

 text_box = driver.find_element_by_id('MyTextBox') driver.execute_script('attribute: set', text_box, 'Width', 10) driver.execute_script('attribute: set', text_box, 'Background.Opacity', 0.3) 

But there are situations when it is justified. For example, in our tests - in order to quickly and accurately move the map to the desired position, we just use this API instead of moving the map with gestures.

This is not a complete list of commands supported by the driver. For a more detailed list and notes on the commands, read the wiki .

So, let's build a simple test based on all these commands:

A simple dough code
 # coding: utf-8 import os from selenium.webdriver import Remote from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC class TestAutoSuggestBox(object): def setup_method(self, _): executor = "http://localhost:{}".format(os.environ.get('WINIUM_PORT', 9999)) self.driver = Remote(command_executor=executor, desired_capabilities={'app': 'aut.appx'}) def test_select_suggest(self, waiter): self.driver.execute_script("mobile: OnScreenKeyboard.Disable") pivots = self.driver.find_elements_by_class_name("Windows.UI.Xaml.Controls.Primitives.PivotHeaderItem") pivots[1].click() autosuggestion_box = waiter.until(EC.presence_of_element_located((By.ID, 'MySuggestBox'))) autosuggestion_input = autosuggestion_box.find_element_by_class_name('Windows.UI.Xaml.Controls.TextBox') autosuggestion_input.send_keys('A') suggestions_list = waiter.until(EC.presence_of_element_located((By.XNAME, 'SuggestionsList'))) suggestions = suggestions_list.find_elements_by_class_name('Windows.UI.Xaml.Controls.TextBlock') expected_text = 'A2' for suggest in suggestions: if suggest.text == expected_text: suggest.click() break assert expected_text == autosuggestion_input.text def teardown_method(self, _): self.driver.quit() 


In this example, we are creating a new session. Hide the on-screen keyboard (for demonstration and just not to interfere).

Switch to the second tab in the pivot element. We find there an input field with prompts and begin to enter text. After that, select one of the prompts in the list and check that the value in the input field matches the prompt value. And finally, close the session.

Running tests

It remains the simplest. Launch Winium.StoreApps.Driver.exe (which can be downloaded from GitHub ), run the tests with your favorite tester and enjoy the magic.

Demo .

Winium CodedUI


The main features and limitations of the driver. After Codefest 2015, we had an idea to create a prototype of a selenium-driver wrapping CodedUI. The idea was brought to life and is now available on Github .

Main features:


Limitations:


How it all works

It works on the same principles as in StoreApps, but now instead of implementing the server in the application, we start the server as a separate background process via vs.test.console and CodedUI. This test server has access to the phone and the UI of running applications directly through the Accessibility API (for example, to search for items) and through the CodedUI API (for example, for gestures).


The structure of the interaction between the tests, the driver and the application under test.

How to prepare the application and write tests

Since this approach does not need to change the application being tested, it is possible to test both release versions of applications and pre-installed applications. Those. This driver version is as close as possible to Appium’s philosophy . This is a plus and a minus - because it imposes restrictions on access to some of the internals of the application.
No special preparation of the application is required. Tests are written and run the same way as for Winium.StoreApps.

Watch the demo video in which we automate the creation of an event in the standard pre-installed Calendar application.

Sample code
 from time import sleep from selenium import webdriver from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions from selenium.webdriver.support.wait import WebDriverWait def find_element(driver, by, value): """ :rtype: selenium.webdriver.remote.webelement.WebElement """ return WebDriverWait(driver, 5).until(expected_conditions.presence_of_element_located((by, value))) winium_driver = webdriver.Remote( command_executor='http://localhost:9999', desired_capabilities={ 'deviceName': 'Emulator', 'locale': 'en-US', }) # AutomationId for tiles can not be used to find tile directly, # but can be used to launch apps by switching to window # Actula tile_id is very very very long # {36F9FA1C-FDAD-4CF0-99EC-C03771ED741A}:x36f9fa1cyfdady4cf0y99ecyc03771ed741ax:Microsoft.MSCalendar_8wekyb3d8bbwe!x36f9fa1cyfdady4cf0y99ecyc03771ed741ax # but all we care about is part after last colon winium_driver.switch_to.window('_:_:Microsoft.MSCalendar_8wekyb3d8bbwe!x36f9fa1cyfdady4cf0y99ecyc03771ed741ax') # accept permisson alert if any try: accept_btn = winium_driver.find_element_by_name("allow") accept_btn.click() except NoSuchElementException: pass # now we are in calendar app new_btn = find_element(winium_driver, By.NAME, "new") new_btn.click() sleep(1) # it all happens fast, lets add sleeps subject = find_element(winium_driver, By.ID, "EditCardSubjectFieldSimplified") subject.send_keys(u'Winium Coded UI Demo') sleep(1) # we should have searched for LocationFiled using name or something, but Calendar app uses slightly different # classes for location filed in 8.1 and 8.1 Update, searching by class works on both location = winium_driver.find_elements_by_class_name('TextBox')[1] location.send_keys(u'Your computer') sleep(1) save_btn = find_element(winium_driver, By.NAME, "save") save_btn.click() sleep(2) winium_driver.close() winium_driver.quit() 


What Winium gave us


What did the creation of this tool give us instead of using platform-specific?

Now all our mobile teams use uniform tools, which allows us to easily share experiences and build a unified toolkit and infrastructure to run our tests and not disperse attention across platforms. In particular, one experienced engineer was able to easily transfer from iOS automation to Windows Phone, share experience and train testing engineers, which significantly raised the level of the project.

From an infrastructure point of view, this allowed us to focus on creating a single tool (vmmaster) to provide a repeatable environment for on-demand testing, but this is a topic for a separate article.

But the most important thing is that it allowed us to start integrating our tests for different platforms into one project ( demo ).

In short, now we have ...


And of course, all this opensource, so you can also use this tool to automate the testing of your Windows Phone applications. Moreover, Winium.StoreApps can be used completely free of charge by downloading the latest release and installing emulators or the Visual Studio Community with a mobile SDK. But for Winium.CodedUi you need a paid version of Visual Studio Premium or higher.

Once again the link to the repository and other opensource 2GIS products .

Source: https://habr.com/ru/post/271217/


All Articles