← Back to team overview

ubuntu-touch-coreapps-reviewers team mailing list archive

[Merge] lp:~nskaggs/ubuntu-clock-app/update-test-layout into lp:ubuntu-clock-app

 

Nicholas Skaggs has proposed merging lp:~nskaggs/ubuntu-clock-app/update-test-layout into lp:ubuntu-clock-app.

Commit message:
Update testing layout

Requested reviews:
  Ubuntu Clock Developers (ubuntu-clock-dev)

For more details, see:
https://code.launchpad.net/~nskaggs/ubuntu-clock-app/update-test-layout/+merge/262271

Update testing layout
-- 
Your team Ubuntu Clock Developers is requested to review the proposed merge of lp:~nskaggs/ubuntu-clock-app/update-test-layout into lp:ubuntu-clock-app.
=== modified file 'README.autopilot'
--- README.autopilot	2014-08-14 20:16:14 +0000
+++ README.autopilot	2015-06-17 21:00:32 +0000
@@ -2,31 +2,34 @@
 
 Ubuntu Clock App follows a test driven development where autopilot tests are run before every merge into trunk. If you are submitting your bugfix/patch to the clock app, please follow the following steps below to ensure that all tests pass before proposing a merge request.
 
-If you are looking for more info about Autopilot or writing AP tests for the clock app, here are some useful links to help you,
-
-- http://developer.ubuntu.com/api/devel/ubuntu-14.10/python/autopilot/
-- http://developer.ubuntu.com/api/devel/ubuntu-14.10/python/autopilot-emulator/
+If you are looking for more info about Autopilot or writing AP tests for the clock app, here are some useful links to help you:
+
+- http://developer.ubuntu.com/start/quality
+- https://developer.ubuntu.com/api/autopilot/python/1.5.0/
+
+For help and options on running tests, see:
+
+- https://developer.ubuntu.com/en/start/platform/guides/running-autopilot-tests/
 
 ## Prerequisites
 
 Install the following autopilot packages required to run the tests,
-$ sudo apt-get install python-autopilot libautopilot-qt ubuntu-ui-toolkit-autopilot python3-autopilot-vis
-
+$ sudo apt-get install python3-autopilot libautopilot-qt ubuntu-ui-toolkit-autopilot python3-autopilot-vis
 
 ## Running tests on the desktop
 
 Using terminal:
 
 *  Branch the clock app code,
-    $ bzr branch lp:ubuntu-clock-app/reboot
-    
+    $ bzr branch lp:ubuntu-clock-app
+
 *  Build the clock app,
     $ mkdir builddir && cd builddir
     $ cmake .. && make
     $ cd ..
 
 *  Navigate to the tests/autopilot directory.
-    $ cd reboot/tests/autopilot
+    $ cd tests/autopilot
 
 *  run all tests.
     $ autopilot3 run -vv ubuntu_clock_app
@@ -47,4 +50,4 @@
 Using autopkg:
 
 1. navigate to the directory where the ubuntu-clock-app branch is and run:
-  $ adt-run ubuntu-clock-app --click=com.ubuntu.clock.devel --- ssh -s adb
+  $ adt-run ubuntu-clock-app --click=com.ubuntu.clock.devel --- ssh -s adb -p YOURPASSWORD

=== added file 'tests/autopilot/ubuntu_clock_app/CMakePluginParser.py'
--- tests/autopilot/ubuntu_clock_app/CMakePluginParser.py	1970-01-01 00:00:00 +0000
+++ tests/autopilot/ubuntu_clock_app/CMakePluginParser.py	2015-06-17 21:00:32 +0000
@@ -0,0 +1,120 @@
+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
+#
+# Copyright (C) 2014 Canonical Ltd.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; version 3.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Author:
+#   David Planella <david.planella@xxxxxxxxxx>
+
+"""
+This module parses a configuration file from the Qt Creator's CMake plugin and
+enables programmatical read-only access to several of its configuration options
+"""
+
+import sys
+from lxml import etree
+
+
+class CMakePluginParseError(Exception):
+    """
+    Custom exception for errors during the parsing of a
+    CMakeLists.txt.user file
+    """
+    def __init__(self, message):
+        Exception.__init__(self, message)
+
+
+class CMakePluginParser(object):
+    """
+    Parses a CMake plugin's config file and provides R/O access to its
+    configuration options """
+
+    def __init__(self, cmakelists_usr_file='CMakeLists.txt.user'):
+        self.usr_file = cmakelists_usr_file
+
+        try:
+            self.info = etree.parse(self.usr_file)
+        except:
+            sys.stderr.write("Could not open the given " +
+                             "CMakeLists.txt.user file: " + self.info)
+            raise
+
+    def _get_active_build_target(self):
+        """
+        Return the active build target from the current project in Qt Creator
+        """
+
+        try:
+            active_build_target_nr = self.info.xpath(
+                "./data/variable" +
+                "[text()='ProjectExplorer.Project.ActiveTarget']" +
+                "/../value")[0].text
+        except:
+            raise CMakePluginParseError("Could not find the active build " +
+                                        "target in the CMake plugin's config")
+
+        active_build_target = "ProjectExplorer.Project.Target." + \
+            active_build_target_nr
+
+        return active_build_target
+
+    def _get_active_build_config(self, active_build_target):
+        """Return the active build config from the active build targed"""
+
+        try:
+            active_build_config_nr = self.info.xpath(
+                "./data/variable[text()='{0}']".format(active_build_target) +
+                "/..//value[@key="
+                "'ProjectExplorer.Target.ActiveBuildConfiguration']")[0].text
+        except:
+            raise CMakePluginParseError("Could not find the active build " +
+                                        "target's active build config " +
+                                        "in the CMake plugin's config")
+
+        active_build_config = "ProjectExplorer.Target.BuildConfiguration." + \
+            active_build_config_nr
+
+        return active_build_config
+
+    def _get_active_build_config_path(self):
+        """Return the active build config's absolute path"""
+
+        active_build_target = self._get_active_build_target()
+        active_build_config = \
+            self._get_active_build_config(active_build_target)
+
+        try:
+            active_build_config_node = self.info.xpath(
+                "./data/variable[text()='{0}']".format(active_build_target) +
+                "/..//valuemap[@key='{0}']".format(active_build_config))[0]
+        except:
+            raise CMakePluginParseError("Could not find the active " +
+                                        "build config's node " +
+                                        "in the CMake plugin's config")
+
+        try:
+            active_build_config_path = active_build_config_node.xpath(
+                "./value[@key=" +
+                "'ProjectExplorer.BuildConfiguration.BuildDirectory']")[0].text
+        except:
+            raise CMakePluginParseError("Could not find the active build " +
+                                        "directory in the CMake plugin's " +
+                                        "config")
+
+        return active_build_config_path
+
+    @property
+    def active_build_dir(self):
+        """Return the active build config's directory as an absolute path"""
+        return self._get_active_build_config_path()

