Merge lp:~nskaggs/ubuntu-calculator-app/ap-fix-missing-keypress into lp:~ubuntu-calculator-dev/ubuntu-calculator-app/old_trunk

Proposed by Nicholas Skaggs
Status: Merged
Approved by: Nicholas Skaggs
Approved revision: 341
Merged at revision: 323
Proposed branch: lp:~nskaggs/ubuntu-calculator-app/ap-fix-missing-keypress
Merge into: lp:~ubuntu-calculator-dev/ubuntu-calculator-app/old_trunk
Diff against target: 1349 lines (+639/-492)
6 files modified
Simple/SimplePage.qml (+1/-0)
tests/autopilot/ubuntu_calculator_app/__init__.py (+332/-7)
tests/autopilot/ubuntu_calculator_app/emulators.py (+0/-282)
tests/autopilot/ubuntu_calculator_app/tests/__init__.py (+156/-72)
tests/autopilot/ubuntu_calculator_app/tests/test_screen.py (+91/-0)
tests/autopilot/ubuntu_calculator_app/tests/test_simple_page.py (+59/-131)
To merge this branch: bzr merge lp:~nskaggs/ubuntu-calculator-app/ap-fix-missing-keypress
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Leo Arias (community) Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Review via email: mp+233534@code.launchpad.net

Commit message

Increase the keypress duration to avoid missing pressing keys.

Description of the change

A simple tweak to increase the keypress duration to avoid missing pressing keys. We should still consider tweaking how we perform operations.

To post a comment you must log in.
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Leo Arias (elopio) :
Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Thanks Leo, left my replies. I'm really trying to not go overboard on redoing this, but it's easy to start that direction.

Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

All the tests now pass locally and on the device, albeit with the extra attempt. Now to track down why the app isn't capturing the press.

Revision history for this message
Nicholas Skaggs (nskaggs) wrote :

Note, althought some things are converted and some cleanups done, I attempted to keep this as simple as possible. Another MP can bring this inline with current best practices.

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Leo Arias (elopio) wrote :

228 + self.pointing_device.press()
229 + buttonarea.pressed.wait_for(True)
230 + self.pointing_device.release()

Could you please put a comment there explaining why calling self.pointing_device.click_object does not work on this case?

341. By Nicholas Skaggs

