def _wait_for_device_to_ready( self, retry_attempts_count=10, retry_interval=0.1, ): """Wait for UInput device to initialize. This is a workaround for a bug in evdev where the input device is not instantly created. :param retry_attempts_count: number of attempts to check if device is ready. :param retry_interval: time in fractional seconds to be slept, between each attempt to check if device is ready. :raises RuntimeError: if device is not initialized after number of retries specified in *retry_attempts_count*. """ for i in range(retry_attempts_count): device = self._device._find_device() if device: self._device.device = device return else: sleep(retry_interval) raise RuntimeError('Failed to find UInput device.')
def press_and_release(self, key, delay=0.2): """Press and release the key *key*. The 'key' argument must be a string of the single key you want pressed and released. For example:: press_and_release('A') presses then releases the 'A' key. :raises: *ValueError* if the provided key is not supported by the OSK Backend (or the current OSK langauge layout). :raises: *ValueError* if there is more than a single key supplied in the *key* argument. """ if len(self._sanitise_keys(key)) != 1: raise ValueError("Only a single key can be passed in.") try: self._keyboard.press_key(key) sleep(delay) except ValueError as e: e.args += ("OSK Backend is unable to type the key '%s" % key,) raise
def test_mocked_sleep_methods(self): with ElapsedTimeCounter() as time_counter: sleep.enable_mock() self.addCleanup(sleep.disable_mock) sleep(10) self.assertThat(time_counter.elapsed_time, LessThan(2))
def _callable_wait_for(refresh_fn, matcher, timeout): """Like the patched :meth:`wait_for method`, but for callable objects instead of patched variables. """ time_left = timeout while True: new_value = refresh_fn() mismatch = matcher.match(new_value) if mismatch: failure_msg = mismatch.describe() else: return if time_left >= 1: sleep(1) time_left -= 1 else: sleep(time_left) break # can't give a very descriptive message here, especially as refresh_fn # is likely to be a lambda. raise AssertionError("After %.1f seconds test failed: %s" % (timeout, failure_msg))
def _do_timeout(timeout): time_elapsed = 0.0 while timeout - time_elapsed > 0.0: yield time_elapsed time_to_sleep = min(timeout - time_elapsed, 1.0) sleep(time_to_sleep) time_elapsed += time_to_sleep yield time_elapsed
def wait_select_single(self, type_name='*', ap_query_timeout=10, **kwargs): """Get a proxy object matching some search criteria, retrying if no object is found until a timeout is reached. This method is identical to the :meth:`select_single` method, except that this method will poll the application under test for 10 seconds in the event that the search criteria does not match anything. This method will return single proxy object from the introspection tree, with type equal to *type_name* and (optionally) matching the keyword filters present in *kwargs*. You must specify either *type_name*, keyword filters or both. This method searches recursively from the proxy object this method is called on. Calling :meth:`select_single` on the application (root) proxy object will search the entire tree. Calling :meth:`select_single` on an object in the tree will only search it's descendants. Example usage:: app.wait_select_single('QPushButton', objectName='clickme') # returns a QPushButton whose 'objectName' property is 'clickme'. # will poll the application until such an object exists, or will # raise StateNotFoundError after 10 seconds. If nothing is returned from the query, this method raises StateNotFoundError after *ap_query_timeout* seconds. :param type_name: Either a string naming the type you want, or a class of the appropriate type (the latter case is for overridden emulator classes). :param ap_query_timeout: Time in seconds to wait for search criteria to match. :raises ValueError: if the query returns more than one item. *If you want more than one item, use select_many instead*. :raises ValueError: if neither *type_name* or keyword filters are provided. :raises StateNotFoundError: if the requested object was not found. .. seealso:: Tutorial Section :ref:`custom_proxy_classes` """ if ap_query_timeout <= 0: return self._select_single(type_name, **kwargs) for i in range(ap_query_timeout): try: return self._select_single(type_name, **kwargs) except StateNotFoundError: sleep(1) raise StateNotFoundError(type_name, **kwargs)
def perform_move(x, y, sync): fake_input(get_display(), X.MotionNotify, sync, X.CurrentTime, X.NONE, x=int(x), y=int(y)) get_display().sync() sleep(time_between_events)
def tap(self, x, y, press_duration=0.1, time_between_events=0.1): """Click (or 'tap') at given x and y coordinates. :raises RuntimeError: if the finger is already pressed. :raises RuntimeError: if no more finger slots are available. """ _logger.debug("Tapping at: %d,%d", x, y) self.event_delayer.delay(time_between_events) self._finger_down(x, y) sleep(press_duration) self._device.finger_up()
def is_moving(self, gap_interval=0.1): """Check if the element is moving. :param gap_interval: Time in seconds to wait before re-inquiring the object co-ordinates to be able to evaluate if, the element has moved. :return: True, if the element is moving, otherwise False. """ x1, y1, h1, w1 = self._get_default_dbus_object().globalRect sleep(gap_interval) x2, y2, h2, w2 = self._get_secondary_dbus_object().globalRect return x1 != x2 or y1 != y2
def wait_swiped_away(self): # We have to be careful here, because coverPage can go away at any time # if there isn't a lockscreen behind it (it hides completely, then # the greeter disposes it). But if there *is* a lockscreen, then we # need a different check, by looking at its showProgress. So make our # own wait_for loop and check both possibilities. for i in range(10): if not self.required: return coverPage = self.select_single(objectName='coverPage') if coverPage.showProgress == 0: return sleep(1) raise AssertionError("Greeter cover page still up after 10s")
def test_create_group_chat(self): # Open the account panel by tapping the navigation menu icon account_page = self.main_view.account_page account_panel = account_page.open_account_panel() self.assertThat(account_panel.opened, Eventually(Equals(True))) # Select the secret chat option account_panel.select_group_chat() contact_page = self.main_view.apl.contacts_page # Select first contact self.main_view.pointing_device.click_object(contact_page.select_first_online_contact()) # Select second contact self.main_view.pointing_device.click_object(contact_page.select_second_contact()) contact_page.enter_group_chat_title('NewGroupTitle') dialog_list_page = account_page.get_dialog_list_page() # Give chance for app to add the group chat to top of chat list sleep(3) # Select the top chat dialog_list_page.select_dialog_at_index(0) dialog_page = self.main_view.apl.dialog_page message_list = dialog_page.account_message_list inital_count = message_list.messages.count if self.input == "dialog_msgSpecialChar": dialog_page.enter_message(messageTypeSpecialChar) dialog_page.message_area.select_attach_or_send() elif self.input == "dialog_msgUrl": dialog_page.enter_message(messageTypeUrl) dialog_page.message_area.select_attach_or_send() elif self.input == "dialog_msgText": dialog_page.enter_message(messageTypeText) dialog_page.message_area.select_attach_or_send() # Wait for the message to be sent and allow for network latency # Check that the single tick image is displayed for the sent message sleep(1) message = message_list.get_message_at_index(0) self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_received))) # Check that the double tick image is displayed for the read message self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_read)))
def press(self, keys, delay=0.2): """Send key press events only. :param string keys: Keys you want pressed. Example:: press('Alt+F2') presses the 'Alt' and 'F2' keys. """ if not isinstance(keys, str): raise TypeError("'keys' argument must be a string.") _logger.debug("Pressing keys %r with delay %f", keys, delay) for key in self.__translate_keys(keys): self.__perform_on_key(key, X.KeyPress) sleep(delay)
def type(self, string, delay=0.1): """Simulate a user typing a string of text. .. note:: Only 'normal' keys can be typed with this method. Control characters (such as 'Alt' will be interpreted as an 'A', and 'l', and a 't'). """ if not isinstance(string, str): raise TypeError("'keys' argument must be a string.") _logger.debug("Typing text %r", string) for key in string: # Don't call press or release here, as they translate keys to # keysyms. self.__perform_on_key(key, X.KeyPress) sleep(delay) self.__perform_on_key(key, X.KeyRelease) sleep(delay)
def pinch(center, vector_start, vector_end): """Perform a two finger pinch (zoom) gesture. :param center: The coordinates (x,y) of the center of the pinch gesture. :param vector_start: The (x,y) values to move away from the center for the start. :param vector_end: The (x,y) values to move away from the center for the end. The fingers will move in 100 steps between the start and the end points. If start is smaller than end, the gesture will zoom in, otherwise it will zoom out. """ finger_1_start = [center[0] - vector_start[0], center[1] - vector_start[1]] finger_2_start = [center[0] + vector_start[0], center[1] + vector_start[1]] finger_1_end = [center[0] - vector_end[0], center[1] - vector_end[1]] finger_2_end = [center[0] + vector_end[0], center[1] + vector_end[1]] dx = 1.0 * (finger_1_end[0] - finger_1_start[0]) / 100 dy = 1.0 * (finger_1_end[1] - finger_1_start[1]) / 100 finger_1 = Touch.create() finger_2 = Touch.create() finger_1.press(*finger_1_start) finger_2.press(*finger_2_start) finger_1_cur = [finger_1_start[0] + dx, finger_1_start[1] + dy] finger_2_cur = [finger_2_start[0] - dx, finger_2_start[1] - dy] for i in range(0, 100): finger_1.move(*finger_1_cur) finger_2.move(*finger_2_cur) sleep(0.005) finger_1_cur = [finger_1_cur[0] + dx, finger_1_cur[1] + dy] finger_2_cur = [finger_2_cur[0] - dx, finger_2_cur[1] - dy] finger_1.move(*finger_1_end) finger_2.move(*finger_2_end) finger_1.release() finger_2.release()
def press(self, keys, delay=0.1): """Send key press events only. The 'keys' argument must be a string of keys you want pressed. For example: press('Alt+F2') presses the 'Alt' and 'F2' keys. :raises TypeError: if ``keys`` is not a string. """ if not isinstance(keys, str): raise TypeError("'keys' argument must be a string.") for key in self._sanitise_keys(keys): for key_button in self._get_key_buttons(key): self._device.press(key_button) sleep(delay)
def release(self, keys, delay=0.2): """Send key release events only. :param string keys: Keys you want released. Example:: release('Alt+F2') releases the 'Alt' and 'F2' keys. """ if not isinstance(keys, str): raise TypeError("'keys' argument must be a string.") _logger.debug("Releasing keys %r with delay %f", keys, delay) # release keys in the reverse order they were pressed in. keys = self.__translate_keys(keys) keys.reverse() for key in keys: self.__perform_on_key(key, X.KeyRelease) sleep(delay)
def wait_until_destroyed(self, timeout=10): """Block until this object is destroyed in the application. Block until the object this instance is a proxy for has been destroyed in the applicaiton under test. This is commonly used to wait until a UI component has been destroyed. :param timeout: The number of seconds to wait for the object to be destroyed. If not specified, defaults to 10 seconds. :raises RuntimeError: if the method timed out. """ for i in range(timeout): try: self._get_new_state() sleep(1) except StateNotFoundError: return else: raise RuntimeError("Object was not destroyed after %d seconds" % timeout)
def test_verify_profile_details(self): # Open the account panel by tapping the navigation menu icon account_page = self.main_view.account_page account_panel = account_page.open_account_panel() self.assertThat(account_panel.opened, Eventually(Equals(True))) # Select Contacts option account_panel.select_contacts() #Select first contact contact_page = self.main_view.apl.contacts_page contact = contact_page.select_contact_at_index(0) self.main_view.pointing_device.click_object(contact) self.main_view.apl.dialog_page.select_chat_info() profile_page = self.main_view.apl.profile_page # print(profile_page.profile_user_photo.get_properties()) # print("IMAGE SRC: " + profile_page.profile_user_photo.source) sleep(3) if profile_page.select_user_photo() is None: #User does not have a profile image print('WARNING - Profiles - Contact does not have Profile image') else: self.assertThat(profile_page.select_user_photo() is not None, Equals(True)) # Check the user has a name if profile_page.profile_user_name.text is None: raise RuntimeError("Profiles - Contact does not have Name") # Check the user has a phone number if profile_page.profile_user_phone_number.text is None: raise RuntimeError( "Profiles - Contact does not have valid Phone Number")
def test_total_time_slept_accumulates(self): with sleep.mocked() as sleep_counter: sleep(1) self.assertThat(sleep_counter.total_time_slept(), Equals(1.0)) sleep(0.5) self.assertThat(sleep_counter.total_time_slept(), Equals(1.5)) sleep(0.5) self.assertThat(sleep_counter.total_time_slept(), Equals(2.0))
def _move_with_animation(self, x, y, rate, time_between_events): current_x, current_y = self.x, self.y while current_x != x or current_y != y: dx = abs(x - current_x) dy = abs(y - current_y) intx = float(dx) / max(dx, dy) inty = float(dy) / max(dx, dy) step_x = min(rate * intx, dx) step_y = min(rate * inty, dy) if x < current_x: step_x *= -1 if y < current_y: step_y *= -1 current_x += step_x current_y += step_y self._device.finger_move(current_x, current_y) sleep(time_between_events)
def release(self, keys, delay=0.1): """Send key release events only. The 'keys' argument must be a string of keys you want released. For example: release('Alt+F2') releases the 'Alt' and 'F2' keys. Keys are released in the reverse order in which they are specified. :raises TypeError: if ``keys`` is not a string. :raises ValueError: if one of the keys to be released is not pressed. """ if not isinstance(keys, str): raise TypeError("'keys' argument must be a string.") for key in reversed(self._sanitise_keys(keys)): for key_button in reversed(self._get_key_buttons(key)): self._device.release(key_button) sleep(delay)
def test_create_basic_chat(self): # Open the account panel by tapping the navigation menu icon account_page = self.main_view.account_page account_panel = account_page.open_account_panel() self.assertThat(account_panel.opened, Eventually(Equals(True))) # Select Contacts option account_panel.select_contacts() #Select first contact contact_page = self.main_view.apl.contacts_page self.main_view.pointing_device.click_object(contact_page.select_first_online_contact()) dialog_page = self.main_view.apl.dialog_page message_list = dialog_page.account_message_list inital_count = message_list.messages.count if self.input == "dialog_msgSpecialChar": dialog_page.enter_message(messageTypeSpecialChar) dialog_page.message_area.select_attach_or_send() elif self.input == "dialog_msgUrl": dialog_page.enter_message(messageTypeUrl) dialog_page.message_area.select_attach_or_send() elif self.input == "dialog_msgText": dialog_page.enter_message(messageTypeText) dialog_page.message_area.select_attach_or_send() # Check that the single tick image is displayed for the sent message sleep(1) message = message_list.get_message_at_index(0) self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_received))) # Check that the double tick image is displayed for the read message self.assertThat(message.message_status_image.source, Eventually(Equals(message_status_read)))
def wait_select_many(self, type_name='*', ap_query_timeout=10, ap_result_count=1, ap_result_sort_keys=None, **kwargs): """Get a list of nodes from the introspection tree, with type equal to *type_name* and (optionally) matching the keyword filters present in *kwargs*. This method is identical to the :meth:`select_many` method, except that this method will poll the application under test for *ap_query_timeout* seconds in the event that the search result count is not greater than or equal to *ap_result_count*. You must specify either *type_name*, keyword filters or both. This method searches recursively from the instance this method is called on. Calling :meth:`wait_select_many` on the application (root) proxy object will search the entire tree. Calling :meth:`wait_select_many` on an object in the tree will only search it's descendants. Example Usage:: app.wait_select_many( 'QPushButton', ap_query_timeout=5, ap_result_count=2, enabled=True ) # returns at least 2 QPushButtons that are enabled, within # 5 seconds. .. warning:: The order in which objects are returned is not guaranteed. It is bad practise to write tests that depend on the order in which this method returns objects. (see :ref:`object_ordering` for more information). :param type_name: Either a string naming the type you want, or a class of the appropriate type (the latter case is for overridden emulator classes). :param ap_query_timeout: Time in seconds to wait for search criteria to match. :param ap_result_count: Minimum number of results to return. :param ap_result_sort_keys: list of object properties to sort the query result with (sort key priority starts with element 0 as highest priority and then descends down the list). :raises ValueError: if neither *type_name* or keyword filters are provided. Also raises, if search result count does not match the number specified by *ap_result_count* within *ap_query_timeout* seconds. .. seealso:: Tutorial Section :ref:`custom_proxy_classes` """ exception_message = 'Failed to find the requested number of elements.' if ap_query_timeout <= 0: instances = self._select_many(type_name, **kwargs) if len(instances) < ap_result_count: raise ValueError(exception_message) return sort_by_keys(instances, ap_result_sort_keys) for i in range(ap_query_timeout): instances = self._select_many(type_name, **kwargs) if len(instances) >= ap_result_count: return sort_by_keys(instances, ap_result_sort_keys) sleep(1) raise ValueError(exception_message)
def test_unmocked_sleep_calls_real_time_sleep_function(self): with patch('autopilot.utilities.time') as patched_time: sleep(1.0) patched_time.sleep.assert_called_once_with(1.0)
def test_mocked_sleep_contextmanager(self): with ElapsedTimeCounter() as time_counter: with sleep.mocked(): sleep(10) self.assertThat(time_counter.elapsed_time, LessThan(2))
def crashing_fn(): for i in range(10): logger.debug("%d %r", i, app_proxy.refresh_state()) sleep(1)
def wait_for(self, expected_value, timeout=10): """Wait up to 10 seconds for our value to change to *expected_value*. *expected_value* can be a testtools.matcher. Matcher subclass (like LessThan, for example), or an ordinary value. This works by refreshing the value using repeated dbus calls. :raises AssertionError: if the attribute was not equal to the expected value after 10 seconds. :raises RuntimeError: if the attribute you called this on was not constructed as part of an object. """ # It's guaranteed that our value is up to date, since __getattr__ # calls refresh_state. This if statement stops us waiting if the # value is already what we expect: if self == expected_value: return if self.name is None or self.parent is None: raise RuntimeError( "This variable was not constructed as part of " "an object. The wait_for method cannot be used.") def make_unicode(value): if isinstance(value, bytes): return value.decode('utf8') return value if hasattr(expected_value, 'expected'): expected_value.expected = make_unicode(expected_value.expected) # unfortunately not all testtools matchers derive from the Matcher # class, so we can't use issubclass, isinstance for this: match_fun = getattr(expected_value, 'match', None) is_matcher = match_fun and callable(match_fun) if not is_matcher: expected_value = Equals(expected_value) time_left = timeout while True: # TODO: These next three lines are duplicated from the parent... # can we just have this code once somewhere? _, new_state = self.parent._get_new_state() new_state = translate_state_keys(new_state) new_value = new_state[self.name][1:] if len(new_value) == 1: new_value = make_unicode(new_value[0]) # Support for testtools.matcher classes: mismatch = expected_value.match(new_value) if mismatch: failure_msg = mismatch.describe() else: self.parent._set_properties(new_state) return if time_left >= 1: sleep(1) time_left -= 1 else: sleep(time_left) break raise AssertionError( "After %.1f seconds test on %s.%s failed: %s" % (timeout, self.parent.__class__.__name__, self.name, failure_msg))
def test_check_blocked_user(self): # Open the account panel by tapping the navigation menu icon account_page = self.main_view.account_page account_panel = account_page.open_account_panel() self.assertThat(account_panel.opened, Eventually(Equals(True))) # Select Contacts option account_panel.select_contacts() #Select first contact contacts_page = self.main_view.apl.contacts_page recipient = contacts_page.select_first_online_contact() self.main_view.pointing_device.click_object(recipient) dialog_page = self.main_view.apl.dialog_page message_list = dialog_page.account_message_list inital_count = message_list.messages.count #Send message dialog_page.enter_message(messageTypeText) dialog_page.message_area.select_attach_or_send() #Check received reply self.assertThat(message_list.messages.count, Eventually(Equals(inital_count + 2))) #Tap the groupInfo button self.main_view.apl.dialog_page.select_chat_info() #Assign ProfilePage profile_page = self.main_view.apl.profile_page #Turn on Block contact switch = profile_page.switch_block self.main_view.pointing_device.click_object(switch) #Verify blocked user switch is turned ON self.assertThat(switch.checked, Equals(True)) #Go back to dialog page profile_page.select_back_button() self.main_view.apl.clear_profile_page() #Send message dialog_page.enter_message(messageTypeText) dialog_page.message_area.select_attach_or_send() # Check that the sent message was read message = None for idx in range(0, message_list.messages.count): message = message_list.get_message_at_index(idx) if message.message_label.text == messageTypeText: self.assertThat( message.message_status_image.source, Eventually( Equals("qrc:/qml/files/check_double_green.png"))) break else: message = None self.assertThat(message is None, Equals(False)) # Check that no response was received (wait for 10 seconds) sleep(10) self.assertThat(message_list.messages.count, Equals(inital_count + 3)) #Tap the groupInfo button self.main_view.apl.dialog_page.select_chat_info() #Assign ProfilePage profile_page = self.main_view.apl.profile_page #Turn off Block contact. switch = profile_page.switch_block self.assertThat(switch.checked, Eventually(Equals(True))) self.main_view.pointing_device.click_object(switch) #Verify blocked user switch is turned OFF self.assertThat(switch.checked, Eventually(Equals(False))) #Go back to dialog page profile_page.select_back_button() #Check number of messages and send message self.assertThat(message_list.messages.count, Equals(inital_count + 3)) #Send message dialog_page.enter_message(messageTypeText) dialog_page.message_area.select_attach_or_send() #Check received reply self.assertThat(message_list.messages.count, Eventually(Equals(inital_count + 5)))
def click(self, button=1, press_duration=0.10, time_between_events=0.1): """Click mouse at current location.""" self.event_delayer.delay(time_between_events) self.press(button) sleep(press_duration) self.release(button)
def test_SecretMessage(self): # Note the number of dialogs in the dialog list at the start of the test account_page = self.main_view.account_page dialog_list_page = account_page.get_dialog_list_page() count = dialog_list_page.dialog_count # Open the account panel by tapping the navigation menu icon account_panel = account_page.open_account_panel() self.assertThat(account_panel.opened, Eventually(Equals(True))) # Select the secret chat option account_panel.select_secret_chat() # Select an online contact apl = self.main_view.apl contacts_page = apl.contacts_page recipient = contacts_page.select_first_online_contact() self.main_view.pointing_device.click_object(recipient) # Create a new secret chat self.assertThat(count, Eventually(Equals(count + 1))) dialog_list_page.select_dialog_at_index(0) dialog_page = apl.dialog_page # Check that only system message is being displayed message_list = dialog_page.account_message_list initial_count = message_list.messages.count self.assertThat(initial_count, Equals(1)) status_received = message_received_image status_read = message_read_image if "textMessage" in self.input or self.input == "photoMessageReceive": # Send the first message ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime( '%y:%m:%d,%H:%M:%S') message_to_send = "Autopilot:" + timestamp if self.input == "textMessageSend": message_to_send = message_to_send + " DO NOT REPLY" elif self.input == "photoMessageReceive": message_to_send = message_to_send + " SEND IMAGE" dialog_page.enter_message(message_to_send) dialog_page.message_area.select_attach_or_send() elif self.input == "photoMessageSend": if platform.model() == "Desktop": return dialog_page.message_area.select_attach_or_send() dialog_page.message_area.select_attach_photo_option() self.main_view.select_content_hub_app("Camera") # Allow time to open the app sleep(5) display = Display.create() screen_width = display.get_screen_width() screen_height = display.get_screen_height() button_x_pos = screen_width / 2.0 button_y_pos = screen_height - 100.0 # Click on the take photo button self.main_view.pointing_device.move(button_x_pos, button_y_pos) self.main_view.pointing_device.click() # Allow time to take the photo sleep(5) # Tap the tick to return to Telegram self.main_view.pointing_device.move(button_x_pos, button_y_pos) self.main_view.pointing_device.click() status_received = media_received_image status_read = media_read_image # Allow time for photo to be sent sleep(30) # Check that sent message appears in the dialog content self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 1))) # Check that the message received image is displayed for the sent message index_of_sent_message = 0 message = message_list.get_message_at_index(index_of_sent_message) status_image = message.message_status_image if self.input != "photoMessageSend": self.assertThat(status_image.source, Eventually(Equals(status_received))) if "Receive" in self.input: index_of_sent_message = index_of_sent_message + 1 # Check for reply self.assertThat(message_list.messages.count, Eventually(Equals(initial_count + 2))) # Check that the message read image is displayed for the sent message message = message_list.get_message_at_index(index_of_sent_message) status_image = message.message_status_image if self.input == "photoMessageSend" and platform.model() != "Desktop": status_image = message.account_message_media.media_message_status_image self.assertThat(status_image.source, Eventually(Equals(status_read)))