=== modified file 'tests/autopilot/ubuntu_clock_app/__init__.py'
--- tests/autopilot/ubuntu_clock_app/__init__.py	2014-08-02 12:57:23 +0000
+++ tests/autopilot/ubuntu_clock_app/__init__.py	2015-06-17 21:00:32 +0000
@@ -1,4 +1,6 @@
-# Copyright (C) 2014 Canonical Ltd
+# -#- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -#-
+#
+# Copyright (C) 2014-2015 Canonical Ltd
 #
 # This file is part of Ubuntu Clock App
 #
@@ -14,5 +16,545 @@
 # You should have received a copy of the GNU General Public License
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-
-"""clock-app autopilot tests and emulators - top level package."""
+import logging
+
+from autopilot import logging as autopilot_logging
+from autopilot.introspection import dbus
+from testtools.matchers import GreaterThan
+
+from ubuntuuitoolkit import pickers
+import ubuntuuitoolkit
+
+logger = logging.getLogger(__name__)
+
+
+class ClockEmulatorException(ubuntuuitoolkit.ToolkitException):
+
+    """Exception raised when there is an error with the emulator."""
+
+
+class ClockApp(object):
+
+    """Autopilot helper object for clock."""
+
+    def __init__(self, app_proxy, test_type):
+        self.app = app_proxy
+        self.test_type = test_type
+        self.main_view = self.app.select_single(MainView)
+
+    @property
+    def pointing_device(self):
+        return self.app.pointing_device
+
+
+class MainView(ubuntuuitoolkit.MainView):
+
+    @autopilot_logging.log_action(logger.info)
+    def open_clock(self):
+        """Open the Clock Page.
+
+        :return the Clock Page
+
+        """
+        return self.wait_select_single(ClockPage)
+
+    @autopilot_logging.log_action(logger.info)
+    def open_alarm(self):
+        """Open the Alarm Page.
+
+        :return: the Alarm Page.
+
+        """
+        clockPage = self.open_clock()
+        clockPage.reveal_bottom_edge_page()
+        self.get_header().visible.wait_for(True)
+        return self.wait_select_single(Page11)
+
+    def get_AlarmList(self):
+        """ Get the AlarmList object. """
+        return AlarmList.select(self)
+
+    @autopilot_logging.log_action(logger.info)
+    def get_worldCityList(self):
+        """ Return the World City List page """
+        return self.wait_select_single("WorldCityList",
+                                       objectName="worldCityList")
+
+
+class Page(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
+
+    """Autopilot helper for Pages."""
+
+    def __init__(self, *args):
+        super(Page, self).__init__(*args)
+        # XXX we need a better way to keep reference to the main view.
+        # --elopio - 2014-01-31
+        self.main_view = self.get_root_instance().select_single(MainView)
+
+
+class PageWithBottomEdge(MainView):
+    """
+    An emulator class that makes it easy to interact with the bottom edge
+    swipe page
+    """
+    def __init__(self, *args):
+        super(PageWithBottomEdge, self).__init__(*args)
+
+    def reveal_bottom_edge_page(self):
+        """Bring the bottom edge page to the screen"""
+        self.bottomEdgePageLoaded.wait_for(True)
+        try:
+            action_item = self.wait_select_single(objectName='bottomEdgeTip')
+            action_item.visible.wait_for(True)
+            action_item.isAnimating.wait_for(False)
+            start_x = (action_item.globalRect.x +
+                       (action_item.globalRect.width * 0.5))
+            start_y = (action_item.globalRect.y +
+                       (action_item.height * 0.5))
+            stop_y = start_y - (self.height * 0.7)
+            self.pointing_device.drag(start_x, start_y,
+                                      start_x, stop_y, rate=2)
+            self.isReady.wait_for(True)
+        except dbus.StateNotFoundError:
+            logger.error('BottomEdge element not found.')
+            raise
+
+
+class ClockPage(PageWithBottomEdge):
+    """Autopilot helper for the Clock page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def click_addCity_to_open_worldCityList(self):
+        """Swipe to reveal WorldCityList"""
+
+        addWorldCityButton = self.wait_select_single(
+            "AbstractButton", objectName="addWorldCityButton")
+        self.pointing_device.click_object(addWorldCityButton)
+
+    def get_num_of_saved_cities(self):
+        """Return the number of saved world cities"""
+        return int(self._get_saved_world_city_list().count)
+
+    def _get_saved_world_city_list(self):
+        """Return the saved world city listview object"""
+        return self.wait_select_single(
+            "QQuickRepeater", objectName='userWorldCityRepeater')
+
+    @autopilot_logging.log_action(logger.info)
+    def delete_added_world_city(self, city_Name, country_Name):
+        """ Delete added world city from user world city list """
+        old_cities_count = self.get_num_of_saved_cities()
+        index = 0
+        for index in range(old_cities_count):
+            world_city_item = self.wait_select_single(
+                objectName='userWorldCityItem{}'.format(index))
+            city_name_label = world_city_item.wait_select_single(
+                'Label', objectName='userCityNameText')
+            country_name_label = world_city_item.wait_select_single(
+                'Label', objectName='userCountryNameText')
+            if (city_name_label.text == city_Name and
+                    country_name_label.text == country_Name):
+                self._delete_userWorldCityItem(index)
+
+    # FIXME -----------------------------------------------------------------
+    # Commenting the following lines as deleting a world city when there is
+    # only one in the user world city list does not decrease counter to 0 but
+    # leaves it at 1 so the test fails
+    # Reported bug #1368393
+    # Discovered that deleting world city clock deletes the city from the clock
+    # app, but if you look with autopilot vis the world city is still there
+    # added a comment to bug #1368393
+    #
+    #    try:
+    #        self._get_saved_world_city_list().count.wait_for(
+    #            old_cities_count - 1)
+    #    except AssertionError:
+    #        raise ClockEmulatorException('Error deleting city.')
+    # -------------------------------------------------------------------------
+
+    def _delete_userWorldCityItem(self, index):
+        cityItem = self.wait_select_single(
+            objectName='userWorldCityItem{}'.format(index))
+        self._swipe_to_delete(cityItem)
+        self._confirm_removal(cityItem)
+
+    def _swipe_to_delete(self, cityItem):
+        x, y, width, height = cityItem.globalRect
+        start_x = x + (width * 0.2)
+        stop_x = x + (width * 0.8)
+        start_y = stop_y = y + (height // 2)
+
+        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
+
+    def _confirm_removal(self, cityItem):
+        deleteButton = cityItem.wait_select_single(name='delete')
+        self.pointing_device.click_object(deleteButton)
+
+
+class Page11(Page):
+    """Autopilot helper for the Alarm page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def add_single_alarm(self, name, days, time_to_set, test_sound_name):
+        """Add a single type alarm
+
+        :param name: name of alarm
+        :param days: days on which the alarm should be triggered
+        :param time_to_set: time to set alarm to
+        :param test_sound_name: sound to set in alarm
+
+        """
+        alarmListPage = AlarmList.select(self.main_view)
+        old_alarm_count = alarmListPage.get_num_of_alarms()
+
+        edit_alarm_page = self._click_add_alarm_button()
+        edit_alarm_page.set_alarm_time(time_to_set)
+
+        alarm_repeat_page = edit_alarm_page.open_alarmRepeat_page()
+        alarm_repeat_page.set_alarm_days(days)
+        self._click_header_backButton()
+
+        alarm_label_page = edit_alarm_page.open_alarmLabel_page()
+        alarm_label_page.set_alarm_label(name)
+        self._click_header_customBackButton()
+
+        alarm_sound_page = edit_alarm_page.open_alarmSound_page()
+        alarm_sound_page.set_alarm_sound(test_sound_name)
+        self._click_header_customBackButton()
+        edit_alarm_page._check_sound_changed(test_sound_name)
+
+        self._click_save()
+        self._confirm_alarm_creation(old_alarm_count)
+
+    def _click_add_alarm_button(self):
+        """Click the add alarm header button."""
+        header = self.main_view.get_header()
+        header.click_action_button('addAlarmAction')
+        return self.main_view.wait_select_single(EditAlarmPage)
+
+    def _click_header_customBackButton(self):
+        """Click the  header button:  'customBackButton' """
+        header = self.main_view.get_header()
+        header.click_custom_back_button()
+
+    def _click_header_backButton(self):
+        """Click the  header button:  'backButton' """
+        header = self.main_view.get_header()
+        header.click_back_button()
+
+    def _click_save(self):
+        """Click the save timer header button"""
+        header = self.main_view.get_header()
+        header.click_action_button('saveAlarmAction')
+
+    def _confirm_alarm_creation(self, count):
+        """Confirm creation of alarm
+
+        :param count: alarm count before alarm creation
+
+        """
+        try:
+            AlarmList.select(self.main_view)._get_saved_alarms_list().\
+                count.wait_for(count + 1)
+        except AssertionError:
+            raise ClockEmulatorException('Error creating alarm.')
+
+
+class WorldCityList(Page):
+    """Autopilot helper for World City List page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def add_world_city_from_list(self, city_Name, country_Name):
+        """Add world city from list
+
+        :param city_Name: world city name to add
+        :param country_Name: country city name belongs to (same city name could
+         be found in more countries)
+        """
+        self.wait_select_single("ActivityIndicator").running.wait_for(False)
+        cityList = self.wait_select_single("QQuickListView",
+                                           objectName="cityList")
+
+        cityList.count.wait_for(GreaterThan(0))
+
+        for index in range(int(cityList.count)):
+            world_city_item = self.wait_select_single(
+                objectName='defaultWorldCityItem{}'.format(index))
+            city_name_label = world_city_item.wait_select_single(
+                'Label', objectName='defaultCityNameText')
+            country_name_label = world_city_item.wait_select_single(
+                'Label', objectName='defaultCountryNameText')
+            if (city_name_label.text == city_Name and
+                    country_name_label.text == country_Name):
+                cityList.click_element(
+                    'defaultWorldCityItem{}'.format(index), direction=None)
+                break
+
+    @autopilot_logging.log_action(logger.info)
+    def search_world_city_(self, city_Name, country_Name):
+        """Add world city by searching the world city name
+
+        :param city_Name: world city name to add
+
+        """
+        header = self.main_view.get_header()
+        header.click_action_button("searchButton")
+        self._search_world_city(city_Name, country_Name)
+
+    def _search_world_city(self, city_Name, country_Name):
+        header = self.main_view.get_header()
+        searchTextfield = header.wait_select_single(
+            "TextField", objectName='searchField')
+        searchTextfield.visible.wait_for(True)
+        searchTextfield.write(city_Name)
+
+
+class EditAlarmPage(Page):
+    """Autopilot helper for the Add Alarm page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def set_alarm_time(self, time_to_set):
+        """Set alarm time on datepicker.
+
+        :param time_to_set: time to set on datepicker
+
+        """
+        PickerRow_HoursPicker = self.wait_select_single(
+            "Picker", objectName="PickerRow_HoursPicker")
+        self._set_picker(PickerRow_HoursPicker, 'time', time_to_set)
+
+    def _set_picker(self, field, mode, value):
+        # open picker
+        self.pointing_device.click_object(field)
+        # valid options are date or time; assume date if invalid/no option
+        mode_value = 'Hours|Minutes'
+        picker = self.wait_select_single(
+            pickers.DatePicker, mode=mode_value, visible=True)
+        picker.pick_time(value)
+        # close picker
+        self.pointing_device.click_object(field)
+
+    @autopilot_logging.log_action(logger.info)
+    def open_alarmRepeat_page(self):
+        """ Open the alarmRepeat page """
+
+        alarmRepeatItem = self.wait_select_single(
+            "SubtitledListItem", objectName="alarmRepeat")
+        self.pointing_device.click_object(alarmRepeatItem)
+        return self.main_view.wait_select_single(AlarmRepeat)
+
+    @autopilot_logging.log_action(logger.info)
+    def open_alarmLabel_page(self):
+        """ Open the alarmLabel page """
+
+        alarmLabelItem = self.wait_select_single(
+            "SubtitledListItem", objectName="alarmLabel")
+        self.pointing_device.click_object(alarmLabelItem)
+        return AlarmLable.select(self.main_view)
+
+    @autopilot_logging.log_action(logger.info)
+    def open_alarmSound_page(self):
+        """ Open the alarmSound page """
+
+        alarmSoundItem = self.wait_select_single(
+            "SubtitledListItem", objectName="alarmSound")
+        self.pointing_device.click_object(alarmSoundItem)
+        return self.main_view.wait_select_single(AlarmSound)
+
+    def _check_sound_changed(self, test_sound_name):
+        """ function to check that sound has changed.
+
+        :param test_sound_name = new sound name
+
+        """
+        try:
+            self.wait_select_single(
+                "SubtitledListItem", objectName="alarmSound").subText.wait_for(
+                    test_sound_name)
+        except AssertionError:
+            raise ClockEmulatorException('Error! Incorrect alarm sound')
+
+
+class AlarmRepeat(Page):
+    """Autopilot helper for the  AlarmRepeat page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def set_alarm_days(self, days):
+        """Set the alarm days of the alarm.
+
+        :param days: days on which alarm is triggered
+
+        """
+        self.unselect_selected_days()
+        index = 0
+        for index in range(len(days)):
+            for index2 in range(self._get_num_of_days()):
+                if self.wait_select_single(
+                        'Label', objectName='alarmDay{}'.format(index2)).text\
+                        == days[index]:
+                    self._select_single_alarm_day(index2)
+                    break
+
+    def _get_num_of_days(self):
+        return int(self.wait_select_single(
+            'QQuickRepeater', objectName='alarmDays').count)
+
+    def _select_single_alarm_day(self, index):
+        """ function for selecting the day passed to the function.
+
+        :param index: the day to be selected
+
+        """
+        dayCheckbox = self.wait_select_single(
+            'CheckBox', objectName='daySwitch{}'.format(index))
+        dayCheckbox.check()
+
+    @autopilot_logging.log_action(logger.info)
+    def unselect_selected_days(self):
+        """ function for unselecting already selected days.   """
+        for index in range(self._get_num_of_days()):
+            dayCheckbox = self.wait_select_single(
+                'CheckBox', objectName='daySwitch{}'.format(index))
+            dayCheckbox.uncheck()
+
+
+class AlarmSound(Page):
+    """Autopilot helper for the  AlarmSound page."""
+
+    @autopilot_logging.log_action(logger.info)
+    def set_alarm_sound(self, test_sound_name):
+        """Set alarm sound.
+
+        :param test_sound_name: sound to set for alarm
+
+        """
+        for index in range(self._get_num_of_sounds()):
+            if self.wait_select_single(
+                    'Label', objectName='soundName{}'.format(index)).\
+                    text == test_sound_name:
+                self._select_alarm_sound(index)
+                break
+
+    def _get_num_of_sounds(self):
+        return int(self.wait_select_single(
+            'QQuickRepeater', objectName='alarmSounds').count)
+
+    def _select_alarm_sound(self, index):
+        """ function for selecting the sound passed to the function.
+
+        :param index: the sound to be selected
+
+        """
+        soundCheckbox = self.wait_select_single(
+            'CheckBox', objectName='soundStatus{}'.format(index))
+        soundCheckbox.check()
+
+
+class AlarmLable(object):
+    """Autopilot helper for the  AlarmLabel page."""
+
+    def __init__(self, proxy_object):
+        super(AlarmLable, self).__init__()
+        self.proxy_object = proxy_object
+
+    @classmethod
+    def select(cls, main_view):
+        proxy_object = main_view.wait_select_single(
+            objectName='alarmLabelPage')
+        proxy_object.visible.wait_for(True)
+        return cls(proxy_object)
+
+    @autopilot_logging.log_action(logger.info)
+    def set_alarm_label(self, name):
+        """Set alarm label.
+
+        :param name: label for alarm to set
+
+        """
+        alarmTextfield = self.proxy_object.wait_select_single(
+            "TextField", objectName='labelEntry')
+        # TODO: This wait to ensure that the textfield is visible before
+        # entering text should be part of the SDK emulator. Until then, it has
+        # been added here. http://pad.lv/1289616  --nik90 2014-03-06
+        alarmTextfield.visible.wait_for(True)
+        alarmTextfield.write(name)
+
+
+class AlarmList(object):
+    """Autopilot helper for the  AlarmList."""
+
+    def __init__(self, proxy_object):
+        super(AlarmList, self).__init__()
+        self.proxy_object = proxy_object
+
+    @classmethod
+    def select(cls, main_view):
+        proxy_object = main_view.wait_select_single(
+            'AlarmList', objectName='alarmListView')
+        proxy_object.visible.wait_for(True)
+        return cls(proxy_object)
+
+    def get_num_of_alarms(self):
+        """Return the number of saved alarms."""
+        return int(self._get_saved_alarms_list().count)
+
+    def _get_saved_alarms_list(self):
+        """Return the saved alarm list"""
+        return self.proxy_object
+
+    def get_saved_alarms(self):
+        """Return a list with the information of the saved alarms.
+
+        Each item of the returned list is a tuple of
+        (name, recurrence, time, enabled).
+
+        """
+        alarms = []
+        for index in range(self.get_num_of_alarms()):
+            name = self.proxy_object.wait_select_single(
+                'Label', objectName='listAlarmLabel{}'.format(index)).text
+            recurrence = self.proxy_object.wait_select_single(
+                'Label', objectName='listAlarmSubtitle{}'.format(index)).text
+            time = self.proxy_object.wait_select_single(
+                'Label', objectName='listAlarmTime{}'.format(index)).text
+            enabled = self.proxy_object.wait_select_single(
+                ubuntuuitoolkit.CheckBox,
+                objectName='listAlarmStatus{}'.format(index)).checked
+            alarms.append((name, recurrence, enabled, time))
+        return alarms
+
+    @autopilot_logging.log_action(logger.info)
+    def delete_alarm(self, index):
+        """Delete an alarm at the specified index."""
+        old_alarm_count = self.get_num_of_alarms()
+        alarm = self.proxy_object.wait_select_single(
+            objectName='alarm{}'.format(index))
+
+        alarm.swipe_to_delete()
+        alarm.confirm_removal()
+        try:
+            self._get_saved_alarms_list().count.wait_for(old_alarm_count - 1)
+        except AssertionError:
+            raise ClockEmulatorException('Error deleting alarm.')
+
+
+class ListItemWithActions(
+        ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
+
+    def swipe_to_delete(self):
+        x, y, width, height = self.globalRect
+        start_x = x + (width * 0.2)
+        stop_x = x + (width * 0.8)
+        start_y = stop_y = y + (height // 2)
+
+        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
+
+    def confirm_removal(self):
+        deleteButton = self.wait_select_single(name='delete')
+        self.pointing_device.click_object(deleteButton)
+
+
+class AlarmDelegate(ListItemWithActions):
+
+    def __init__(self, *args):
+        super(AlarmDelegate, self).__init__(*args)

=== removed file 'tests/autopilot/ubuntu_clock_app/emulators.py'
--- tests/autopilot/ubuntu_clock_app/emulators.py	2014-11-25 15:17:21 +0000
+++ tests/autopilot/ubuntu_clock_app/emulators.py	1970-01-01 00:00:00 +0000
@@ -1,546 +0,0 @@
-# -#- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -#-
-#
-# Copyright (C) 2014 Canonical Ltd
-#
-# This file is part of Ubuntu Clock App
-#
-# Ubuntu Clock App is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 3 as
-# published by the Free Software Foundation.
-#
-# Ubuntu Clock App is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-import logging
-
-from autopilot import logging as autopilot_logging
-from autopilot.introspection import dbus
-from testtools.matchers import GreaterThan
-
-from ubuntuuitoolkit import pickers
-import ubuntuuitoolkit
-
-logger = logging.getLogger(__name__)
-
-
-class ClockEmulatorException(ubuntuuitoolkit.ToolkitException):
-
-    """Exception raised when there is an error with the emulator."""
-
-
-class MainView(ubuntuuitoolkit.MainView):
-
-    @autopilot_logging.log_action(logger.info)
-    def open_clock(self):
-        """Open the Clock Page.
-
-        :return the Clock Page
-
-        """
-        return self.wait_select_single(ClockPage)
-
-    @autopilot_logging.log_action(logger.info)
-    def open_alarm(self):
-        """Open the Alarm Page.
-
-        :return: the Alarm Page.
-
-        """
-        clockPage = self.open_clock()
-        clockPage.reveal_bottom_edge_page()
-        self.get_header().visible.wait_for(True)
-        return self.wait_select_single(Page11)
-
-    def get_AlarmList(self):
-        """ Get the AlarmList object. """
-        return AlarmList.select(self)
-
-    @autopilot_logging.log_action(logger.info)
-    def get_worldCityList(self):
-        """ Return the World City List page """
-        return self.wait_select_single("WorldCityList",
-                                       objectName="worldCityList")
-
-
-class Page(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
-
-    """Autopilot helper for Pages."""
-
-    def __init__(self, *args):
-        super(Page, self).__init__(*args)
-        # XXX we need a better way to keep reference to the main view.
-        # --elopio - 2014-01-31
-        self.main_view = self.get_root_instance().select_single(MainView)
-
-
-class PageWithBottomEdge(MainView):
-    """
-    An emulator class that makes it easy to interact with the bottom edge
-    swipe page
-    """
-    def __init__(self, *args):
-        super(PageWithBottomEdge, self).__init__(*args)
-
-    def reveal_bottom_edge_page(self):
-        """Bring the bottom edge page to the screen"""
-        self.bottomEdgePageLoaded.wait_for(True)
-        try:
-            action_item = self.wait_select_single(objectName='bottomEdgeTip')
-            action_item.visible.wait_for(True)
-            action_item.isAnimating.wait_for(False)
-            start_x = (action_item.globalRect.x +
-                       (action_item.globalRect.width * 0.5))
-            start_y = (action_item.globalRect.y +
-                       (action_item.height * 0.5))
-            stop_y = start_y - (self.height * 0.7)
-            self.pointing_device.drag(start_x, start_y,
-                                      start_x, stop_y, rate=2)
-            self.isReady.wait_for(True)
-        except dbus.StateNotFoundError:
-            logger.error('BottomEdge element not found.')
-            raise
-
-
-class ClockPage(PageWithBottomEdge):
-    """Autopilot helper for the Clock page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def click_addCity_to_open_worldCityList(self):
-        """Swipe to reveal WorldCityList"""
-
-        addWorldCityButton = self.wait_select_single(
-            "AbstractButton", objectName="addWorldCityButton")
-        self.pointing_device.click_object(addWorldCityButton)
-
-    def get_num_of_saved_cities(self):
-        """Return the number of saved world cities"""
-        return int(self._get_saved_world_city_list().count)
-
-    def _get_saved_world_city_list(self):
-        """Return the saved world city listview object"""
-        return self.wait_select_single(
-            "QQuickRepeater", objectName='userWorldCityRepeater')
-
-    @autopilot_logging.log_action(logger.info)
-    def delete_added_world_city(self, city_Name, country_Name):
-        """ Delete added world city from user world city list """
-        old_cities_count = self.get_num_of_saved_cities()
-        index = 0
-        for index in range(old_cities_count):
-            world_city_item = self.wait_select_single(
-                objectName='userWorldCityItem{}'.format(index))
-            city_name_label = world_city_item.wait_select_single(
-                'Label', objectName='userCityNameText')
-            country_name_label = world_city_item.wait_select_single(
-                'Label', objectName='userCountryNameText')
-            if (city_name_label.text == city_Name and
-                    country_name_label.text == country_Name):
-                self._delete_userWorldCityItem(index)
-
-    # FIXME -----------------------------------------------------------------
-    # Commenting the following lines as deleting a world city when there is
-    # only one in the user world city list does not decrease counter to 0 but
-    # leaves it at 1 so the test fails
-    # Reported bug #1368393
-    # Discovered that deleting world city clock deletes the city from the clock
-    # app, but if you look with autopilot vis the world city is still there
-    # added a comment to bug #1368393
-    #
-    #    try:
-    #        self._get_saved_world_city_list().count.wait_for(
-    #            old_cities_count - 1)
-    #    except AssertionError:
-    #        raise ClockEmulatorException('Error deleting city.')
-    # -------------------------------------------------------------------------
-
-    def _delete_userWorldCityItem(self, index):
-        cityItem = self.wait_select_single(
-            objectName='userWorldCityItem{}'.format(index))
-        self._swipe_to_delete(cityItem)
-        self._confirm_removal(cityItem)
-
-    def _swipe_to_delete(self, cityItem):
-        x, y, width, height = cityItem.globalRect
-        start_x = x + (width * 0.2)
-        stop_x = x + (width * 0.8)
-        start_y = stop_y = y + (height // 2)
-
-        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
-
-    def _confirm_removal(self, cityItem):
-        deleteButton = cityItem.wait_select_single(name='delete')
-        self.pointing_device.click_object(deleteButton)
-
-
-class Page11(Page):
-    """Autopilot helper for the Alarm page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def add_single_alarm(self, name, days, time_to_set, test_sound_name):
-        """Add a single type alarm
-
-        :param name: name of alarm
-        :param days: days on which the alarm should be triggered
-        :param time_to_set: time to set alarm to
-        :param test_sound_name: sound to set in alarm
-
-        """
-        alarmListPage = AlarmList.select(self.main_view)
-        old_alarm_count = alarmListPage.get_num_of_alarms()
-
-        edit_alarm_page = self._click_add_alarm_button()
-        edit_alarm_page.set_alarm_time(time_to_set)
-
-        alarm_repeat_page = edit_alarm_page.open_alarmRepeat_page()
-        alarm_repeat_page.set_alarm_days(days)
-        self._click_header_backButton()
-
-        alarm_label_page = edit_alarm_page.open_alarmLabel_page()
-        alarm_label_page.set_alarm_label(name)
-        self._click_header_customBackButton()
-
-        alarm_sound_page = edit_alarm_page.open_alarmSound_page()
-        alarm_sound_page.set_alarm_sound(test_sound_name)
-        self._click_header_customBackButton()
-        edit_alarm_page._check_sound_changed(test_sound_name)
-
-        self._click_save()
-        self._confirm_alarm_creation(old_alarm_count)
-
-    def _click_add_alarm_button(self):
-        """Click the add alarm header button."""
-        header = self.main_view.get_header()
-        header.click_action_button('addAlarmAction')
-        return self.main_view.wait_select_single(EditAlarmPage)
-
-    def _click_header_customBackButton(self):
-        """Click the  header button:  'customBackButton' """
-        header = self.main_view.get_header()
-        header.click_custom_back_button()
-
-    def _click_header_backButton(self):
-        """Click the  header button:  'backButton' """
-        header = self.main_view.get_header()
-        header.click_back_button()
-
-    def _click_save(self):
-        """Click the save timer header button"""
-        header = self.main_view.get_header()
-        header.click_action_button('saveAlarmAction')
-
-    def _confirm_alarm_creation(self, count):
-        """Confirm creation of alarm
-
-        :param count: alarm count before alarm creation
-
-        """
-        try:
-            AlarmList.select(self.main_view)._get_saved_alarms_list().\
-                count.wait_for(count + 1)
-        except AssertionError:
-            raise ClockEmulatorException('Error creating alarm.')
-
-
-class WorldCityList(Page):
-    """Autopilot helper for World City List page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def add_world_city_from_list(self, city_Name, country_Name):
-        """Add world city from list
-
-        :param city_Name: world city name to add
-        :param country_Name: country city name belongs to (same city name could
-         be found in more countries)
-        """
-        self.wait_select_single("ActivityIndicator").running.wait_for(False)
-        cityList = self.wait_select_single("QQuickListView",
-                                           objectName="cityList")
-
-        cityList.count.wait_for(GreaterThan(0))
-
-        for index in range(int(cityList.count)):
-            world_city_item = self.wait_select_single(
-                objectName='defaultWorldCityItem{}'.format(index))
-            city_name_label = world_city_item.wait_select_single(
-                'Label', objectName='defaultCityNameText')
-            country_name_label = world_city_item.wait_select_single(
-                'Label', objectName='defaultCountryNameText')
-            if (city_name_label.text == city_Name and
-                    country_name_label.text == country_Name):
-                cityList.click_element(
-                    'defaultWorldCityItem{}'.format(index), direction=None)
-                break
-
-    @autopilot_logging.log_action(logger.info)
-    def search_world_city_(self, city_Name, country_Name):
-        """Add world city by searching the world city name
-
-        :param city_Name: world city name to add
-
-        """
-        header = self.main_view.get_header()
-        header.click_action_button("searchButton")
-        self._search_world_city(city_Name, country_Name)
-
-    def _search_world_city(self, city_Name, country_Name):
-        header = self.main_view.get_header()
-        searchTextfield = header.wait_select_single(
-            "TextField", objectName='searchField')
-        searchTextfield.visible.wait_for(True)
-        searchTextfield.write(city_Name)
-
-
-class EditAlarmPage(Page):
-    """Autopilot helper for the Add Alarm page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def set_alarm_time(self, time_to_set):
-        """Set alarm time on datepicker.
-
-        :param time_to_set: time to set on datepicker
-
-        """
-        PickerRow_HoursPicker = self.wait_select_single(
-            "Picker", objectName="PickerRow_HoursPicker")
-        self._set_picker(PickerRow_HoursPicker, 'time', time_to_set)
-
-    def _set_picker(self, field, mode, value):
-        # open picker
-        self.pointing_device.click_object(field)
-        # valid options are date or time; assume date if invalid/no option
-        mode_value = 'Hours|Minutes'
-        picker = self.wait_select_single(
-            pickers.DatePicker, mode=mode_value, visible=True)
-        picker.pick_time(value)
-        # close picker
-        self.pointing_device.click_object(field)
-
-    @autopilot_logging.log_action(logger.info)
-    def open_alarmRepeat_page(self):
-        """ Open the alarmRepeat page """
-
-        alarmRepeatItem = self.wait_select_single(
-            "SubtitledListItem", objectName="alarmRepeat")
-        self.pointing_device.click_object(alarmRepeatItem)
-        return self.main_view.wait_select_single(AlarmRepeat)
-
-    @autopilot_logging.log_action(logger.info)
-    def open_alarmLabel_page(self):
-        """ Open the alarmLabel page """
-
-        alarmLabelItem = self.wait_select_single(
-            "SubtitledListItem", objectName="alarmLabel")
-        self.pointing_device.click_object(alarmLabelItem)
-        return AlarmLable.select(self.main_view)
-
-    @autopilot_logging.log_action(logger.info)
-    def open_alarmSound_page(self):
-        """ Open the alarmSound page """
-
-        alarmSoundItem = self.wait_select_single(
-            "SubtitledListItem", objectName="alarmSound")
-        self.pointing_device.click_object(alarmSoundItem)
-        return self.main_view.wait_select_single(AlarmSound)
-
-    def _check_sound_changed(self, test_sound_name):
-        """ function to check that sound has changed.
-
-        :param test_sound_name = new sound name
-
-        """
-        try:
-            self.wait_select_single(
-                "SubtitledListItem", objectName="alarmSound").subText.wait_for(
-                    test_sound_name)
-        except AssertionError:
-            raise ClockEmulatorException('Error! Incorrect alarm sound')
-
-
-class AlarmRepeat(Page):
-    """Autopilot helper for the  AlarmRepeat page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def set_alarm_days(self, days):
-        """Set the alarm days of the alarm.
-
-        :param days: days on which alarm is triggered
-
-        """
-        self.unselect_selected_days()
-        index = 0
-        for index in range(len(days)):
-            for index2 in range(self._get_num_of_days()):
-                if self.wait_select_single(
-                        'Label', objectName='alarmDay{}'.format(index2)).text\
-                        == days[index]:
-                    self._select_single_alarm_day(index2)
-                    break
-
-    def _get_num_of_days(self):
-        return int(self.wait_select_single(
-            'QQuickRepeater', objectName='alarmDays').count)
-
-    def _select_single_alarm_day(self, index):
-        """ function for selecting the day passed to the function.
-
-        :param index: the day to be selected
-
-        """
-        dayCheckbox = self.wait_select_single(
-            'CheckBox', objectName='daySwitch{}'.format(index))
-        dayCheckbox.check()
-
-    @autopilot_logging.log_action(logger.info)
-    def unselect_selected_days(self):
-        """ function for unselecting already selected days.   """
-        for index in range(self._get_num_of_days()):
-            dayCheckbox = self.wait_select_single(
-                'CheckBox', objectName='daySwitch{}'.format(index))
-            dayCheckbox.uncheck()
-
-
-class AlarmSound(Page):
-    """Autopilot helper for the  AlarmSound page."""
-
-    @autopilot_logging.log_action(logger.info)
-    def set_alarm_sound(self, test_sound_name):
-        """Set alarm sound.
-
-        :param test_sound_name: sound to set for alarm
-
-        """
-        for index in range(self._get_num_of_sounds()):
-            if self.wait_select_single(
-                    'Label', objectName='soundName{}'.format(index)).\
-                    text == test_sound_name:
-                self._select_alarm_sound(index)
-                break
-
-    def _get_num_of_sounds(self):
-        return int(self.wait_select_single(
-            'QQuickRepeater', objectName='alarmSounds').count)
-
-    def _select_alarm_sound(self, index):
-        """ function for selecting the sound passed to the function.
-
-        :param index: the sound to be selected
-
-        """
-        soundCheckbox = self.wait_select_single(
-            'CheckBox', objectName='soundStatus{}'.format(index))
-        soundCheckbox.check()
-
-
-class AlarmLable(object):
-    """Autopilot helper for the  AlarmLabel page."""
-
-    def __init__(self, proxy_object):
-        super(AlarmLable, self).__init__()
-        self.proxy_object = proxy_object
-
-    @classmethod
-    def select(cls, main_view):
-        proxy_object = main_view.wait_select_single(
-            objectName='alarmLabelPage')
-        proxy_object.visible.wait_for(True)
-        return cls(proxy_object)
-
-    @autopilot_logging.log_action(logger.info)
-    def set_alarm_label(self, name):
-        """Set alarm label.
-
-        :param name: label for alarm to set
-
-        """
-        alarmTextfield = self.proxy_object.wait_select_single(
-            "TextField", objectName='labelEntry')
-        # TODO: This wait to ensure that the textfield is visible before
-        # entering text should be part of the SDK emulator. Until then, it has
-        # been added here. http://pad.lv/1289616  --nik90 2014-03-06
-        alarmTextfield.visible.wait_for(True)
-        alarmTextfield.write(name)
-
-
-class AlarmList(object):
-    """Autopilot helper for the  AlarmList."""
-
-    def __init__(self, proxy_object):
-        super(AlarmList, self).__init__()
-        self.proxy_object = proxy_object
-
-    @classmethod
-    def select(cls, main_view):
-        proxy_object = main_view.wait_select_single(
-            'AlarmList', objectName='alarmListView')
-        proxy_object.visible.wait_for(True)
-        return cls(proxy_object)
-
-    def get_num_of_alarms(self):
-        """Return the number of saved alarms."""
-        return int(self._get_saved_alarms_list().count)
-
-    def _get_saved_alarms_list(self):
-        """Return the saved alarm list"""
-        return self.proxy_object
-
-    def get_saved_alarms(self):
-        """Return a list with the information of the saved alarms.
-
-        Each item of the returned list is a tuple of
-        (name, recurrence, time, enabled).
-
-        """
-        alarms = []
-        for index in range(self.get_num_of_alarms()):
-            name = self.proxy_object.wait_select_single(
-                'Label', objectName='listAlarmLabel{}'.format(index)).text
-            recurrence = self.proxy_object.wait_select_single(
-                'Label', objectName='listAlarmSubtitle{}'.format(index)).text
-            time = self.proxy_object.wait_select_single(
-                'Label', objectName='listAlarmTime{}'.format(index)).text
-            enabled = self.proxy_object.wait_select_single(
-                ubuntuuitoolkit.CheckBox,
-                objectName='listAlarmStatus{}'.format(index)).checked
-            alarms.append((name, recurrence, enabled, time))
-        return alarms
-
-    @autopilot_logging.log_action(logger.info)
-    def delete_alarm(self, index):
-        """Delete an alarm at the specified index."""
-        old_alarm_count = self.get_num_of_alarms()
-        alarm = self.proxy_object.wait_select_single(
-            objectName='alarm{}'.format(index))
-
-        alarm.swipe_to_delete()
-        alarm.confirm_removal()
-        try:
-            self._get_saved_alarms_list().count.wait_for(old_alarm_count - 1)
-        except AssertionError:
-            raise ClockEmulatorException('Error deleting alarm.')
-
-
-class ListItemWithActions(
-        ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
-
-    def swipe_to_delete(self):
-        x, y, width, height = self.globalRect
-        start_x = x + (width * 0.2)
-        stop_x = x + (width * 0.8)
-        start_y = stop_y = y + (height // 2)
-
-        self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
-
-    def confirm_removal(self):
-        deleteButton = self.wait_select_single(name='delete')
-        self.pointing_device.click_object(deleteButton)
-
-
-class AlarmDelegate(ListItemWithActions):
-
-    def __init__(self, *args):
-        super(AlarmDelegate, self).__init__(*args)

=== modified file 'tests/autopilot/ubuntu_clock_app/tests/__init__.py'
--- tests/autopilot/ubuntu_clock_app/tests/__init__.py	2014-11-27 09:12:00 +0000
+++ tests/autopilot/ubuntu_clock_app/tests/__init__.py	2015-06-17 21:00:32 +0000
@@ -24,50 +24,63 @@
 import fixtures
 
 from autopilot import logging as autopilot_logging
-from ubuntuuitoolkit import (
-    base,
-    emulators as toolkit_emulators
-)
+from autopilot.testcase import AutopilotTestCase
+import ubuntuuitoolkit
+from ubuntuuitoolkit import base
 
-from ubuntu_clock_app import emulators, fixture_setup
+import ubuntu_clock_app
+from ubuntu_clock_app import fixture_setup, CMakePluginParser
 
 logger = logging.getLogger(__name__)
 
 
-class ClockAppTestCase(base.UbuntuUIToolkitAppTestCase):
+class ClockAppTestCase(AutopilotTestCase):
 
     """A common test case class that provides several useful methods for
     clock-app tests.
 
     """
 
-    local_location = os.path.dirname(os.path.dirname(os.getcwd()))
-    local_location_qml = os.path.join(local_location,
-                                      'app/ubuntu-clock-app.qml')
-    local_location_backend = os.path.join(local_location, 'builddir/backend')
-    installed_location_backend = ""
-    if glob.glob('/usr/lib/*/qt5/qml/ClockApp'):
-        installed_location_backend = \
-            glob.glob('/usr/lib/*/qt5/qml/ClockApp')[0]
-    installed_location_qml = \
-        '/usr/share/ubuntu-clock-app/ubuntu-clock-app.qml'
-
-    sqlite_dir = os.path.expanduser(
-        "~/.local/share/com.ubuntu.clock")
-    backup_dir = sqlite_dir + ".backup"
-
     def setUp(self):
+        # setup paths
+        self.binary = 'ubuntu-clock-app'
+        self.source_dir = os.path.dirname(
+            os.path.dirname(os.path.abspath('.')))
+        self.build_dir = self._get_build_dir()
+
+        self.local_location = self.build_dir
+        self.local_location_qml = os.path.join(self.build_dir,
+                                          'app', self.binary + '.qml')
+
+        self.local_location_backend = os.path.join(self.local_location,
+                                                   'builddir', 'backend')
+        self.installed_location_backend = ""
+        if glob.glob('/usr/lib/*/qt5/qml/ClockApp'):
+            installed_location_backend = \
+                glob.glob('/usr/lib/*/qt5/qml/ClockApp')[0]
+        self.installed_location_qml = \
+            '/usr/share/ubuntu-clock-app/ubuntu-clock-app.qml'
+
+        self.sqlite_dir = os.path.expanduser(
+            "~/.local/share/com.ubuntu.clock")
+        self.backup_dir = self.sqlite_dir + ".backup"
+
+
         # backup and wipe db's before testing
         self.temp_move_sqlite_db()
         self.addCleanup(self.restore_sqlite_db)
+
+        # setup fixtures and launcher
         self.useFixture(fixture_setup.LocationServiceTestEnvironment())
-        launch, self.test_type = self.get_launcher_method_and_type()
         self.useFixture(fixtures.EnvironmentVariable('LC_ALL', newvalue='C'))
+        self.launcher, self.test_type = self.get_launcher_and_type()
+
+        # launch application under introspection
         super(ClockAppTestCase, self).setUp()
-
-        launch()
-
-    def get_launcher_method_and_type(self):
+        self.app = ubuntu_clock_app.ClockApp(self.launcher(), self.test_type)
+
+
+    def get_launcher_and_type(self):
         if os.path.exists(self.local_location_backend):
             launcher = self.launch_test_local
             test_type = 'local'
@@ -86,7 +99,7 @@
             self.local_location_qml,
             "-I", self.local_location_backend,
             app_type='qt',
-            emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
+            emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
 
     @autopilot_logging.log_action(logger.info)
     def launch_test_installed(self):
@@ -95,13 +108,13 @@
             self.installed_location_qml,
             "-I", self.installed_location_backend,
             app_type='qt',
-            emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
+            emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
 
     @autopilot_logging.log_action(logger.info)
     def launch_test_click(self):
         self.app = self.launch_click_package(
             "com.ubuntu.clock",
-            emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
+            emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
 
     def temp_move_sqlite_db(self):
         try:
@@ -132,6 +145,17 @@
             except:
                 logger.error("Failed to restore database")
 
-    @property
-    def main_view(self):
-        return self.app.wait_select_single(emulators.MainView)
+    def _get_build_dir(self):
+        """
+        Returns the build dir after having parsed the CMake config file
+        generated by Qt Creator. If it cannot find it or it cannot be parsed,
+        an in-tree build is assumed and thus returned.
+        """
+        try:
+            cmake_config = CMakePluginParser.CMakePluginParser(os.path.join(
+                self.source_dir, 'CMakeLists.txt.user'))
+            build_dir = cmake_config.active_build_dir
+        except:
+            build_dir = self.source_dir
+
+        return build_dir


References