add comment explaining use of _click_button

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Approve (continuous-integration)
Revision history for this message
Leo Arias (elopio) :
review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'Simple/SimplePage.qml'
2--- Simple/SimplePage.qml 2014-09-02 07:00:29 +0000
3+++ Simple/SimplePage.qml 2014-09-08 19:35:18 +0000
4@@ -45,6 +45,7 @@
5 property variant keyboardButtons: null
6
7 id: page
8+ objectName: "simplepage"
9
10 function formulaPush(visual) {
11 //If first character in number is dot, then add zero before
12
13=== modified file 'tests/autopilot/ubuntu_calculator_app/__init__.py'
14--- tests/autopilot/ubuntu_calculator_app/__init__.py 2013-03-22 12:15:46 +0000
15+++ tests/autopilot/ubuntu_calculator_app/__init__.py 2014-09-08 19:35:18 +0000
16@@ -1,8 +1,333 @@
17 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
18-# Copyright 2013 Canonical
19-#
20-# This program is free software: you can redistribute it and/or modify it
21-# under the terms of the GNU General Public License version 3, as published
22-# by the Free Software Foundation.
23-
24-"""Autopilot tests and emulators for calculator - top level package."""
25+#
26+# Copyright (C) 2013 Canonical Ltd.
27+#
28+# This program is free software; you can redistribute it and/or modify
29+# it under the terms of the GNU Lesser General Public License as published by
30+# the Free Software Foundation; version 3.
31+#
32+# This program is distributed in the hope that it will be useful,
33+# but WITHOUT ANY WARRANTY; without even the implied warranty of
34+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35+# GNU Lesser General Public License for more details.
36+#
37+# You should have received a copy of the GNU Lesser General Public License
38+# along with this program. If not, see <http://www.gnu.org/licenses/>.
39+
40+"""Calculator app autopilot emulators."""
41+
42+import logging
43+
44+import autopilot.logging
45+from autopilot.introspection import dbus
46+
47+import ubuntuuitoolkit
48+
49+logger = logging.getLogger(__name__)
50+
51+
52+class CalculatorException(ubuntuuitoolkit.ToolkitException):
53+
54+ """Exception raised when there are problems with the Calculator."""
55+
56+
57+class CalculatorApp(object):
58+
59+ """Autopilot helper object for the terminal application."""
60+
61+ def __init__(self, app_proxy, test_type):
62+ self.app = app_proxy
63+ self.test_type = test_type
64+ self.main_view = self.app.select_single(MainView)
65+
66+ @property
67+ def pointing_device(self):
68+ return self.app.pointing_device
69+
70+
71+class MainView(ubuntuuitoolkit.MainView):
72+ """Calculator MainView Autopilot emulator."""
73+
74+ # TODO when we start the tests for the scientific calculator, many of this
75+ # methods will have to be moved to the SimplePage emulator, and the main
76+ # view can call them depending on the current page displayed.
77+ # --elopio - 2013-08-08
78+
79+ def __init__(self, *args):
80+ super(MainView, self).__init__(*args)
81+ self.visible.wait_for(True)
82+
83+ def get_simple_page(self):
84+ return self.select_single('SimplePage', objectName='simplepage')
85+
86+ def clear_with_button(self):
87+ """Clear the calculation using the clear button."""
88+ self.get_calc_keyboard().click_clear()
89+
90+ def get_calc_keyboard(self):
91+ """Return the CalcKeyboard autopilot emulator."""
92+ return self.select_single(CalcKeyboard)
93+
94+ def calculate_operation(self, operation):
95+ """Calculate an operation.
96+
97+ :parameter operation: A string with the operation to calculate.
98+
99+ """
100+ self.enter_operation(operation)
101+ self.get_calc_keyboard().click_equals()
102+
103+ def enter_operation(self, operation):
104+ """Enter an operation.
105+
106+ :parameter operation: A string with the operation to enter.
107+
108+ """
109+ self.get_calc_keyboard().enter_operation(operation)
110+
111+ def change_sign(self):
112+ """Change the sign of the last operand."""
113+ self.get_calc_keyboard().click_sign()
114+
115+ def get_result(self):
116+ """Return the result of a calculation."""
117+ return self.get_current_screen().get_result()
118+
119+ def get_current_screen(self):
120+ """Return the screen for the current calculation."""
121+ count = self.get_number_of_screens()
122+ return self.select_many(Screen)[count - 1]
123+
124+ def get_operand_by_index(self, index):
125+ """Return an operand of a calculation entered."""
126+ return self.get_current_screen().get_operand_by_index(index)
127+
128+ def clear_with_swipe(self):
129+ """Clear the calculation making a swipe on the screen."""
130+ self.get_current_screen().swipe_up()
131+ self._wait_for_screen_to_finish_animation()
132+
133+ def _wait_for_screen_to_finish_animation(self):
134+ qquicklistview = self.select_single('QQuickListView')
135+ qquicklistview.moving.wait_for(False)
136+
137+ def is_cleared(self):
138+ """Return True if the screen has no calculation. False otherwise."""
139+ return self.get_current_screen().is_cleared()
140+
141+ def get_screen_by_index(self, index):
142+ """Return a screen."""
143+ return self._get_screens()[index]
144+
145+ def _get_screens(self):
146+ return self.select_many(Screen)
147+
148+ def get_number_of_screens(self):
149+ """Return the number of screens."""
150+ return len(self._get_screens())
151+
152+ def swipe_previous_calculation_into_view(self, screen_index):
153+ previous_screen = self.get_screen_by_index(screen_index)
154+ _, prev_screen_y, _, prev_screen_h = previous_screen.globalRect
155+ x, y, w, h = self.globalRect
156+ start_x = stop_x = x + w / 2
157+ start_y = y + h / 2
158+ stop_y = start_y + y - prev_screen_y
159+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
160+ self._wait_for_screen_to_finish_animation()
161+
162+ def delete_previous_calculation(self, screen_index, confirm):
163+ """Delete an old calculation.
164+
165+ :parameter screen_index: If index of the screen with the calculation
166+ to delete.
167+ :parameter confirm: If True, the deletion will be confimed. If False,
168+ it will be canceled.
169+
170+ """
171+ self.swipe_previous_calculation_into_view(screen_index)
172+ screen = self.get_screen_by_index(screen_index)
173+ screen.swipe_to_delete()
174+ self._wait_for_screen_to_finish_animation()
175+ if confirm:
176+ screen.confirm_removal()
177+ else:
178+ raise NotImplementedError('Not yet implemented.')
179+
180+
181+class CalcKeyboard(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
182+ """CalcKeyboard Autopilot emulator."""
183+
184+ _BUTTONS_DICT = {
185+ "0": "zeroButton",
186+ "1": "oneButton",
187+ "2": "twoButton",
188+ "3": "threeButton",
189+ "4": "fourButton",
190+ "5": "fiveButton",
191+ "6": "sixButton",
192+ "7": "sevenButton",
193+ "8": "eightButton",
194+ "9": "nineButton",
195+ "+": "plusButton",
196+ "-": "minusButton",
197+ "/": "divideButton",
198+ "*": "multiplyButton",
199+ '.': "pointButton",
200+ }
201+
202+ def __init__(self, *args):
203+ super(CalcKeyboard, self).__init__(*args)
204+
205+ @autopilot.logging.log_action(logger.info)
206+ def click_clear(self):
207+ """Click the clear button."""
208+ clear_button = self._get_keyboard_button('clearButton')
209+ self._click_button(clear_button)
210+
211+ def _get_keyboard_button(self, objectName):
212+ return self.select_single('KeyboardButton', objectName=objectName)
213+
214+ def enter_operation(self, operation):
215+ """Enter an operation on the calculator.
216+
217+ :parameter operation: A string with the operation to enter.
218+
219+ """
220+ for char in operation:
221+ button = self._get_keyboard_button(self._BUTTONS_DICT[char])
222+ self._click_button(button)
223+
224+ def _click_button(self, button):
225+ logger.debug("Pressing %s button", button.text)
226+ buttonarea = button.select_single('QQuickMouseArea')
227+ self.pointing_device.move_to_object(button)
228+ # we use press and release so we can check the qml property
229+ # and ensure the button is pressed long enough to be recieved
230+ # and processed correctly
231+ # using a larger press_duration for click_object would be inferior
232+ # as it would cause longer delays (we are forced to arbitrarily decide
233+ # how long to press each time) and potentially fail.
234+ # Also, https://bugs.launchpad.net/autopilot/+bug/1366949
235+ # causes press_duration argument to be ignored currently
236+ # balloons 2014-09-08
237+ self.pointing_device.press()
238+ buttonarea.pressed.wait_for(True)
239+ self.pointing_device.release()
240+
241+ @autopilot.logging.log_action(logger.info)
242+ def click_equals(self):
243+ """Click the equals button."""
244+ equals_button = self._get_keyboard_button('equalsButton')
245+ self._click_button(equals_button)
246+
247+ @autopilot.logging.log_action(logger.info)
248+ def click_sign(self):
249+ """Click the sign button."""
250+ sign_button = self._get_keyboard_button('signButton')
251+ self._click_button(sign_button)
252+
253+
254+class Screen(ubuntuuitoolkit.listitems.Standard):
255+ """Screen Autopilot emulator."""
256+
257+ def __init__(self, *args):
258+ super(Screen, self).__init__(*args)
259+
260+ def _wait_for_screen_to_finish_animation(self):
261+ flickables = self.select_many('QQuickFlickable')
262+ for animation in flickables:
263+ animation.moving.wait_for(False)
264+
265+ def _click_screen_object(self, screen_object):
266+ self._wait_for_screen_to_finish_animation()
267+ self.pointing_device.click_object(screen_object)
268+
269+ def get_result(self):
270+ """Return the result of a calculation."""
271+ result_label = self.get_result_label()
272+ assert result_label is not None, 'No result displayed.'
273+ return result_label.numbers
274+
275+ def get_result_label(self):
276+ try:
277+ return self.select_single(
278+ 'CalcLabel', objectName='result', isLast=True)
279+ except dbus.StateNotFoundError:
280+ results = self.select_many('CalcLabel', objectName='result')
281+ count = len(results)
282+ if count > 0:
283+ return results[count - 1]
284+ else:
285+ return None
286+
287+ @autopilot.logging.log_action(logger.info)
288+ def click_result_label(self):
289+ result = self.get_result_label()
290+ self._click_screen_object(result)
291+
292+ def get_edit_icon(self):
293+ results = self.select_many('QQuickItem', objectName='editIcon')
294+ count = len(results)
295+ if count > 0:
296+ return results[count - 1]
297+ else:
298+ return None
299+
300+ @autopilot.logging.log_action(logger.info)
301+ def click_edit_icon(self):
302+ result = self.get_edit_icon()
303+ self._click_screen_object(result)
304+
305+ def get_title_label(self):
306+ return self.select_single('TextField', objectName='title')
307+
308+ @autopilot.logging.log_action(logger.info)
309+ def click_title_label(self):
310+ text_label = self.get_title_label()
311+ self._click_screen_object(text_label)
312+
313+ def get_operand_by_index(self, index):
314+ """Return an operand of a calculation entered."""
315+ operand_label = self.select_single(
316+ 'CalcLabel', objectName='operand{0}'.format(index))
317+ assert operand_label is not None, 'No operand with index {0}.'.format(
318+ index)
319+ return operand_label.numbers
320+
321+ def swipe_up(self):
322+ """Swipe up on the screen to tear off the calculation."""
323+ x, y, w, h = self.globalRect
324+ tx = x + (w / 2)
325+ ty = y + (h / 2)
326+
327+ self.pointing_device.drag(tx, ty + h, tx, ty - h)
328+
329+ def is_cleared(self):
330+ """Return True if the screen has no calculation. False otherwise."""
331+ return (self.get_result_label() is None and
332+ self._get_number_of_labels() == 1 and
333+ self.get_operand_by_index(0) == "")
334+
335+ def _get_number_of_labels(self):
336+ return len(self.select_many('CalcLabel'))
337+
338+ @autopilot.logging.log_action(logger.info)
339+ def swipe_to_delete(self):
340+ """Swipe the screen to delete the calculation."""
341+ # We override it because the left side of the screen is used to
342+ # add labels, so the swipe has to start where the operation starts.
343+ # This is hard for a user to do, and weird for automation, which means
344+ # it's an usability issue. See http://pad.lv/1329536
345+ self._drag_pointing_device_to_delete()
346+ self.waitingConfirmationForRemoval.wait_for(True)
347+
348+ def _drag_pointing_device_to_delete(self):
349+ x, y, width, height = self.globalRect
350+ left_x = x + (width * 0.33)
351+ right_x = x + (width * 0.9)
352+ start_y = stop_y = y + (height // 2)
353+
354+ start_x = left_x
355+ stop_x = right_x
356+ self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
357
358=== removed file 'tests/autopilot/ubuntu_calculator_app/emulators.py'
359--- tests/autopilot/ubuntu_calculator_app/emulators.py 2014-06-12 22:25:46 +0000
360+++ tests/autopilot/ubuntu_calculator_app/emulators.py 1970-01-01 00:00:00 +0000
361@@ -1,282 +0,0 @@
362-# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
363-#
364-# Copyright (C) 2013 Canonical Ltd.
365-#
366-# This program is free software; you can redistribute it and/or modify
367-# it under the terms of the GNU Lesser General Public License as published by
368-# the Free Software Foundation; version 3.
369-#
370-# This program is distributed in the hope that it will be useful,
371-# but WITHOUT ANY WARRANTY; without even the implied warranty of
372-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
373-# GNU Lesser General Public License for more details.
374-#
375-# You should have received a copy of the GNU Lesser General Public License
376-# along with this program. If not, see <http://www.gnu.org/licenses/>.
377-
378-"""Calculator app autopilot emulators."""
379-
380-import logging
381-
382-import autopilot.logging
383-from autopilot.introspection import dbus
384-
385-from ubuntuuitoolkit import emulators as toolkit_emulators
386-
387-
388-logger = logging.getLogger(__name__)
389-
390-
391-class MainView(toolkit_emulators.MainView):
392- """Calculator MainView Autopilot emulator."""
393-
394- # TODO when we start the tests for the scientific calculator, many of this
395- # methods will have to be moved to the SimplePage emulator, and the main
396- # view can call them depending on the current page displayed.
397- # --elopio - 2013-08-08
398-
399- def __init__(self, *args):
400- super(MainView, self).__init__(*args)
401- self.pointing_device = toolkit_emulators.get_pointing_device()
402-
403- def clear_with_button(self):
404- """Clear the calculation using the clear button."""
405- self.get_calc_keyboard().click_clear()
406-
407- def get_calc_keyboard(self):
408- """Return the CalcKeyboard autopilot emulator."""
409- return self.select_single(CalcKeyboard)
410-
411- def calculate_operation(self, operation):
412- """Calculate an operation.
413-
414- :parameter operation: A string with the operation to calculate.
415-
416- """
417- self.enter_operation(operation)
418- self.get_calc_keyboard().click_equals()
419-
420- def enter_operation(self, operation):
421- """Enter an operation.
422-
423- :parameter operation: A string with the operation to enter.
424-
425- """
426- self.get_calc_keyboard().enter_operation(operation)
427-
428- def change_sign(self):
429- """Change the sign of the last operand."""
430- self.get_calc_keyboard().click_sign()
431-
432- def get_result(self):
433- """Return the result of a calculation."""
434- return self.get_current_screen().get_result()
435-
436- def get_current_screen(self):
437- """Return the screen for the current calculation."""
438- count = self.get_number_of_screens()
439- return self.select_many(Screen)[count - 1]
440-
441- def get_operand_by_index(self, index):
442- """Return an operand of a calculation entered."""
443- return self.get_current_screen().get_operand_by_index(index)
444-
445- def clear_with_swipe(self):
446- """Clear the calculation making a swipe on the screen."""
447- self.get_current_screen().swipe_up()
448- self._wait_for_screen_to_finish_animation()
449-
450- def _wait_for_screen_to_finish_animation(self):
451- qquicklistview = self.select_single('QQuickListView')
452- qquicklistview.moving.wait_for(False)
453-
454- def is_cleared(self):
455- """Return True if the screen has no calculation. False otherwise."""
456- return self.get_current_screen().is_cleared()
457-
458- def get_screen_by_index(self, index):
459- """Return a screen."""
460- return self._get_screens()[index]
461-
462- def _get_screens(self):
463- return self.select_many(Screen)
464-
465- def get_number_of_screens(self):
466- """Return the number of screens."""
467- return len(self._get_screens())
468-
469- def swipe_previous_calculation_into_view(self, screen_index):
470- previous_screen = self.get_screen_by_index(screen_index)
471- _, prev_screen_y, _, prev_screen_h = previous_screen.globalRect
472- x, y, w, h = self.globalRect
473- start_x = stop_x = x + w / 2
474- start_y = y + h / 2
475- stop_y = start_y + y - prev_screen_y
476- self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
477- self._wait_for_screen_to_finish_animation()
478-
479- def delete_previous_calculation(self, screen_index, confirm):
480- """Delete an old calculation.
481-
482- :parameter screen_index: If index of the screen with the calculation
483- to delete.
484- :parameter confirm: If True, the deletion will be confimed. If False,
485- it will be canceled.
486-
487- """
488- self.swipe_previous_calculation_into_view(screen_index)
489- screen = self.get_screen_by_index(screen_index)
490- screen.swipe_to_delete()
491- self._wait_for_screen_to_finish_animation()
492- if confirm:
493- screen.confirm_removal()
494- else:
495- raise NotImplementedError('Not yet implemented.')
496-
497-
498-class CalcKeyboard(toolkit_emulators.UbuntuUIToolkitEmulatorBase):
499- """CalcKeyboard Autopilot emulator."""
500-
501- _BUTTONS_DICT = {
502- "0": "zeroButton",
503- "1": "oneButton",
504- "2": "twoButton",
505- "3": "threeButton",
506- "4": "fourButton",
507- "5": "fiveButton",
508- "6": "sixButton",
509- "7": "sevenButton",
510- "8": "eightButton",
511- "9": "nineButton",
512- "+": "plusButton",
513- "-": "minusButton",
514- "/": "divideButton",
515- "*": "multiplyButton",
516- '.': "pointButton",
517- }
518-
519- def __init__(self, *args):
520- super(CalcKeyboard, self).__init__(*args)
521- self.pointing_device = toolkit_emulators.get_pointing_device()
522-
523- def click_clear(self):
524- """Click the clear button."""
525- clear_button = self._get_keyboard_button('clearButton')
526- self.pointing_device.click_object(clear_button)
527-
528- def _get_keyboard_button(self, objectName):
529- return self.select_single('KeyboardButton', objectName=objectName)
530-
531- def enter_operation(self, operation):
532- """Enter an operation on the calculator.
533-
534- :parameter operation: A string with the operation to enter.
535-
536- """
537- for char in operation:
538- button = self._get_keyboard_button(self._BUTTONS_DICT[char])
539- self.pointing_device.click_object(button)
540-
541- def click_equals(self):
542- """Click the equals button."""
543- equals_button = self._get_keyboard_button('equalsButton')
544- self.pointing_device.click_object(equals_button)
545-
546- def click_sign(self):
547- """Click the sign button."""
548- sign_button = self._get_keyboard_button('signButton')
549- self.pointing_device.click_object(sign_button)
550-
551-
552-class Screen(toolkit_emulators.Standard):
553- """Screen Autopilot emulator."""
554-
555- def __init__(self, *args):
556- super(Screen, self).__init__(*args)
557- self.pointing_device = toolkit_emulators.get_pointing_device()
558-
559- def get_result(self):
560- """Return the result of a calculation."""
561- result_label = self.get_result_label()
562- assert result_label is not None, 'No result displayed.'
563- return result_label.numbers
564-
565- def get_result_label(self):
566- try:
567- return self.select_single(
568- 'CalcLabel', objectName='result', isLast=True)
569- except dbus.StateNotFoundError:
570- results = self.select_many('CalcLabel', objectName='result')
571- count = len(results)
572- if count > 0:
573- return results[count - 1]
574- else:
575- return None
576-
577- def click_result_label(self):
578- result = self.get_result_label()
579- self.pointing_device.click_object(result)
580-
581- def get_edit_icon(self):
582- results = self.select_many('QQuickItem', objectName='editIcon')
583- count = len(results)
584- if count > 0:
585- return results[count - 1]
586- else:
587- return None
588-
589- def click_edit_icon(self):
590- result = self.get_edit_icon()
591- self.pointing_device.click_object(result)
592-
593- def get_title_label(self):
594- return self.select_single('TextField', objectName='title')
595-
596- def click_title_label(self):
597- text_label = self.get_title_label()
598- self.pointing_device.click_object(text_label)
599-
600- def get_operand_by_index(self, index):
601- """Return an operand of a calculation entered."""
602- operand_label = self.select_single(
603- 'CalcLabel', objectName='operand{0}'.format(index))
604- assert operand_label is not None, 'No operand with index {0}.'.format(
605- index)
606- return operand_label.numbers
607-
608- def swipe_up(self):
609- """Swipe up on the screen to tear off the calculation."""
610- x, y, w, h = self.globalRect
611- tx = x + (w / 2)
612- ty = y + (h / 2)
613-
614- self.pointing_device.drag(tx, ty + h, tx, ty - h)
615-
616- def is_cleared(self):
617- """Return True if the screen has no calculation. False otherwise."""
618- return (self.get_result_label() is None and
619- self._get_number_of_labels() == 1 and
620- self.get_operand_by_index(0) == "")
621-
622- def _get_number_of_labels(self):
623- return len(self.select_many('CalcLabel'))
624-
625- @autopilot.logging.log_action(logger.info)
626- def swipe_to_delete(self):
627- """Swipe the screen to delete the calculation."""
628- # We override it because the left side of the screen is used to
629- # add labels, so the swipe has to start where the operation starts.
630- # This is hard for a user to do, and weird for automation, which means
631- # it's an usability issue. See http://pad.lv/1329536
632- self._drag_pointing_device_to_delete()
633- self.waitingConfirmationForRemoval.wait_for(True)
634-
635- def _drag_pointing_device_to_delete(self):
636- x, y, width, height = self.globalRect
637- left_x = x + (width * 0.33)
638- right_x = x + (width * 0.9)
639- start_y = stop_y = y + (height // 2)
640-
641- start_x = left_x
642- stop_x = right_x
643- self.pointing_device.drag(start_x, start_y, stop_x, stop_y)
644
645=== modified file 'tests/autopilot/ubuntu_calculator_app/tests/__init__.py'
646--- tests/autopilot/ubuntu_calculator_app/tests/__init__.py 2014-01-17 20:50:29 +0000
647+++ tests/autopilot/ubuntu_calculator_app/tests/__init__.py 2014-09-08 19:35:18 +0000
648@@ -1,102 +1,186 @@
649 # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
650-# Copyright 2013 Canonical
651-#
652-# This program is free software: you can redistribute it and/or modify it
653-# under the terms of the GNU General Public License version 3, as published
654-# by the Free Software Foundation.
655+#
656+# Copyright (C) 2013, 2014 Canonical Ltd
657+#
658+# This program is free software: you can redistribute it and/or modify
659+# it under the terms of the GNU General Public License version 3 as
660+# published by the Free Software Foundation.
661+#
662+# This program is distributed in the hope that it will be useful,
663+# but WITHOUT ANY WARRANTY; without even the implied warranty of
664+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
665+# GNU General Public License for more details.
666+#
667+# You should have received a copy of the GNU General Public License
668+# along with this program. If not, see <http://www.gnu.org/licenses/>.
669
670-"""Calculator autopilot tests."""
671+"""Calculator app autopilot tests."""
672
673 import os
674 import shutil
675 import logging
676
677+import fixtures
678+import ubuntu_calculator_app
679+
680 from autopilot.testcase import AutopilotTestCase
681+from autopilot import logging as autopilot_logging
682+
683+import ubuntuuitoolkit
684 from ubuntuuitoolkit import (
685 base,
686- emulators as toolkit_emulators
687+ fixture_setup as toolkit_fixtures
688 )
689
690-from ubuntu_calculator_app import emulators
691-
692 logger = logging.getLogger(__name__)
693
694
695-class CalculatorTestCase(AutopilotTestCase):
696+class BaseTestCaseWithPatchedHome(AutopilotTestCase):
697
698- """A common testcase class that provides useful methods for calculator
699- app.
700+ """A common test case class that provides several useful methods for
701+ ubuntu-calculator-app tests.
702
703 """
704- local_location = "../../ubuntu-calculator-app.qml"
705- installed_location = "/usr/share/ubuntu-calculator-app/" \
706- "ubuntu-calculator-app.qml"
707-
708- sqlite_dir = os.path.expanduser(
709- "~/.local/share/com.ubuntu.calculator/Databases")
710- backup_dir = sqlite_dir + ".backup"
711+
712+ local_location = os.path.dirname(os.path.dirname(os.getcwd()))
713+ local_location_qml = os.path.join(local_location,
714+ 'ubuntu-calculator-app.qml')
715+ installed_location_qml = os.path.join('/usr/share/ubuntu-calculator-app/',
716+ 'ubuntu-calculator-app.qml')
717+
718+ def get_launcher_and_type(self):
719+ if os.path.exists(self.local_location_qml):
720+ launcher = self.launch_test_local
721+ test_type = 'local'
722+ elif os.path.exists(self.installed_location_qml):
723+ launcher = self.launch_test_installed
724+ test_type = 'deb'
725+ else:
726+ launcher = self.launch_test_click
727+ test_type = 'click'
728+ return launcher, test_type
729
730 def setUp(self):
731- self.pointing_device = toolkit_emulators.get_pointing_device()
732- super(CalculatorTestCase, self).setUp()
733- self.temp_move_sqlite_db()
734- self.addCleanup(self.restore_sqlite_db)
735-
736- if os.path.exists(self.local_location):
737- self.launch_test_local()
738- elif os.path.exists(self.installed_location):
739- self.launch_test_installed()
740- else:
741- self.launch_test_click()
742-
743+ super(BaseTestCaseWithPatchedHome, self).setUp()
744+ self.launcher, self.test_type = self.get_launcher_and_type()
745+ self.home_dir = self._patch_home()
746+
747+ # Unset the current locale to ensure locale-specific data
748+ # (day and month names, first day of the week, …) doesn’t get
749+ # in the way of test expectations.
750+ self.useFixture(fixtures.EnvironmentVariable('LC_ALL', newvalue='C'))
751+
752+ @autopilot_logging.log_action(logger.info)
753 def launch_test_local(self):
754- self.app = self.launch_test_application(
755+ return self.launch_test_application(
756 base.get_qmlscene_launch_command(),
757- self.local_location,
758+ self.local_location_qml,
759 app_type='qt',
760- emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
761+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
762
763+ @autopilot_logging.log_action(logger.info)
764 def launch_test_installed(self):
765- self.app = self.launch_test_application(
766+ return self.launch_test_application(
767 base.get_qmlscene_launch_command(),
768- self.installed_location,
769+ self.installed_location_qml,
770 app_type='qt',
771- emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
772+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
773
774+ @autopilot_logging.log_action(logger.info)
775 def launch_test_click(self):
776- self.app = self.launch_click_package(
777+ return self.launch_click_package(
778 "com.ubuntu.calculator",
779- emulator_base=toolkit_emulators.UbuntuUIToolkitEmulatorBase)
780-
781- def temp_move_sqlite_db(self):
782- try:
783- shutil.rmtree(self.backup_dir)
784- except:
785- pass
786- else:
787- logger.warning("Prexisting backup database found and removed")
788-
789- try:
790- shutil.move(self.sqlite_dir, self.backup_dir)
791- except:
792- logger.warning("No current database found")
793- else:
794- logger.debug("Backed up database")
795-
796- def restore_sqlite_db(self):
797- if os.path.exists(self.backup_dir):
798- if os.path.exists(self.sqlite_dir):
799- try:
800- shutil.rmtree(self.sqlite_dir)
801- except:
802- logger.error("Failed to remove test database and restore" /
803- "database")
804- return
805- try:
806- shutil.move(self.backup_dir, self.sqlite_dir)
807- except:
808- logger.error("Failed to restore database")
809-
810- @property
811- def main_view(self):
812- return self.app.select_single(emulators.MainView)
813+ emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
814+
815+ def _copy_xauthority_file(self, directory):
816+ """ Copy .Xauthority file to directory, if it exists in /home
817+ """
818+ # If running under xvfb, as jenkins does,
819+ # xsession will fail to start without xauthority file
820+ # Thus if the Xauthority file is in the home directory
821+ # make sure we copy it to our temp home directory
822+
823+ xauth = os.path.expanduser(os.path.join(os.environ.get('HOME'),
824+ '.Xauthority'))
825+ if os.path.isfile(xauth):
826+ logger.debug("Copying .Xauthority to %s" % directory)
827+ shutil.copyfile(
828+ os.path.expanduser(os.path.join(os.environ.get('HOME'),
829+ '.Xauthority')),
830+ os.path.join(directory, '.Xauthority'))
831+
832+ def _patch_home(self):
833+ """ mock /home for testing purposes to preserve user data
834+ """
835+ # click requires apparmor profile, and writing to special dir
836+ # but the desktop can write to a traditional /tmp directory
837+ if self.test_type == 'click':
838+ env_dir = os.path.join(os.environ.get('HOME'), 'autopilot',
839+ 'fakeenv')
840+
841+ if not os.path.exists(env_dir):
842+ os.makedirs(env_dir)
843+
844+ temp_dir_fixture = fixtures.TempDir(env_dir)
845+ self.useFixture(temp_dir_fixture)
846+
847+ # apparmor doesn't allow the app to create needed directories,
848+ # so we create them now
849+ temp_dir = temp_dir_fixture.path
850+ temp_dir_cache = os.path.join(temp_dir, '.cache')
851+ temp_dir_cache_font = os.path.join(temp_dir_cache, 'fontconfig')
852+ temp_dir_cache_media = os.path.join(temp_dir_cache, 'media-art')
853+ temp_dir_cache_write = os.path.join(temp_dir_cache,
854+ 'tncache-write-text.null')
855+ temp_dir_config = os.path.join(temp_dir, '.config')
856+ temp_dir_toolkit = os.path.join(temp_dir_config,
857+ 'ubuntu-ui-toolkit')
858+ temp_dir_font = os.path.join(temp_dir_cache, '.fontconfig')
859+ temp_dir_local = os.path.join(temp_dir, '.local', 'share')
860+ temp_dir_confined = os.path.join(temp_dir, 'confined')
861+
862+ if not os.path.exists(temp_dir_cache):
863+ os.makedirs(temp_dir_cache)
864+ if not os.path.exists(temp_dir_cache_font):
865+ os.makedirs(temp_dir_cache_font)
866+ if not os.path.exists(temp_dir_cache_media):
867+ os.makedirs(temp_dir_cache_media)
868+ if not os.path.exists(temp_dir_cache_write):
869+ os.makedirs(temp_dir_cache_write)
870+ if not os.path.exists(temp_dir_config):
871+ os.makedirs(temp_dir_config)
872+ if not os.path.exists(temp_dir_toolkit):
873+ os.makedirs(temp_dir_toolkit)
874+ if not os.path.exists(temp_dir_font):
875+ os.makedirs(temp_dir_font)
876+ if not os.path.exists(temp_dir_local):
877+ os.makedirs(temp_dir_local)
878+ if not os.path.exists(temp_dir_confined):
879+ os.makedirs(temp_dir_confined)
880+
881+ # before we set fixture, copy xauthority if needed
882+ self._copy_xauthority_file(temp_dir)
883+ self.useFixture(toolkit_fixtures.InitctlEnvironmentVariable(
884+ HOME=temp_dir))
885+ else:
886+ temp_dir_fixture = fixtures.TempDir()
887+ self.useFixture(temp_dir_fixture)
888+ temp_dir = temp_dir_fixture.path
889+
890+ # before we set fixture, copy xauthority if needed
891+ self._copy_xauthority_file(temp_dir)
892+ self.useFixture(fixtures.EnvironmentVariable('HOME',
893+ newvalue=temp_dir))
894+
895+ logger.debug("Patched home to fake home directory %s" % temp_dir)
896+ return temp_dir
897+
898+
899+class CalculatorAppTestCase(BaseTestCaseWithPatchedHome):
900+
901+ """Base test case that launches the ubuntu-calculator-app."""
902+
903+ def setUp(self):
904+ super(CalculatorAppTestCase, self).setUp()
905+ self.app = ubuntu_calculator_app.CalculatorApp(self.launcher(),
906+ self.test_type)
907
908=== added file 'tests/autopilot/ubuntu_calculator_app/tests/test_screen.py'
909--- tests/autopilot/ubuntu_calculator_app/tests/test_screen.py 1970-01-01 00:00:00 +0000
910+++ tests/autopilot/ubuntu_calculator_app/tests/test_screen.py 2014-09-08 19:35:18 +0000
911@@ -0,0 +1,91 @@
912+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
913+#
914+# Copyright (C) 2014 Canonical Ltd.
915+#
916+# This program is free software; you can redistribute it and/or modify
917+# it under the terms of the GNU Lesser General Public License as published by
918+# the Free Software Foundation; version 3.
919+#
920+# This program is distributed in the hope that it will be useful,
921+# but WITHOUT ANY WARRANTY; without even the implied warranty of
922+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
923+# GNU Lesser General Public License for more details.
924+#
925+# You should have received a copy of the GNU Lesser General Public License
926+# along with this program. If not, see <http://www.gnu.org/licenses/>.
927+
928+"""Tests for the Calculator App Screen"""
929+
930+from __future__ import absolute_import
931+
932+from testtools.matchers import Equals
933+from autopilot.matchers import Eventually
934+
935+from ubuntu_calculator_app.tests import CalculatorAppTestCase
936+
937+
938+class TestScreen(CalculatorAppTestCase):
939+
940+ def setUp(self):
941+ super(TestScreen, self).setUp()
942+ self.app.main_view.get_simple_page().visible.wait_for(True)
943+
944+ def _assert_result(self, expected_result):
945+ self.assertThat(
946+ self.app.main_view.get_result, Eventually(Equals(expected_result)))
947+
948+ def test_operands_before_number(self):
949+ """ Operands before the numbers."""
950+ self.app.main_view.calculate_operation("*3")
951+ screen = self.app.main_view.get_current_screen()
952+ result_label = screen.get_result_label()
953+
954+ self.assertThat(result_label, Equals(None))
955+
956+ def test_unfocus_label(self):
957+ """ Clear label focus by clicking outside its area. """
958+ self.app.main_view.calculate_operation("12+3")
959+ self._assert_result("15")
960+
961+ # Focus the item
962+ screen = self.app.main_view.get_current_screen()
963+ screen.click_title_label()
964+ title_label = screen.get_title_label()
965+ self.assertThat(title_label.activeFocus, Eventually(Equals(True)))
966+
967+ # Click elsewhere to unfocus the label
968+ self.app.pointing_device.click_object(screen)
969+ self.assertThat(title_label.activeFocus, Eventually(Equals(False)))
970+
971+ def test_edit_mode(self):
972+ """ Enter and exit edit mode clicking on pencil icon """
973+ self.app.main_view.calculate_operation("105-5")
974+ self._assert_result("100")
975+
976+ # Click the edit button
977+ screen = self.app.main_view.get_current_screen()
978+ screen.click_edit_icon()
979+
980+ # Check if is focused
981+ title_label = screen.get_title_label()
982+ self.assertThat(title_label.activeFocus, Eventually(Equals(True)))
983+
984+ # Click to unfocus the label
985+ screen.click_edit_icon()
986+ self.assertThat(title_label.activeFocus, Eventually(Equals(False)))
987+
988+ def test_hide_calc_keyboard(self):
989+ """ Hide calc keyboard when focus on a label """
990+ self.app.main_view.calculate_operation("18-1")
991+ self._assert_result("17")
992+
993+ # Focus the item
994+ screen = self.app.main_view.get_current_screen()
995+ screen.click_title_label()
996+
997+ calc_keyboard = self.app.main_view.get_calc_keyboard()
998+ self.assertThat(calc_keyboard.visible, Eventually(Equals(False)))
999+
1000+ # Click elsewhere to unfocus the label
1001+ self.app.pointing_device.click_object(screen)
1002+ self.assertThat(calc_keyboard.visible, Eventually(Equals(True)))
1003
1004=== modified file 'tests/autopilot/ubuntu_calculator_app/tests/test_simple_page.py'
1005--- tests/autopilot/ubuntu_calculator_app/tests/test_simple_page.py 2014-06-12 21:56:11 +0000
1006+++ tests/autopilot/ubuntu_calculator_app/tests/test_simple_page.py 2014-09-08 19:35:18 +0000
1007@@ -14,93 +14,77 @@
1008 # You should have received a copy of the GNU Lesser General Public License
1009 # along with this program. If not, see <http://www.gnu.org/licenses/>.
1010
1011-"""Tests for the Calculator App"""
1012+"""Tests for the Calculator App Simple Page"""
1013
1014 from __future__ import absolute_import
1015
1016 from testtools.matchers import Equals
1017 from autopilot.matchers import Eventually
1018-from autopilot.platform import model
1019-
1020-from ubuntu_calculator_app.tests import CalculatorTestCase
1021-import subprocess
1022-
1023-
1024-class TestSimplePage(CalculatorTestCase):
1025+
1026+from ubuntu_calculator_app.tests import CalculatorAppTestCase
1027+
1028+
1029+class TestSimplePage(CalculatorAppTestCase):
1030
1031 def setUp(self):
1032 super(TestSimplePage, self).setUp()
1033-
1034- @classmethod
1035- def setUpClass(cls):
1036- if model() != "Desktop":
1037- try:
1038- subprocess.check_call(["stop", "-q", "maliit-server"])
1039- except subprocess.CalledProcessError:
1040- pass
1041-
1042- @classmethod
1043- def tearDownClass(cls):
1044- if model() != "Desktop":
1045- try:
1046- subprocess.check_call(["start", "-q", "maliit-server"])
1047- except subprocess.CalledProcessError:
1048- pass
1049+ self.app.main_view.get_simple_page().visible.wait_for(True)
1050+
1051+ def _assert_result(self, expected_result):
1052+ self.assertThat(
1053+ self.app.main_view.get_result, Eventually(Equals(expected_result)))
1054
1055 def test_operation_after_clear(self):
1056 """ Test that after clearing one calculation, the next is still correct
1057 (bug #1164973).
1058
1059 """
1060- self.main_view.calculate_operation("1+1")
1061- self._assert_result("2")
1062- self.main_view.clear_with_button()
1063- self.main_view.calculate_operation("1+1")
1064- self._assert_result("2")
1065-
1066- def _assert_result(self, expected_result):
1067- self.assertThat(
1068- self.main_view.get_result, Eventually(Equals(expected_result)))
1069+ self.app.main_view.calculate_operation("1+1")
1070+ self._assert_result("2")
1071+ self.app.main_view.clear_with_button()
1072+ self.app.main_view.calculate_operation("1+1")
1073+ self._assert_result("2")
1074
1075 def test_enter_operand(self):
1076- self.main_view.enter_operation("123")
1077- self.assertEqual(self.main_view.get_operand_by_index(0), "123")
1078+ self.app.main_view.enter_operation("123")
1079+ self.assertEqual(self.app.main_view.get_operand_by_index(0), "123")
1080
1081 def test_equals_dont_change_numbers(self):
1082 """ Test that typing a number and pressing "=" won't change the number
1083 (bug #1165894).
1084
1085 """
1086- self.main_view.enter_operation("123")
1087- self.main_view.get_calc_keyboard().click_equals()
1088+ self.app.main_view.enter_operation("123")
1089+ self.app.main_view.get_calc_keyboard().click_equals()
1090
1091 # check that the label is still displaying correctly
1092- self.assertEqual(self.main_view.get_operand_by_index(0), "123")
1093+ self.assertEqual(self.app.main_view.get_operand_by_index(0), "123")
1094
1095 def test_multiply_priority(self):
1096 """Multiply is done before addition or substraction."""
1097- self.main_view.calculate_operation("2+2*2")
1098+ self.app.main_view.calculate_operation("2+2*2")
1099 self._assert_result("6")
1100
1101 def test_divide_priority(self):
1102 """Divide is done before addition or substraction."""
1103- self.main_view.calculate_operation("5+6/2")
1104+ self.app.main_view.calculate_operation("5+6/2")
1105 self._assert_result("8")
1106
1107 def test_divide_with_infinity_length_result_number(self):
1108 """Check how is formatted infinity long result number."""
1109- self.main_view.calculate_operation("1/3")
1110+ self.app.main_view.calculate_operation("1/3")
1111 self._assert_result("0.33333333")
1112
1113 def test_swipe_up_clears(self):
1114 """Make sure swiping up clears the formula label."""
1115- self.main_view.enter_operation("9")
1116- self.main_view.clear_with_swipe()
1117- self.assertThat(self.main_view.is_cleared, Eventually(Equals(True)))
1118+ self.app.main_view.enter_operation("9")
1119+ self.app.main_view.clear_with_swipe()
1120+ self.assertThat(self.app.main_view.is_cleared,
1121+ Eventually(Equals(True)))
1122
1123 def test_sign_button(self):
1124 """Ensure the sign button is working."""
1125- calc_keyboard = self.main_view.get_calc_keyboard()
1126+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1127 calc_keyboard.enter_operation("5+")
1128 calc_keyboard.click_sign()
1129 calc_keyboard.enter_operation("1")
1130@@ -110,24 +94,24 @@
1131
1132 def test_addition(self):
1133 """Addition test."""
1134- self.main_view.calculate_operation("4+2.55")
1135+ self.app.main_view.calculate_operation("4+2.55")
1136 self._assert_result("6.55")
1137
1138 def test_substraction(self):
1139- self.main_view.calculate_operation("5-4")
1140+ self.app.main_view.calculate_operation("5-4")
1141 self._assert_result("1")
1142
1143 def test_positive_numbers_multiplication(self):
1144- self.main_view.calculate_operation("2.1*3")
1145+ self.app.main_view.calculate_operation("2.1*3")
1146 self._assert_result("6.3")
1147
1148 def test_multiplication_by_zero(self):
1149- self.main_view.calculate_operation("4*0")
1150+ self.app.main_view.calculate_operation("4*0")
1151 self._assert_result("0")
1152
1153 def test_one_negative_number_multiplication(self):
1154 # tested operation: -3*4
1155- calc_keyboard = self.main_view.get_calc_keyboard()
1156+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1157 calc_keyboard.click_sign() # to get "-"
1158 calc_keyboard.enter_operation("3*4")
1159 calc_keyboard.click_equals()
1160@@ -135,7 +119,7 @@
1161
1162 def test_two_negative_numbers_multiplication(self):
1163 # tested operation: -2*-3
1164- calc_keyboard = self.main_view.get_calc_keyboard()
1165+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1166 calc_keyboard.click_sign() # to get "-"
1167 calc_keyboard.enter_operation("2*")
1168 calc_keyboard.click_sign() # to get "-"
1169@@ -145,12 +129,12 @@
1170 self._assert_result("6")
1171
1172 def test_three_positive_numbers_multiplication(self):
1173- self.main_view.calculate_operation("2*3*10")
1174+ self.app.main_view.calculate_operation("2*3*10")
1175 self._assert_result("60")
1176
1177 def test_two_negatives_in_three_numbers_multiplication(self):
1178 # tested operation: -2*-3*5
1179- calc_keyboard = self.main_view.get_calc_keyboard()
1180+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1181 calc_keyboard.click_sign() # to get "-"
1182 calc_keyboard.enter_operation("2*")
1183 calc_keyboard.click_sign() # to get "-"
1184@@ -161,7 +145,7 @@
1185
1186 def test_three_negative_numbers_multiplication(self):
1187 # tested operation: -4*-5*-7
1188- calc_keyboard = self.main_view.get_calc_keyboard()
1189+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1190 calc_keyboard.click_sign() # to get "-"
1191 calc_keyboard.enter_operation("4*")
1192 calc_keyboard.click_sign() # to get "-"
1193@@ -173,12 +157,12 @@
1194 self._assert_result("-140")
1195
1196 def test_divide_positive(self):
1197- self.main_view.calculate_operation("4/2")
1198+ self.app.main_view.calculate_operation("4/2")
1199 self._assert_result("2")
1200
1201 def test_divide_negative(self):
1202 # tested operation: 4/-2
1203- calc_keyboard = self.main_view.get_calc_keyboard()
1204+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1205 calc_keyboard.enter_operation("4/")
1206 calc_keyboard.click_sign() # to get "-"
1207 calc_keyboard.enter_operation("2")
1208@@ -188,7 +172,7 @@
1209
1210 def test_divide_two_negatives(self):
1211 # tested operation: -4/-2
1212- calc_keyboard = self.main_view.get_calc_keyboard()
1213+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1214 calc_keyboard.click_sign() # to get "-"
1215 calc_keyboard.enter_operation("4/")
1216 calc_keyboard.click_sign() # to get "-"
1217@@ -198,114 +182,58 @@
1218 self._assert_result("2")
1219
1220 def test_divide_with_zero(self):
1221- self.main_view.calculate_operation("0/4")
1222+ self.app.main_view.calculate_operation("0/4")
1223 self._assert_result("0")
1224
1225 def test_divide_by_zero(self):
1226- self.main_view.calculate_operation("4/0")
1227+ self.app.main_view.calculate_operation("4/0")
1228 self._assert_result(u'+\u221e')
1229
1230 def test_divide_zero_by_zero(self):
1231- self.main_view.calculate_operation("0/0")
1232+ self.app.main_view.calculate_operation("0/0")
1233 self._assert_result("NaN")
1234
1235 def test_adding_small_number(self):
1236- self.main_view.calculate_operation("0.000000001+1")
1237+ self.app.main_view.calculate_operation("0.000000001+1")
1238 self._assert_result("1.000000001")
1239
1240 def test_divide_small_number(self):
1241 """Check result number formating."""
1242- self.main_view.calculate_operation(".000000001/10")
1243+ self.app.main_view.calculate_operation(".000000001/10")
1244 self._assert_result("1e-10")
1245
1246 def test_large_numbers_multiplication(self):
1247- self.main_view.calculate_operation("99999999999*99999999999")
1248+ self.app.main_view.calculate_operation("99999999999*99999999999")
1249 self._assert_result("1.0000000e+22")
1250
1251 def test_swipe_up_with_result(self):
1252 """Test swipe up adds calculation to history"""
1253- self.main_view.calculate_operation("9+8")
1254- self.main_view.clear_with_swipe()
1255+ self.app.main_view.calculate_operation("9+8")
1256+ self.app.main_view.clear_with_swipe()
1257
1258 self.assertThat(
1259- self.main_view.get_number_of_screens, Eventually(Equals(2)))
1260+ self.app.main_view.get_number_of_screens, Eventually(Equals(2)))
1261 self.assertTrue(
1262- self.main_view.get_screen_by_index(1).is_cleared())
1263+ self.app.main_view.get_screen_by_index(1).is_cleared())
1264 self.assertEquals(
1265- self.main_view.get_screen_by_index(0).get_result(), "17")
1266+ self.app.main_view.get_screen_by_index(0).get_result(), "17")
1267
1268 def test_swipe_to_delete_calculation(self):
1269 """Delete a calculation swiping on it to the side."""
1270- self.main_view.calculate_operation("9+5")
1271- self.main_view.clear_with_swipe()
1272+ self.app.main_view.calculate_operation("9+5")
1273+ self.app.main_view.clear_with_swipe()
1274
1275- self.main_view.swipe_previous_calculation_into_view(0)
1276- self.main_view.delete_previous_calculation(0, confirm=True)
1277+ self.app.main_view.swipe_previous_calculation_into_view(0)
1278+ self.app.main_view.delete_previous_calculation(0, confirm=True)
1279
1280 self.assertThat(
1281- self.main_view.get_number_of_screens, Eventually(Equals(1)))
1282-
1283- def test_operands_before_number(self):
1284- """ Operands before the numbers."""
1285- self.main_view.calculate_operation("*3")
1286- screen = self.main_view.get_current_screen()
1287- result_label = screen.get_result_label()
1288-
1289- self.assertThat(result_label, Equals(None))
1290+ self.app.main_view.get_number_of_screens, Eventually(Equals(1)))
1291
1292 def test_continue_calculation(self):
1293- self.main_view.calculate_operation("59+1")
1294+ self.app.main_view.calculate_operation("59+1")
1295
1296- calc_keyboard = self.main_view.get_calc_keyboard()
1297+ calc_keyboard = self.app.main_view.get_calc_keyboard()
1298 calc_keyboard.enter_operation("+5")
1299 calc_keyboard.click_equals()
1300
1301 self._assert_result("65")
1302-
1303- def test_unfocus_label(self):
1304- """ Clear label focus by clicking outside its area. """
1305- self.main_view.calculate_operation("12+3")
1306- self._assert_result("15")
1307-
1308- # Focus the item
1309- screen = self.main_view.get_current_screen()
1310- screen.click_title_label()
1311- title_label = screen.get_title_label()
1312- self.assertThat(title_label.activeFocus, Eventually(Equals(True)))
1313-
1314- # Click elsewhere to unfocus the label
1315- screen.click_result_label()
1316- self.assertThat(title_label.activeFocus, Eventually(Equals(False)))
1317-
1318- def test_hide_calc_keyboard(self):
1319- """ Hide calc keyboard when focus on a label """
1320- self.main_view.calculate_operation("18-1")
1321- self._assert_result("17")
1322-
1323- # Focus the item
1324- screen = self.main_view.get_current_screen()
1325- screen.click_title_label()
1326-
1327- calc_keyboard = self.main_view.get_calc_keyboard()
1328- self.assertThat(calc_keyboard.visible, Eventually(Equals(False)))
1329-
1330- # Click elsewhere to unfocus the label
1331- screen.click_result_label()
1332- self.assertThat(calc_keyboard.visible, Eventually(Equals(True)))
1333-
1334- def test_edit_mode(self):
1335- """ Enter and exit edit mode clicking on pencil icon """
1336- self.main_view.calculate_operation("105-5")
1337- self._assert_result("100")
1338-
1339- # Click the edit button
1340- screen = self.main_view.get_current_screen()
1341- screen.click_edit_icon()
1342-
1343- # Check if is focused
1344- title_label = screen.get_title_label()
1345- self.assertThat(title_label.activeFocus, Eventually(Equals(True)))
1346-
1347- # Click to unfocus the label
1348- screen.click_edit_icon()
1349- self.assertThat(title_label.activeFocus, Eventually(Equals(False)))

Subscribers

People subscribed via source and target branches