Merge lp:~nik90/ubuntu-clock-app/add-world-qml-tests into lp:ubuntu-clock-app
- add-world-qml-tests
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Nekhelesh Ramananthan |
Approved revision: | 168 |
Merged at revision: | 147 |
Proposed branch: | lp:~nik90/ubuntu-clock-app/add-world-qml-tests |
Merge into: | lp:ubuntu-clock-app |
Prerequisite: | lp:~nik90/ubuntu-clock-app/edit-alarm-qml-tests |
Diff against target: |
417 lines (+309/-23) 6 files modified
app/worldclock/WorldCityList.qml (+3/-3) debian/changelog (+1/-0) tests/autopilot/ubuntu_clock_app/emulators.py (+20/-20) tests/unit/CMakeLists.txt (+3/-0) tests/unit/MockClockApp.qml (+88/-0) tests/unit/tst_worldClock.qml (+194/-0) |
To merge this branch: | bzr merge lp:~nik90/ubuntu-clock-app/add-world-qml-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Leo Arias (community) | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Ubuntu Clock Developers | Pending | ||
Review via email:
|
Commit message
Added world clock feature qml tests.
Description of the change
Added world clock feature qml tests.
The QML Test Suite now comprises of Feature, Unit and Integration tests and collectively has a far higher test coverage of the clock app than AP test have. A few more MPs later, I might propose removing AP tests.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Leo Arias (elopio) wrote : | # |
You have a couple of ifs there that are really hard to understand.
You can refactor them like this: http://
(I haven't run the tests with the refactor, so please double check the code, I could make typos).
Also, please remember that on python, we should name the variables with all lower case separating words with spaces. And that we should prefer single quotes instead of double quotes. Looking at the emulators file, I see some style errors. They can be fixed in a separate branch, unless you are planning to kill that file soon.
126 +/*
127 + This file is meant to create a fake but fully fleshed clock app with its
128 + own database and settings. This will avoid messing with the user data while
129 + running the tests.
130 +*/
Interesting, I like it. You just need to take a lot of care that this test double is as close to the real as possible. Ideally without duplicating any code, because otherwise they will be hard to maintain. Usually, devs add things to the real one and forget to update the double, so they end up testing a different thing.
Could you make a QML file that takes the app name and any other things you want to change on the mock as parameters, and then make both app/ubuntu-
250 + function _findWorldCity(
It's slightly clearer when you make two methods instead of passing a type argument:
findUserWorldCity and findDefaultWorl
Those are the methods you call from a test. Then, you make them call an internal _findWorldCity where you pass the right prefix. But you are encapsulating the prefix in the internal methods, your tests don't know about the exact prefix. So by changing the tests to call a method instead of passing a string, it will be easier for you if you ever have to change the prefix. Instead of changing it in all the tests that call findWorldCity, you will just have to change it on the non-internal methods and the name can remain the same.
271 + function _confirmWorldCi
Here again, I prefer assert. confirm sounds like a step of the test, like confirm a dialog or something like that.
295 + tryCompareFunct
And here again, this shouldn't be needed if you are already asserting the successful creation during a test.
327 + // Wait for the list to be populated with results
328 + tryCompareFunct
Now this is a valid usage of an assertion on the middle of the steps. But it's just because this framework doesn't have a proper wait. On autopilot we would do it with a wait_for or something similar, that's a little different than an assertion.
373 + function test_addCityByS
You have to be careful here. The unit tests many times are run in a confined machine without internet access. As the tests are passing, I'm guessing that's not the case for the jenkins runners. But ideally, you would replace the online model with a hard-coded one for a unit test. And then do an integration test for the service that provides you with cities.
This is great, ...
- 160. By Nekhelesh Ramananthan
-
merged trunk
- 161. By Nekhelesh Ramananthan
-
Migrated tst_worldClock over to ClockTestCase
- 162. By Nekhelesh Ramananthan
-
renamed confirmWorldCit
yAddition( ) to assertWorldCity Addition( ) - 163. By Nekhelesh Ramananthan
-
Removed unnecessary confirm statement iat the start of a test
- 164. By Nekhelesh Ramananthan
-
Added TODO comment for mocking the searchOnline function
- 165. By Nekhelesh Ramananthan
-
Improved if logic in emulators.py
- 166. By Nekhelesh Ramananthan
-
Simplified code a bit
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nekhelesh Ramananthan (nik90) wrote : | # |
> You have a couple of ifs there that are really hard to understand.
> You can refactor them like this: http://
> (I haven't run the tests with the refactor, so please double check the code, I
> could make typos).
>
> Also, please remember that on python, we should name the variables with all
> lower case separating words with spaces. And that we should prefer single
> quotes instead of double quotes. Looking at the emulators file, I see some
> style errors. They can be fixed in a separate branch, unless you are planning
> to kill that file soon.
Thnx I fixed that as well. I was only planning to make minimal changes to emulators.py in fear of breaking the AP test ;). But now the if logic looks much simpler despite taking me longer than usual to fix that (hence my uneasiness in touch python code)
> 250 + function _findWorldCity(
>
> It's slightly clearer when you make two methods instead of passing a type
> argument:
> findUserWorldCity and findDefaultWorl
> Those are the methods you call from a test. Then, you make them call an
> internal _findWorldCity where you pass the right prefix. But you are
> encapsulating the prefix in the internal methods, your tests don't know about
> the exact prefix. So by changing the tests to call a method instead of passing
> a string, it will be easier for you if you ever have to change the prefix.
> Instead of changing it in all the tests that call findWorldCity, you will just
> have to change it on the non-internal methods and the name can remain the
> same.
>
Done. I hope what I did is what you had in mind as well.
> 271 + function _confirmWorldCi
>
> Here again, I prefer assert. confirm sounds like a step of the test, like
> confirm a dialog or something like that.
Trivial fix. Done. I will use assert from now on.
>
> 295 + tryCompareFunct
>
> And here again, this shouldn't be needed if you are already asserting the
> successful creation during a test.
>
Done
> 327 + // Wait for the list to be populated with results
> 328 + tryCompareFunct
>
> Now this is a valid usage of an assertion on the middle of the steps. But it's
> just because this framework doesn't have a proper wait. On autopilot we would
> do it with a wait_for or something similar, that's a little different than an
> assertion.
>
Done
> 373 + function test_addCityByS
>
> You have to be careful here. The unit tests many times are run in a confined
> machine without internet access. As the tests are passing, I'm guessing that's
> not the case for the jenkins runners. But ideally, you would replace the
> online model with a hard-coded one for a unit test. And then do an integration
> test for the service that provides you with cities.
>
This is an easy one. I have added a TODO comment about mocking that. I am not sure *yet* how to do this without touching the clock app code which at the moment (for RTM) I don't want to do.
> This is great, as always. Ping me on IRC if you want to ...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nekhelesh Ramananthan (nik90) wrote : | # |
>
> 126 +/*
> 127 + This file is meant to create a fake but fully fleshed clock app with
> its
> 128 + own database and settings. This will avoid messing with the user
> data while
> 129 + running the tests.
> 130 +*/
>
> Interesting, I like it.
This is my first attempt at mocking the clock app. And I was surprised at how easy it was to do this, something which wouldn't be possible with AP without touching the actual app config files.
> You just need to take a lot of care that this test
> double is as close to the real as possible. Ideally without duplicating any
> code, because otherwise they will be hard to maintain. Usually, devs add
> things to the real one and forget to update the double, so they end up testing
> a different thing.
Yup. I agree this can be a potential issue. However this late in the cycle (close to RTM) there wouldn't be any more changes to ubuntu-
>
> Could you make a QML file that takes the app name and any other things you
> want to change on the mock as parameters, and then make both app/ubuntu-clock-
> app.qml and tests/unit/
>
At this point, I don't want to avoid touching the ubuntu-
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:166
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
- 167. By Nekhelesh Ramananthan
-
Merged prerequisite branch
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:167
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Leo Arias (elopio) : | # |
- 168. By Nekhelesh Ramananthan
-
Merged prerequisite branch
Preview Diff
1 | === modified file 'app/worldclock/WorldCityList.qml' | |||
2 | --- app/worldclock/WorldCityList.qml 2014-10-11 18:39:12 +0000 | |||
3 | +++ app/worldclock/WorldCityList.qml 2014-10-14 16:02:15 +0000 | |||
4 | @@ -302,7 +302,7 @@ | |||
5 | 302 | 302 | ||
6 | 303 | delegate: ListItem.Base { | 303 | delegate: ListItem.Base { |
7 | 304 | showDivider: false | 304 | showDivider: false |
9 | 305 | objectName: "worldCityItem" + index | 305 | objectName: "defaultWorldCityItem" + index |
10 | 306 | 306 | ||
11 | 307 | Column { | 307 | Column { |
12 | 308 | id: worldCityDelegateColumn | 308 | id: worldCityDelegateColumn |
13 | @@ -316,7 +316,7 @@ | |||
14 | 316 | 316 | ||
15 | 317 | Label { | 317 | Label { |
16 | 318 | text: city | 318 | text: city |
18 | 319 | objectName: "cityNameText" | 319 | objectName: "defaultCityNameText" |
19 | 320 | width: parent.width | 320 | width: parent.width |
20 | 321 | elide: Text.ElideRight | 321 | elide: Text.ElideRight |
21 | 322 | color: UbuntuColors.midAubergine | 322 | color: UbuntuColors.midAubergine |
22 | @@ -324,7 +324,7 @@ | |||
23 | 324 | 324 | ||
24 | 325 | Label { | 325 | Label { |
25 | 326 | text: country | 326 | text: country |
27 | 327 | objectName: "countryNameText" | 327 | objectName: "defaultCountryNameText" |
28 | 328 | fontSize: "xx-small" | 328 | fontSize: "xx-small" |
29 | 329 | width: parent.width | 329 | width: parent.width |
30 | 330 | elide: Text.ElideRight | 330 | elide: Text.ElideRight |
31 | 331 | 331 | ||
32 | === modified file 'debian/changelog' | |||
33 | --- debian/changelog 2014-10-14 16:02:15 +0000 | |||
34 | +++ debian/changelog 2014-10-14 16:02:15 +0000 | |||
35 | @@ -14,6 +14,7 @@ | |||
36 | 14 | * Fixed alarm page header width warning and corrected icon spacing. | 14 | * Fixed alarm page header width warning and corrected icon spacing. |
37 | 15 | * Added edit alarm qml tests and added a library helper which contains commonly | 15 | * Added edit alarm qml tests and added a library helper which contains commonly |
38 | 16 | used test functions to avoid code duplication in future tests. | 16 | used test functions to avoid code duplication in future tests. |
39 | 17 | * Added world clock feature qml tests | ||
40 | 17 | * Delayed loading of xmltimezone model until add world city page is loaded and | 18 | * Delayed loading of xmltimezone model until add world city page is loaded and |
41 | 18 | dynamically load/unload the jsontimezone model only when necessary. | 19 | dynamically load/unload the jsontimezone model only when necessary. |
42 | 19 | 20 | ||
43 | 20 | 21 | ||
44 | === modified file 'tests/autopilot/ubuntu_clock_app/emulators.py' | |||
45 | --- tests/autopilot/ubuntu_clock_app/emulators.py 2014-10-10 22:12:50 +0000 | |||
46 | +++ tests/autopilot/ubuntu_clock_app/emulators.py 2014-10-14 16:02:15 +0000 | |||
47 | @@ -133,16 +133,15 @@ | |||
48 | 133 | old_cities_count = self.get_num_of_saved_cities() | 133 | old_cities_count = self.get_num_of_saved_cities() |
49 | 134 | index = 0 | 134 | index = 0 |
50 | 135 | for index in range(old_cities_count): | 135 | for index in range(old_cities_count): |
61 | 136 | if self.wait_select_single( | 136 | world_city_item = self.wait_select_single( |
62 | 137 | objectName='userWorldCityItem{}'.format(index)).\ | 137 | objectName='userWorldCityItem{}'.format(index)) |
63 | 138 | wait_select_single("Label", objectName="userCityNameText").\ | 138 | city_name_label = world_city_item.wait_select_single( |
64 | 139 | text == city_Name: | 139 | 'Label', objectName='userCityNameText') |
65 | 140 | if self.wait_select_single( | 140 | country_name_label = world_city_item.wait_select_single( |
66 | 141 | objectName='userWorldCityItem{}'.format(index)).\ | 141 | 'Label', objectName='userCountryNameText') |
67 | 142 | wait_select_single( | 142 | if (city_name_label.text == city_Name and |
68 | 143 | "Label", objectName="userCountryNameText").\ | 143 | country_name_label.text == country_Name): |
69 | 144 | text == country_Name: | 144 | self._delete_userWorldCityItem(index) |
60 | 145 | self._delete_userWorldCityItem(index) | ||
70 | 146 | 145 | ||
71 | 147 | # FIXME ----------------------------------------------------------------- | 146 | # FIXME ----------------------------------------------------------------- |
72 | 148 | # Commenting the following lines as deleting a world city when there is | 147 | # Commenting the following lines as deleting a world city when there is |
73 | @@ -266,16 +265,17 @@ | |||
74 | 266 | cityList.count.wait_for(GreaterThan(0)) | 265 | cityList.count.wait_for(GreaterThan(0)) |
75 | 267 | 266 | ||
76 | 268 | for index in range(int(cityList.count)): | 267 | for index in range(int(cityList.count)): |
87 | 269 | if cityList.wait_select_single( | 268 | world_city_item = self.wait_select_single( |
88 | 270 | objectName="worldCityItem{}".format(index)).wait_select_single( | 269 | objectName='defaultWorldCityItem{}'.format(index)) |
89 | 271 | "Label", objectName="cityNameText").text == city_Name: | 270 | city_name_label = world_city_item.wait_select_single( |
90 | 272 | if cityList.wait_select_single( | 271 | 'Label', objectName='defaultCityNameText') |
91 | 273 | objectName="worldCityItem{}".format(index)).\ | 272 | country_name_label = world_city_item.wait_select_single( |
92 | 274 | wait_select_single("Label", objectName="countryNameText").\ | 273 | 'Label', objectName='defaultCountryNameText') |
93 | 275 | text == country_Name: | 274 | if (city_name_label.text == city_Name and |
94 | 276 | cityList.click_element( | 275 | country_name_label.text == country_Name): |
95 | 277 | "worldCityItem{}".format(index), direction=None) | 276 | cityList.click_element( |
96 | 278 | break | 277 | 'defaultWorldCityItem{}'.format(index), direction=None) |
97 | 278 | break | ||
98 | 279 | 279 | ||
99 | 280 | @autopilot_logging.log_action(logger.info) | 280 | @autopilot_logging.log_action(logger.info) |
100 | 281 | def search_world_city_(self, city_Name, country_Name): | 281 | def search_world_city_(self, city_Name, country_Name): |
101 | 282 | 282 | ||
102 | === modified file 'tests/unit/CMakeLists.txt' | |||
103 | --- tests/unit/CMakeLists.txt 2014-10-14 16:02:15 +0000 | |||
104 | +++ tests/unit/CMakeLists.txt 2014-10-14 16:02:15 +0000 | |||
105 | @@ -26,6 +26,7 @@ | |||
106 | 26 | declare_qml_test("Alarm" tst_alarm.qml) | 26 | declare_qml_test("Alarm" tst_alarm.qml) |
107 | 27 | declare_qml_test("AlarmSound" tst_alarmSound.qml) | 27 | declare_qml_test("AlarmSound" tst_alarmSound.qml) |
108 | 28 | declare_qml_test("AlarmUtils" tst_alarmUtils.qml) | 28 | declare_qml_test("AlarmUtils" tst_alarmUtils.qml) |
109 | 29 | declare_qml_test("WorldClock" tst_worldClock.qml) | ||
110 | 29 | else() | 30 | else() |
111 | 30 | if (NOT QMLTESTRUNNER_BIN) | 31 | if (NOT QMLTESTRUNNER_BIN) |
112 | 31 | message(WARNING "Qml tests disabled: qmltestrunner not found") | 32 | message(WARNING "Qml tests disabled: qmltestrunner not found") |
113 | @@ -40,10 +41,12 @@ | |||
114 | 40 | tst_alarm.qml | 41 | tst_alarm.qml |
115 | 41 | tst_alarmSound.qml | 42 | tst_alarmSound.qml |
116 | 42 | tst_alarmUtils.qml | 43 | tst_alarmUtils.qml |
117 | 44 | tst_worldClock.qml | ||
118 | 43 | ) | 45 | ) |
119 | 44 | add_custom_target(tst_QmlFiles ALL SOURCES ${QML_TST_FILES}) | 46 | add_custom_target(tst_QmlFiles ALL SOURCES ${QML_TST_FILES}) |
120 | 45 | 47 | ||
121 | 46 | set(QML_TST_UTILS | 48 | set(QML_TST_UTILS |
122 | 49 | MockClockApp.qml | ||
123 | 47 | ClockTestCase.qml | 50 | ClockTestCase.qml |
124 | 48 | ) | 51 | ) |
125 | 49 | 52 | ||
126 | 50 | 53 | ||
127 | === added file 'tests/unit/MockClockApp.qml' | |||
128 | --- tests/unit/MockClockApp.qml 1970-01-01 00:00:00 +0000 | |||
129 | +++ tests/unit/MockClockApp.qml 2014-10-14 16:02:15 +0000 | |||
130 | @@ -0,0 +1,88 @@ | |||
131 | 1 | /* | ||
132 | 2 | * Copyright (C) 2014 Canonical Ltd | ||
133 | 3 | * | ||
134 | 4 | * This file is part of Ubuntu Clock App | ||
135 | 5 | * | ||
136 | 6 | * Ubuntu Clock App is free software: you can redistribute it and/or modify | ||
137 | 7 | * it under the terms of the GNU General Public License version 3 as | ||
138 | 8 | * published by the Free Software Foundation. | ||
139 | 9 | * | ||
140 | 10 | * Ubuntu Clock App is distributed in the hope that it will be useful, | ||
141 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
142 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
143 | 13 | * GNU General Public License for more details. | ||
144 | 14 | * | ||
145 | 15 | * You should have received a copy of the GNU General Public License | ||
146 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
147 | 17 | */ | ||
148 | 18 | |||
149 | 19 | import QtQuick 2.3 | ||
150 | 20 | import DateTime 1.0 | ||
151 | 21 | import U1db 1.0 as U1db | ||
152 | 22 | import Ubuntu.Components 1.1 | ||
153 | 23 | import "../../app/clock" | ||
154 | 24 | |||
155 | 25 | /* | ||
156 | 26 | This file is meant to create a fake but fully fleshed clock app with its | ||
157 | 27 | own database and settings. This will avoid messing with the user data while | ||
158 | 28 | running the tests. | ||
159 | 29 | */ | ||
160 | 30 | |||
161 | 31 | MainView { | ||
162 | 32 | id: clockApp | ||
163 | 33 | |||
164 | 34 | // Property to store the state of an application (active or suspended) | ||
165 | 35 | property bool applicationState: Qt.application.active | ||
166 | 36 | |||
167 | 37 | width: units.gu(40) | ||
168 | 38 | height: units.gu(70) | ||
169 | 39 | useDeprecatedToolbar: false | ||
170 | 40 | applicationName: "com.ubuntu.fakeclock.test" | ||
171 | 41 | |||
172 | 42 | U1db.Database { | ||
173 | 43 | id: clockDB | ||
174 | 44 | path: "user-preferences" | ||
175 | 45 | } | ||
176 | 46 | |||
177 | 47 | U1db.Document { | ||
178 | 48 | id: clockModeDocument | ||
179 | 49 | create: true | ||
180 | 50 | database: clockDB | ||
181 | 51 | docId: "clockModeDocument" | ||
182 | 52 | defaults: { "digitalMode": false } | ||
183 | 53 | } | ||
184 | 54 | |||
185 | 55 | DateTime { | ||
186 | 56 | id: localTimeSource | ||
187 | 57 | updateInterval: 1000 | ||
188 | 58 | } | ||
189 | 59 | |||
190 | 60 | PageStack { | ||
191 | 61 | id: mainStack | ||
192 | 62 | objectName: "pageStack" | ||
193 | 63 | |||
194 | 64 | Component.onCompleted: push(clockPage) | ||
195 | 65 | |||
196 | 66 | ClockPage { | ||
197 | 67 | id: clockPage | ||
198 | 68 | |||
199 | 69 | Loader { | ||
200 | 70 | id: alarmModelLoader | ||
201 | 71 | asynchronous: false | ||
202 | 72 | } | ||
203 | 73 | |||
204 | 74 | alarmModel: alarmModelLoader.item | ||
205 | 75 | bottomEdgeEnabled: alarmModelLoader.status === Loader.Ready | ||
206 | 76 | clockTime: new Date | ||
207 | 77 | ( | ||
208 | 78 | localTimeSource.localDateString.split(":")[0], | ||
209 | 79 | localTimeSource.localDateString.split(":")[1]-1, | ||
210 | 80 | localTimeSource.localDateString.split(":")[2], | ||
211 | 81 | localTimeSource.localTimeString.split(":")[0], | ||
212 | 82 | localTimeSource.localTimeString.split(":")[1], | ||
213 | 83 | localTimeSource.localTimeString.split(":")[2], | ||
214 | 84 | localTimeSource.localTimeString.split(":")[3] | ||
215 | 85 | ) | ||
216 | 86 | } | ||
217 | 87 | } | ||
218 | 88 | } | ||
219 | 0 | 89 | ||
220 | === added file 'tests/unit/tst_worldClock.qml' | |||
221 | --- tests/unit/tst_worldClock.qml 1970-01-01 00:00:00 +0000 | |||
222 | +++ tests/unit/tst_worldClock.qml 2014-10-14 16:02:15 +0000 | |||
223 | @@ -0,0 +1,194 @@ | |||
224 | 1 | /* | ||
225 | 2 | * Copyright (C) 2014 Canonical Ltd | ||
226 | 3 | * | ||
227 | 4 | * This file is part of Ubuntu Clock App | ||
228 | 5 | * | ||
229 | 6 | * Ubuntu Clock App is free software: you can redistribute it and/or modify | ||
230 | 7 | * it under the terms of the GNU General Public License version 3 as | ||
231 | 8 | * published by the Free Software Foundation. | ||
232 | 9 | * | ||
233 | 10 | * Ubuntu Clock App is distributed in the hope that it will be useful, | ||
234 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
235 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
236 | 13 | * GNU General Public License for more details. | ||
237 | 14 | * | ||
238 | 15 | * You should have received a copy of the GNU General Public License | ||
239 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
240 | 17 | */ | ||
241 | 18 | |||
242 | 19 | import QtQuick 2.0 | ||
243 | 20 | import QtTest 1.0 | ||
244 | 21 | import Ubuntu.Test 1.0 | ||
245 | 22 | import Ubuntu.Components 1.1 | ||
246 | 23 | |||
247 | 24 | MockClockApp { | ||
248 | 25 | id: clockApp | ||
249 | 26 | |||
250 | 27 | ClockTestCase { | ||
251 | 28 | id: worldClockFeatureTest | ||
252 | 29 | name: "WorldClockFeatureTest" | ||
253 | 30 | |||
254 | 31 | when: windowShown | ||
255 | 32 | |||
256 | 33 | property var header | ||
257 | 34 | property var backButton | ||
258 | 35 | property var clockPage | ||
259 | 36 | property var pageStack | ||
260 | 37 | |||
261 | 38 | function initTestCase() { | ||
262 | 39 | header = findChild(clockApp, "MainView_Header") | ||
263 | 40 | backButton = findChild(header, "customBackButton") | ||
264 | 41 | pageStack = findChild(clockApp, "pageStack") | ||
265 | 42 | clockPage = findChild(clockApp, "clockPage") | ||
266 | 43 | } | ||
267 | 44 | |||
268 | 45 | // *********** Helper Functions ************ | ||
269 | 46 | |||
270 | 47 | function pressAddWorldCityButton() { | ||
271 | 48 | var addWorldCityButton = findChild(clockApp, "addWorldCityButton") | ||
272 | 49 | pressButton(addWorldCityButton) | ||
273 | 50 | } | ||
274 | 51 | |||
275 | 52 | function _findWorldCity(cityList, type, cityName, countryName) { | ||
276 | 53 | /* | ||
277 | 54 | The list view for the user world city list and the available world | ||
278 | 55 | city list have the same structure with some minor object name | ||
279 | 56 | changes. The 'objectPrefix' varible is used to handle that. | ||
280 | 57 | */ | ||
281 | 58 | var objectPrefix = type === "user" ? "user" : "default" | ||
282 | 59 | |||
283 | 60 | for(var i=0; i<cityList.count; i++) { | ||
284 | 61 | var cityListItem = findChild(clockApp, objectPrefix+"WorldCityItem"+i) | ||
285 | 62 | var city = findChild(cityListItem, objectPrefix+"CityNameText") | ||
286 | 63 | var country = findChild(cityListItem, objectPrefix+"CountryNameText") | ||
287 | 64 | |||
288 | 65 | if (city.text === cityName && country.text === countryName) { | ||
289 | 66 | return i | ||
290 | 67 | } | ||
291 | 68 | } | ||
292 | 69 | |||
293 | 70 | return -1; | ||
294 | 71 | } | ||
295 | 72 | |||
296 | 73 | function findUserWorldCity(cityList, cityName, countryName) { | ||
297 | 74 | return _findWorldCity(cityList, "user", cityName, countryName) | ||
298 | 75 | } | ||
299 | 76 | |||
300 | 77 | function findDefaultWorldCity(cityList, cityName, countryName) { | ||
301 | 78 | return _findWorldCity(cityList, "default", cityName, countryName) | ||
302 | 79 | } | ||
303 | 80 | |||
304 | 81 | function assertWorldCityAddition(cityName, countryName) { | ||
305 | 82 | var cityList = findChild(clockApp, "userWorldCityRepeater") | ||
306 | 83 | |||
307 | 84 | // Wait for the user list to be populated with results | ||
308 | 85 | tryCompareFunction(function() { return cityList.count > 0}, true) | ||
309 | 86 | |||
310 | 87 | var cityIndex = findUserWorldCity(cityList, cityName, countryName) | ||
311 | 88 | |||
312 | 89 | if (cityIndex === -1) { | ||
313 | 90 | // If city couldn't be found in the saved city list, fail the test | ||
314 | 91 | fail("City added during the test cannot be found in the user world city list!") | ||
315 | 92 | } | ||
316 | 93 | } | ||
317 | 94 | |||
318 | 95 | function deleteWorldCity(cityName, countryName) { | ||
319 | 96 | var cityList = findChild(clockApp, "userWorldCityRepeater") | ||
320 | 97 | |||
321 | 98 | var oldCount = cityList.count | ||
322 | 99 | var cityIndex = findUserWorldCity(cityList, cityName, countryName) | ||
323 | 100 | |||
324 | 101 | if (cityIndex === -1) { | ||
325 | 102 | fail("City added during the test cannot be found in the user world city list!") | ||
326 | 103 | } | ||
327 | 104 | else { | ||
328 | 105 | var cityListItem = findChild(clockApp, "userWorldCityItem"+cityIndex) | ||
329 | 106 | swipeToDeleteItem(cityListItem) | ||
330 | 107 | } | ||
331 | 108 | |||
332 | 109 | /* | ||
333 | 110 | #FIXME: Commented out the following line as deleting a world city | ||
334 | 111 | when there is only one world city does not decrease the count to 0 | ||
335 | 112 | but leaves it as 1 causing the test to fail. This has been reported | ||
336 | 113 | in bug #1368393. (Also fails in Autopilot) | ||
337 | 114 | |||
338 | 115 | tryCompare(cityList, "count", oldCount-1, 5000, "city list count did not decrease") | ||
339 | 116 | |||
340 | 117 | The wait() call below is to ensure that the world city is deleted properly | ||
341 | 118 | which wouldn't be required if could do the count decrease check mentioned above. | ||
342 | 119 | */ | ||
343 | 120 | |||
344 | 121 | wait(1000) | ||
345 | 122 | } | ||
346 | 123 | |||
347 | 124 | function addCityFromList(cityName, countryName) { | ||
348 | 125 | var worldCityPage = getPage(pageStack, "worldCityList") | ||
349 | 126 | var cityList = findChild(worldCityPage, "cityList") | ||
350 | 127 | |||
351 | 128 | // Wait for the list to be populated with results | ||
352 | 129 | tryCompareFunction(function() { return cityList.count > 0}, true) | ||
353 | 130 | |||
354 | 131 | var cityIndex = findDefaultWorldCity(cityList, cityName, countryName) | ||
355 | 132 | |||
356 | 133 | if (cityIndex === -1) { | ||
357 | 134 | fail("City cannot be found in the local world city list") | ||
358 | 135 | } | ||
359 | 136 | |||
360 | 137 | var cityListItem = findChild(cityList, "defaultWorldCityItem"+cityIndex) | ||
361 | 138 | mouseClick(cityListItem, centerOf(cityListItem).x, centerOf(cityListItem).y) | ||
362 | 139 | } | ||
363 | 140 | |||
364 | 141 | function addCityBySearchingOnline(cityName, countryName) { | ||
365 | 142 | pressHeaderButton(header, "searchButton") | ||
366 | 143 | var searchField = findChild(clockApp, "searchField") | ||
367 | 144 | tryCompare(searchField, "visible", true, 5000, "Search field is not visible") | ||
368 | 145 | typeString(cityName) | ||
369 | 146 | addCityFromList(cityName, countryName) | ||
370 | 147 | } | ||
371 | 148 | |||
372 | 149 | // *********** Test Functions ************* | ||
373 | 150 | |||
374 | 151 | /* | ||
375 | 152 | Test to check if a city found in the world city list can be added | ||
376 | 153 | to the user world city list. | ||
377 | 154 | */ | ||
378 | 155 | function test_addCityAlreadyPresentInWorldCityList() { | ||
379 | 156 | var clockPage = getPage(pageStack, "clockPage") | ||
380 | 157 | |||
381 | 158 | pressAddWorldCityButton() | ||
382 | 159 | |||
383 | 160 | var worldCityPage = getPage(pageStack, "worldCityList") | ||
384 | 161 | waitForRendering(worldCityPage) | ||
385 | 162 | |||
386 | 163 | addCityFromList("Amsterdam", "Netherlands") | ||
387 | 164 | assertWorldCityAddition("Amsterdam", "Netherlands") | ||
388 | 165 | |||
389 | 166 | // Clean up after the test by deleting the city which was added during the test | ||
390 | 167 | deleteWorldCity("Amsterdam", "Netherlands") | ||
391 | 168 | } | ||
392 | 169 | |||
393 | 170 | /* | ||
394 | 171 | Test to check if a city now found in the world city list can be added | ||
395 | 172 | by searcing it online and then adding it from the results returned. | ||
396 | 173 | */ | ||
397 | 174 | function test_addCityBySearchingOnline() { | ||
398 | 175 | var clockPage = getPage(pageStack, "clockPage") | ||
399 | 176 | |||
400 | 177 | pressAddWorldCityButton() | ||
401 | 178 | |||
402 | 179 | var worldCityPage = getPage(pageStack, "worldCityList") | ||
403 | 180 | waitForRendering(worldCityPage) | ||
404 | 181 | |||
405 | 182 | /* | ||
406 | 183 | #TODO: Jenkins machine may run in a confined environment with no | ||
407 | 184 | access to internet to run this function. Ideally we should mock | ||
408 | 185 | the data given to this function. | ||
409 | 186 | */ | ||
410 | 187 | addCityBySearchingOnline("Venice", "Provincia di Venezia, Veneto, Italy") | ||
411 | 188 | assertWorldCityAddition("Venice", " Veneto, Italy") | ||
412 | 189 | |||
413 | 190 | // Clean up after the test by deleting the city which was added during the test | ||
414 | 191 | deleteWorldCity("Venice", " Veneto, Italy") | ||
415 | 192 | } | ||
416 | 193 | } | ||
417 | 194 | } |
PASSED: Continuous integration, rev:159 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/560/ 91.189. 93.70:8080/ job/generic- mediumtests- utopic- python3/ 924 91.189. 93.70:8080/ job/generic- mediumtests- utopic- python3/ 924/artifact/ work/output/ *zip*/output. zip
http://
Executed test runs:
SUCCESS: http://
deb: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/560/ rebuild
http://