Merge lp:~martin-borho/ubuntu-weather-app/autopilot-tests into lp:ubuntu-weather-app/obsolete.trunk
- autopilot-tests
- Merge into trunk
Status: | Merged | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Approved by: | Martin Borho | ||||||||||||
Approved revision: | 53 | ||||||||||||
Merged at revision: | 49 | ||||||||||||
Proposed branch: | lp:~martin-borho/ubuntu-weather-app/autopilot-tests | ||||||||||||
Merge into: | lp:ubuntu-weather-app/obsolete.trunk | ||||||||||||
Diff against target: |
645 lines (+418/-32) 11 files modified
components/AddLocationPage.qml (+8/-3) components/LocationManagerPage.qml (+2/-1) components/LocationTab.qml (+1/-0) tests/autopilot/ubuntu_weather_app/emulators/__init__.py (+16/-5) tests/autopilot/ubuntu_weather_app/emulators/main_window.py (+9/-3) tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py (+154/-0) tests/autopilot/ubuntu_weather_app/tests/__init__.py (+72/-6) tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py (+118/-0) tests/autopilot/ubuntu_weather_app/tests/test_mainview.py (+23/-6) tests/autopilot/ubuntu_weather_app/tests/weatherdata.py (+10/-0) ubuntu-weather-app.qml (+5/-8) |
||||||||||||
To merge this branch: | bzr merge lp:~martin-borho/ubuntu-weather-app/autopilot-tests | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nicholas Skaggs (community) | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Review via email: mp+170137@code.launchpad.net |
Commit message
Autopilot tests added for adding, removing and switching of locations..
Description of the change
Autopilot tests added for adding, removing and switching of locations. Bug #1188342, Bug #1188729 and Bug #1188728
$ cd tests/autopilot/
$ autopilot run ubuntu-weather-app
- 47. By Martin Borho
-
fixed add_location test
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 48. By Martin Borho
-
merged from trunk
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:48
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 49. By Martin Borho
-
added test for switching locations
- 50. By Martin Borho
-
splitted location manager tests into smaller parts
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:50
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Nicholas Skaggs (nskaggs) wrote : | # |
Martin, thanks for this. I'll try and review it a bit more in a few hours, but at the moment could you make sure you are using the emulator for this?
https:/
It's going to keep expanding and has many of the common functions your using. It will be easier to standardize and keep best practices if everyone adopts this. See http://
- 51. By Martin Borho
-
autopiloit tests modified to run with ubuntusdk.py
- 52. By Martin Borho
-
commit files missed
- 53. By Martin Borho
-
ubuntusdk.py added from https:/
/code.launchpad .net/~nskaggs/ +junk/ubuntusdk _autopilot_ emulator
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:53
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Martin Borho (martin-borho) wrote : | # |
Since I've already copied the very helpful methods from ubuntusdk.py to main_window.py, I had only to instanciate the TestCase property "main_window" with a ubuntusdk instance. Works so far (main_window.py now obsolete?)
The database related stuff I've copied over from https:/
Cheers
Martin
Nicholas Skaggs (nskaggs) wrote : | # |
Looks excellent Martin -- your no stranger to python :-)
So the localstorage stuff is basically your DatabaseMixin class right? I wonder if I could integrate that generically somehow. Worth thinking about. Thanks!
Preview Diff
1 | === modified file 'components/AddLocationPage.qml' | |||
2 | --- components/AddLocationPage.qml 2013-06-17 15:23:41 +0000 | |||
3 | +++ components/AddLocationPage.qml 2013-06-20 16:20:34 +0000 | |||
4 | @@ -4,7 +4,7 @@ | |||
5 | 4 | 4 | ||
6 | 5 | Page { | 5 | Page { |
7 | 6 | id: addLocationPage | 6 | id: addLocationPage |
9 | 7 | objectName: "AddLocationrPage" | 7 | objectName: "AddLocationPage" |
10 | 8 | title: i18n.tr("Add city") | 8 | title: i18n.tr("Add city") |
11 | 9 | visible: false | 9 | visible: false |
12 | 10 | tools: ToolbarActions{ | 10 | tools: ToolbarActions{ |
13 | @@ -17,6 +17,7 @@ | |||
14 | 17 | source: "./WeatherApi.js" | 17 | source: "./WeatherApi.js" |
15 | 18 | onMessage: { | 18 | onMessage: { |
16 | 19 | if(!messageObject.error) { | 19 | if(!messageObject.error) { |
17 | 20 | listView.visible = true | ||
18 | 20 | messageObject.result.locations.forEach(function(loc) { | 21 | messageObject.result.locations.forEach(function(loc) { |
19 | 21 | citiesModel.append(loc); | 22 | citiesModel.append(loc); |
20 | 22 | }); | 23 | }); |
21 | @@ -27,8 +28,9 @@ | |||
22 | 27 | } | 28 | } |
23 | 28 | 29 | ||
24 | 29 | function clear() { | 30 | function clear() { |
27 | 30 | locationString.text = '' | 31 | locationString.text = ''; |
28 | 31 | citiesModel.clear() | 32 | citiesModel.clear(); |
29 | 33 | listView.visible = true; | ||
30 | 32 | } | 34 | } |
31 | 33 | 35 | ||
32 | 34 | Rectangle { | 36 | Rectangle { |
33 | @@ -38,6 +40,7 @@ | |||
34 | 38 | color: "transparent" | 40 | color: "transparent" |
35 | 39 | TextField { | 41 | TextField { |
36 | 40 | id: locationString | 42 | id: locationString |
37 | 43 | objectName: "SearchField" | ||
38 | 41 | width: parent.width-units.gu(2) | 44 | width: parent.width-units.gu(2) |
39 | 42 | height:units.gu(5) | 45 | height:units.gu(5) |
40 | 43 | anchors.centerIn: parent | 46 | anchors.centerIn: parent |
41 | @@ -65,6 +68,8 @@ | |||
42 | 65 | color: "transparent" | 68 | color: "transparent" |
43 | 66 | ListView { | 69 | ListView { |
44 | 67 | id: listView; | 70 | id: listView; |
45 | 71 | objectName: "SearchResultList" | ||
46 | 72 | visible: false | ||
47 | 68 | clip: true; | 73 | clip: true; |
48 | 69 | anchors.fill: parent; | 74 | anchors.fill: parent; |
49 | 70 | model: citiesModel; | 75 | model: citiesModel; |
50 | 71 | 76 | ||
51 | === modified file 'components/LocationManagerPage.qml' | |||
52 | --- components/LocationManagerPage.qml 2013-06-17 15:23:41 +0000 | |||
53 | +++ components/LocationManagerPage.qml 2013-06-20 16:20:34 +0000 | |||
54 | @@ -146,7 +146,7 @@ | |||
55 | 146 | color:"transparent" | 146 | color:"transparent" |
56 | 147 | height: units.gu(40) | 147 | height: units.gu(40) |
57 | 148 | ListView { | 148 | ListView { |
59 | 149 | objectName: "locationList" | 149 | objectName: "LocationList" |
60 | 150 | anchors.fill: parent | 150 | anchors.fill: parent |
61 | 151 | model: locationModel | 151 | model: locationModel |
62 | 152 | delegate: ListItem.Standard { | 152 | delegate: ListItem.Standard { |
63 | @@ -164,6 +164,7 @@ | |||
64 | 164 | } | 164 | } |
65 | 165 | } | 165 | } |
66 | 166 | footer: ListItem.Standard { | 166 | footer: ListItem.Standard { |
67 | 167 | objectName: "AddCityListItem" | ||
68 | 167 | text: i18n.tr("Add city") | 168 | text: i18n.tr("Add city") |
69 | 168 | progression: true | 169 | progression: true |
70 | 169 | onClicked: pageStack.push(addLocationPage) | 170 | onClicked: pageStack.push(addLocationPage) |
71 | 170 | 171 | ||
72 | === modified file 'components/LocationTab.qml' | |||
73 | --- components/LocationTab.qml 2013-06-17 19:22:19 +0000 | |||
74 | +++ components/LocationTab.qml 2013-06-20 16:20:34 +0000 | |||
75 | @@ -4,6 +4,7 @@ | |||
76 | 4 | 4 | ||
77 | 5 | Tab { | 5 | Tab { |
78 | 6 | id: locationTab | 6 | id: locationTab |
79 | 7 | objectName: "LocationTab" | ||
80 | 7 | property int locationIndex: 0 | 8 | property int locationIndex: 0 |
81 | 8 | property var locationData: {} | 9 | property var locationData: {} |
82 | 9 | 10 | ||
83 | 10 | 11 | ||
84 | === modified file 'tests/autopilot/ubuntu_weather_app/emulators/__init__.py' | |||
85 | --- tests/autopilot/ubuntu_weather_app/emulators/__init__.py 2013-04-05 08:12:09 +0000 | |||
86 | +++ tests/autopilot/ubuntu_weather_app/emulators/__init__.py 2013-06-20 16:20:34 +0000 | |||
87 | @@ -1,6 +1,17 @@ | |||
88 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
94 | 2 | # Copyright 2013 Canonical | 2 | # |
95 | 3 | # | 3 | # Copyright (C) 2013 Canonical Ltd |
96 | 4 | # This program is free software: you can redistribute it and/or modify it | 4 | # |
97 | 5 | # under the terms of the GNU General Public License version 3, as published | 5 | # This program is free software: you can redistribute it and/or modify |
98 | 6 | # by the Free Software Foundation. | 6 | # it under the terms of the GNU General Public License version 3 as |
99 | 7 | # published by the Free Software Foundation. | ||
100 | 8 | # | ||
101 | 9 | # This program is distributed in the hope that it will be useful, | ||
102 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
103 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
104 | 12 | # GNU General Public License for more details. | ||
105 | 13 | # | ||
106 | 14 | # You should have received a copy of the GNU General Public License | ||
107 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
108 | 16 | # | ||
109 | 17 | # Authored by: Nicholas Skaggs <nicholas.skaggs@canonical.com> | ||
110 | 7 | 18 | ||
111 | === modified file 'tests/autopilot/ubuntu_weather_app/emulators/main_window.py' | |||
112 | --- tests/autopilot/ubuntu_weather_app/emulators/main_window.py 2013-04-08 07:59:44 +0000 | |||
113 | +++ tests/autopilot/ubuntu_weather_app/emulators/main_window.py 2013-06-20 16:20:34 +0000 | |||
114 | @@ -9,11 +9,17 @@ | |||
115 | 9 | class MainWindow(object): | 9 | class MainWindow(object): |
116 | 10 | """An emulator class that makes it easy to interact with the weather app""" | 10 | """An emulator class that makes it easy to interact with the weather app""" |
117 | 11 | 11 | ||
119 | 12 | def __init__(self, app): | 12 | def __init__(self, autopilot, app): |
120 | 13 | self.app = app | 13 | self.app = app |
121 | 14 | self.autopilot= autopilot | ||
122 | 14 | 15 | ||
123 | 15 | def get_qml_view(self): | 16 | def get_qml_view(self): |
124 | 16 | return self.app.select_single("QQuickView") | 17 | return self.app.select_single("QQuickView") |
125 | 17 | 18 | ||
128 | 18 | def get_tabs(self): | 19 | def get_object(self, typeName, name): |
129 | 19 | return self.app.select_single("Tabs", objectName="Tabs") | 20 | """Get a specific object""" |
130 | 21 | return self.app.select_single(typeName, objectName=name) | ||
131 | 22 | |||
132 | 23 | def get_objects(self, typeName, name): | ||
133 | 24 | """Get more than one object""" | ||
134 | 25 | return self.app.select_many(typeName, objectName=name) | ||
135 | 20 | 26 | ||
136 | === added file 'tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py' | |||
137 | --- tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py 1970-01-01 00:00:00 +0000 | |||
138 | +++ tests/autopilot/ubuntu_weather_app/emulators/ubuntusdk.py 2013-06-20 16:20:34 +0000 | |||
139 | @@ -0,0 +1,154 @@ | |||
140 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
141 | 2 | # | ||
142 | 3 | # Copyright (C) 2013 Canonical Ltd | ||
143 | 4 | # | ||
144 | 5 | # This program is free software: you can redistribute it and/or modify | ||
145 | 6 | # it under the terms of the GNU General Public License version 3 as | ||
146 | 7 | # published by the Free Software Foundation. | ||
147 | 8 | # | ||
148 | 9 | # This program is distributed in the hope that it will be useful, | ||
149 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
150 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
151 | 12 | # GNU General Public License for more details. | ||
152 | 13 | # | ||
153 | 14 | # You should have received a copy of the GNU General Public License | ||
154 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
155 | 16 | # | ||
156 | 17 | # Authored by: Nicholas Skaggs <nicholas.skaggs@canonical.com> | ||
157 | 18 | |||
158 | 19 | from testtools.matchers import Equals, NotEquals, Not, Is | ||
159 | 20 | from autopilot.matchers import Eventually | ||
160 | 21 | |||
161 | 22 | class ubuntusdk(object): | ||
162 | 23 | """An emulator class that makes it easy to interact with the ubuntu sdk applications.""" | ||
163 | 24 | |||
164 | 25 | def __init__(self, autopilot, app): | ||
165 | 26 | self.app = app | ||
166 | 27 | self.autopilot = autopilot | ||
167 | 28 | |||
168 | 29 | def get_qml_view(self): | ||
169 | 30 | """Get the main QML view""" | ||
170 | 31 | return self.app.select_single("QQuickView") | ||
171 | 32 | |||
172 | 33 | def get_object(self, typeName, name): | ||
173 | 34 | """Get a specific object""" | ||
174 | 35 | return self.app.select_single(typeName, objectName=name) | ||
175 | 36 | |||
176 | 37 | def get_objects(self, typeName, name): | ||
177 | 38 | """Get more than one object""" | ||
178 | 39 | return self.app.select_many(typeName, objectName=name) | ||
179 | 40 | |||
180 | 41 | def switch_to_tab(self, tab): | ||
181 | 42 | """Switch to the specified tab number""" | ||
182 | 43 | tabs = self.get_tabs() | ||
183 | 44 | currentTab = tabs.selectedTabIndex | ||
184 | 45 | |||
185 | 46 | #perform operations until tab == currentTab | ||
186 | 47 | while tab != currentTab: | ||
187 | 48 | if tab > currentTab: | ||
188 | 49 | self._previous_tab() | ||
189 | 50 | if tab < currentTab: | ||
190 | 51 | self._next_tab() | ||
191 | 52 | currentTab = tabs.selectedTabIndex | ||
192 | 53 | |||
193 | 54 | def toggle_toolbar(self): | ||
194 | 55 | """Toggle the toolbar between revealed and hidden""" | ||
195 | 56 | #check and see if the toolbar is open or not | ||
196 | 57 | if self.get_toolbar().opened: | ||
197 | 58 | self.hide_toolbar() | ||
198 | 59 | else: | ||
199 | 60 | self.open_toolbar() | ||
200 | 61 | |||
201 | 62 | def get_toolbar(self): | ||
202 | 63 | """Returns the toolbar in the main events view.""" | ||
203 | 64 | return self.app.select_single("Toolbar") | ||
204 | 65 | |||
205 | 66 | def get_toolbar_button(self, buttonLabel): | ||
206 | 67 | """Returns the toolbar button at position index""" | ||
207 | 68 | toolbar = self.get_toolbar() | ||
208 | 69 | if not toolbar.opened: | ||
209 | 70 | self.open_toolbar() | ||
210 | 71 | row = toolbar.select_single("QQuickRow") | ||
211 | 72 | loaderList = row.select_many("QQuickLoader") | ||
212 | 73 | for loader in loaderList: | ||
213 | 74 | buttonList = loader.select_many("Button") | ||
214 | 75 | for button in buttonList: | ||
215 | 76 | if button.text == buttonLabel: | ||
216 | 77 | return button | ||
217 | 78 | |||
218 | 79 | def click_toolbar_button(self, buttonLabel): | ||
219 | 80 | """Clicks the toolbar button with buttonLabel""" | ||
220 | 81 | #The toolbar button is assumed to be the following format | ||
221 | 82 | #ToolbarActions { | ||
222 | 83 | # Action { | ||
223 | 84 | # objectName: "name" | ||
224 | 85 | # text: value | ||
225 | 86 | button = self.get_toolbar_button(buttonLabel) | ||
226 | 87 | self.autopilot.pointing_device.click_object(button) | ||
227 | 88 | |||
228 | 89 | def open_toolbar(self): | ||
229 | 90 | """Open the toolbar""" | ||
230 | 91 | qmlView = self.get_qml_view() | ||
231 | 92 | |||
232 | 93 | lineX = qmlView.x + qmlView.width * 0.50 | ||
233 | 94 | startY = qmlView.y + qmlView.height - 1 | ||
234 | 95 | stopY = qmlView.y + qmlView.height * 0.95 | ||
235 | 96 | |||
236 | 97 | self.autopilot.pointing_device.drag(lineX, startY, lineX, stopY) | ||
237 | 98 | |||
238 | 99 | def hide_toolbar(self): | ||
239 | 100 | """Hide the toolbar""" | ||
240 | 101 | qmlView = self.get_qml_view() | ||
241 | 102 | |||
242 | 103 | lineX = qmlView.x + qmlView.width * 0.50 | ||
243 | 104 | startY = qmlView.y + qmlView.height * 0.95 | ||
244 | 105 | stopY = qmlView.y + qmlView.height - 1 | ||
245 | 106 | |||
246 | 107 | self.autopilot.pointing_device.drag(lineX, startY, lineX, stopY) | ||
247 | 108 | |||
248 | 109 | def set_popup_value(self, popover, button, value): | ||
249 | 110 | """Changes the given popover selector to the request value | ||
250 | 111 | At the moment this only works for values that are currently visible. To | ||
251 | 112 | access the remaining items, a help method to drag and recheck is needed.""" | ||
252 | 113 | #The popover is assumed to be the following format | ||
253 | 114 | # Popover { | ||
254 | 115 | # Column { | ||
255 | 116 | # ListView { | ||
256 | 117 | # delegate: Standard { | ||
257 | 118 | # objectName: "name" | ||
258 | 119 | # text: value | ||
259 | 120 | |||
260 | 121 | self.autopilot.pointing_device.click_object(button) | ||
261 | 122 | #we'll get all matching objects, incase the popover is reused between buttons | ||
262 | 123 | itemList = lambda: self.get_objects("Standard", popover) | ||
263 | 124 | |||
264 | 125 | for item in itemList(): | ||
265 | 126 | if item.get_properties()['text'] == value: | ||
266 | 127 | self.autopilot.pointing_device.click_object(item) | ||
267 | 128 | |||
268 | 129 | def get_tabs(self): | ||
269 | 130 | """Return all tabs""" | ||
270 | 131 | return self.get_object("Tabs", "rootTabs") | ||
271 | 132 | |||
272 | 133 | def _previous_tab(self): | ||
273 | 134 | """Switch to the previous tab""" | ||
274 | 135 | qmlView = self.get_qml_view() | ||
275 | 136 | |||
276 | 137 | startX = qmlView.x + qmlView.width * 0.35 | ||
277 | 138 | stopX = qmlView.x + qmlView.width * 0.50 | ||
278 | 139 | lineY = qmlView.y + qmlView.height * 0.05 | ||
279 | 140 | |||
280 | 141 | self.autopilot.pointing_device.drag(startX, lineY, stopX, lineY) | ||
281 | 142 | self.autopilot.pointing_device.click() | ||
282 | 143 | self.autopilot.pointing_device.click() | ||
283 | 144 | |||
284 | 145 | def _next_tab(self): | ||
285 | 146 | """Switch to the next tab""" | ||
286 | 147 | qmlView = self.get_qml_view() | ||
287 | 148 | |||
288 | 149 | startX = qmlView.x + qmlView.width * 0.50 | ||
289 | 150 | stopX = qmlView.x + qmlView.width * 0.35 | ||
290 | 151 | lineY = qmlView.y + qmlView.height * 0.05 | ||
291 | 152 | |||
292 | 153 | self.autopilot.pointing_device.drag(startX, lineY, stopX, lineY) | ||
293 | 154 | self.autopilot.pointing_device.click() | ||
294 | 0 | 155 | ||
295 | === modified file 'tests/autopilot/ubuntu_weather_app/tests/__init__.py' | |||
296 | --- tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-05-31 13:21:10 +0000 | |||
297 | +++ tests/autopilot/ubuntu_weather_app/tests/__init__.py 2013-06-20 16:20:34 +0000 | |||
298 | @@ -9,13 +9,15 @@ | |||
299 | 9 | 9 | ||
300 | 10 | import os.path | 10 | import os.path |
301 | 11 | import glob | 11 | import glob |
302 | 12 | import sqlite3 | ||
303 | 13 | import time | ||
304 | 12 | 14 | ||
305 | 13 | from autopilot.input import Mouse, Touch, Pointer | 15 | from autopilot.input import Mouse, Touch, Pointer |
306 | 14 | from autopilot.platform import model | 16 | from autopilot.platform import model |
307 | 15 | from autopilot.testcase import AutopilotTestCase | 17 | from autopilot.testcase import AutopilotTestCase |
308 | 16 | 18 | ||
309 | 17 | from ubuntu_weather_app.emulators.main_window import MainWindow | 19 | from ubuntu_weather_app.emulators.main_window import MainWindow |
311 | 18 | 20 | from ubuntu_weather_app.emulators.ubuntusdk import ubuntusdk | |
312 | 19 | 21 | ||
313 | 20 | class WeatherTestCase(AutopilotTestCase): | 22 | class WeatherTestCase(AutopilotTestCase): |
314 | 21 | 23 | ||
315 | @@ -32,10 +34,7 @@ | |||
316 | 32 | def setUp(self): | 34 | def setUp(self): |
317 | 33 | self.pointing_device = Pointer(self.input_device_class.create()) | 35 | self.pointing_device = Pointer(self.input_device_class.create()) |
318 | 34 | super(WeatherTestCase, self).setUp() | 36 | super(WeatherTestCase, self).setUp() |
323 | 35 | if os.path.exists(self.local_location): | 37 | self.launch_app() |
320 | 36 | self.launch_test_local() | ||
321 | 37 | else: | ||
322 | 38 | self.launch_test_installed() | ||
324 | 39 | 38 | ||
325 | 40 | """Workaround to find the qmlscene binary via shell globbing. | 39 | """Workaround to find the qmlscene binary via shell globbing. |
326 | 41 | This is needed since we can't rely on qt5-default being installed on | 40 | This is needed since we can't rely on qt5-default being installed on |
327 | @@ -43,6 +42,12 @@ | |||
328 | 43 | def qmlscene(self): | 42 | def qmlscene(self): |
329 | 44 | return glob.glob("/usr/lib/*/qt5/bin/qmlscene")[0] | 43 | return glob.glob("/usr/lib/*/qt5/bin/qmlscene")[0] |
330 | 45 | 44 | ||
331 | 45 | def launch_app(self): | ||
332 | 46 | if os.path.exists(self.local_location): | ||
333 | 47 | self.launch_test_local() | ||
334 | 48 | else: | ||
335 | 49 | self.launch_test_installed() | ||
336 | 50 | |||
337 | 46 | def launch_test_local(self): | 51 | def launch_test_local(self): |
338 | 47 | self.app = self.launch_test_application( | 52 | self.app = self.launch_test_application( |
339 | 48 | self.qmlscene(), | 53 | self.qmlscene(), |
340 | @@ -56,6 +61,67 @@ | |||
341 | 56 | "--desktop_file_hint=/usr/share/applications/ubuntu-weather-app.desktop", | 61 | "--desktop_file_hint=/usr/share/applications/ubuntu-weather-app.desktop", |
342 | 57 | app_type='qt') | 62 | app_type='qt') |
343 | 58 | 63 | ||
344 | 64 | def launch_and_quit_app(self): | ||
345 | 65 | self.launch_app() | ||
346 | 66 | self.main_window.get_qml_view().visible.wait_for(True) | ||
347 | 67 | |||
348 | 68 | # When calling launch_app an instance of the spawned process | ||
349 | 69 | # control object will be stored in self.app.process, and a cleanup | ||
350 | 70 | # handler will be registered that essentially kills the process. | ||
351 | 71 | # Therefore, by triggering the cleanup handler here we're killing the | ||
352 | 72 | # process and removing the handler, which allows a clean launch of | ||
353 | 73 | # the process during regular test setup. | ||
354 | 74 | self.doCleanups() | ||
355 | 75 | |||
356 | 59 | @property | 76 | @property |
357 | 60 | def main_window(self): | 77 | def main_window(self): |
359 | 61 | return MainWindow(self.app) | 78 | return ubuntusdk(self, self.app)#MainWindow(self, self.app) |
360 | 79 | |||
361 | 80 | |||
362 | 81 | class DatabaseMixin(object): | ||
363 | 82 | |||
364 | 83 | """ | ||
365 | 84 | Helper functions for dealing with sqlite databases | ||
366 | 85 | """ | ||
367 | 86 | |||
368 | 87 | def find_db(self): | ||
369 | 88 | dbs_path = os.path.expanduser("~/.local/share/Qt Project/QtQmlViewer/QML/OfflineStorage/Databases/") | ||
370 | 89 | if not os.path.exists(dbs_path): | ||
371 | 90 | return None | ||
372 | 91 | |||
373 | 92 | files = [ f for f in os.listdir(dbs_path) if os.path.splitext(f)[1] == ".ini" ] | ||
374 | 93 | for f in files: | ||
375 | 94 | ini_path = os.path.join(dbs_path, f) | ||
376 | 95 | with open(ini_path) as ini: | ||
377 | 96 | for line in ini: | ||
378 | 97 | if "=" in line: | ||
379 | 98 | key, val = line.strip().split("=") | ||
380 | 99 | if key == "Name" and val == "ubuntu-weather-app": | ||
381 | 100 | try: | ||
382 | 101 | return ini_path.replace(".ini", ".sqlite") | ||
383 | 102 | except OSError: | ||
384 | 103 | pass | ||
385 | 104 | return None | ||
386 | 105 | |||
387 | 106 | def clean_db(self): | ||
388 | 107 | path = self.find_db() | ||
389 | 108 | if path is None: | ||
390 | 109 | self.launch_and_quit_app() | ||
391 | 110 | path = self.find_db() | ||
392 | 111 | if path is None: | ||
393 | 112 | self.assertNotEquals(path, None) | ||
394 | 113 | |||
395 | 114 | try: | ||
396 | 115 | os.remove(path) | ||
397 | 116 | except OSError: | ||
398 | 117 | pass | ||
399 | 118 | |||
400 | 119 | def save_locations_to_storage(self, locations): | ||
401 | 120 | path = self.find_db() | ||
402 | 121 | conn = sqlite3.connect(path) | ||
403 | 122 | cursor = conn.cursor() | ||
404 | 123 | for loc_data in locations: | ||
405 | 124 | cursor.execute("INSERT INTO Locations(date, data) VALUES('{}', '{}')".format(int(time.time()*1000), loc_data)) | ||
406 | 125 | conn.commit() | ||
407 | 126 | conn.close() | ||
408 | 127 | |||
409 | 62 | 128 | ||
410 | === added file 'tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py' | |||
411 | --- tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 1970-01-01 00:00:00 +0000 | |||
412 | +++ tests/autopilot/ubuntu_weather_app/tests/test_locationmanager.py 2013-06-20 16:20:34 +0000 | |||
413 | @@ -0,0 +1,118 @@ | |||
414 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
415 | 2 | # Copyright 2013 Canonical | ||
416 | 3 | # | ||
417 | 4 | # This program is free software: you can redistribute it and/or modify it | ||
418 | 5 | # under the terms of the GNU General Public License version 3, as published | ||
419 | 6 | # by the Free Software Foundation. | ||
420 | 7 | |||
421 | 8 | """Tests for managing locations in Weather app""" | ||
422 | 9 | |||
423 | 10 | from __future__ import absolute_import | ||
424 | 11 | |||
425 | 12 | from testtools.matchers import Equals | ||
426 | 13 | from autopilot.matchers import Eventually | ||
427 | 14 | |||
428 | 15 | from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin | ||
429 | 16 | from ubuntu_weather_app.tests.weatherdata import locations_data | ||
430 | 17 | |||
431 | 18 | class TestLocationManager(WeatherTestCase, DatabaseMixin): | ||
432 | 19 | def setUp(self): | ||
433 | 20 | self.clean_db() | ||
434 | 21 | super(TestLocationManager, self).setUp() | ||
435 | 22 | self.assertThat( | ||
436 | 23 | self.main_window.get_qml_view().visible, Eventually(Equals(True))) | ||
437 | 24 | |||
438 | 25 | def _open_add_location_page(self): | ||
439 | 26 | """Opens the AddLocationPage""" | ||
440 | 27 | # click on listitem to open AddLocationPage | ||
441 | 28 | locationList = self.main_window.get_object('QQuickListView', 'LocationList') | ||
442 | 29 | addCityItem = locationList.get_children()[0] | ||
443 | 30 | self.pointing_device.move_to_object(addCityItem) | ||
444 | 31 | self.pointing_device.click() | ||
445 | 32 | |||
446 | 33 | addLocPage = self.main_window.get_object("AddLocationPage", "AddLocationPage") | ||
447 | 34 | self.assertThat(addLocPage.visible, Eventually(Equals(True))) | ||
448 | 35 | |||
449 | 36 | def test_add_location(self): | ||
450 | 37 | """Adds a location""" | ||
451 | 38 | self._open_add_location_page() | ||
452 | 39 | |||
453 | 40 | # insert city name to search for | ||
454 | 41 | searchField = self.main_window.get_object("TextField", "SearchField") | ||
455 | 42 | self.pointing_device.move_to_object(searchField) | ||
456 | 43 | self.pointing_device.click() | ||
457 | 44 | self.keyboard.type("London") | ||
458 | 45 | self.assertThat(searchField.text, Eventually(Equals("London"))) | ||
459 | 46 | self.keyboard.press_and_release('Enter') | ||
460 | 47 | |||
461 | 48 | # wait for results and click on the first item | ||
462 | 49 | resultsList = self.main_window.get_object('QQuickListView', 'SearchResultList') | ||
463 | 50 | resultsModel = self.main_window.get_object('QQuickListModel', 'CitiesModel') | ||
464 | 51 | self.assertThat(resultsList.visible, Eventually(Equals(True), timeout=30)) | ||
465 | 52 | firstResult = resultsList.get_children()[0].get_children()[0] | ||
466 | 53 | self.pointing_device.move_to_object(firstResult) | ||
467 | 54 | self.pointing_device.click() | ||
468 | 55 | |||
469 | 56 | # LocationManagerPage should be visible and "London" added | ||
470 | 57 | locationList = self.main_window.get_object('QQuickListView', 'LocationList') | ||
471 | 58 | addedItem = locationList.get_children()[0] | ||
472 | 59 | self.assertThat(addedItem.get_children()[1].text, Eventually(Equals("London"))) | ||
473 | 60 | |||
474 | 61 | # a location is defined, so toolbar should be visible | ||
475 | 62 | toolbar = self.main_window.get_toolbar() | ||
476 | 63 | self.assertThat(toolbar.opened, Eventually(Equals(True))) | ||
477 | 64 | |||
478 | 65 | def test_toolbar_hidden_when_no_location_is_defined(self): | ||
479 | 66 | """Toolbar is not visible when there's no location is defined""" | ||
480 | 67 | toolbar = self.main_window.get_toolbar() | ||
481 | 68 | self.assertThat(toolbar.opened, Eventually(Equals(False))) | ||
482 | 69 | |||
483 | 70 | """no way found to click the back button""" | ||
484 | 71 | #def test_cancel_adding_location(self): | ||
485 | 72 | # self.open_add_location_page() | ||
486 | 73 | # self.main_window.click_toolbar_button("Back") | ||
487 | 74 | # locationList = self.main_window.get_object('QQuickListView', 'LocationList') | ||
488 | 75 | # self.assertThat(locationList, Eventually(Equals(True))) | ||
489 | 76 | |||
490 | 77 | class TestLocationManagerWithLocation(WeatherTestCase, DatabaseMixin): | ||
491 | 78 | def setUp(self): | ||
492 | 79 | self.clean_db() | ||
493 | 80 | self.launch_and_quit_app() | ||
494 | 81 | # add one location to storage | ||
495 | 82 | self.save_locations_to_storage([locations_data[0]]) | ||
496 | 83 | super(TestLocationManagerWithLocation, self).setUp() | ||
497 | 84 | self.assertThat( | ||
498 | 85 | self.main_window.get_qml_view().visible, Eventually(Equals(True))) | ||
499 | 86 | |||
500 | 87 | def _open_location_manager(self): | ||
501 | 88 | """Opens the location manager""" | ||
502 | 89 | self.main_window.open_toolbar() | ||
503 | 90 | self.assertThat(self.main_window.get_toolbar().opened, Eventually(Equals(True))) | ||
504 | 91 | self.main_window.click_toolbar_button("Edit") | ||
505 | 92 | |||
506 | 93 | def test_remove_location(self): | ||
507 | 94 | """Removes location""" | ||
508 | 95 | # check loading screen diappears | ||
509 | 96 | loadingPage = self.main_window.get_object("Tabs", "LoadingTabs") | ||
510 | 97 | self.assertThat(loadingPage.visible, Eventually(Equals(False))) | ||
511 | 98 | |||
512 | 99 | # go to the location manegr | ||
513 | 100 | self._open_location_manager() | ||
514 | 101 | |||
515 | 102 | # swipe right to delete the first location | ||
516 | 103 | locationList = self.main_window.get_object('QQuickListView', 'LocationList') | ||
517 | 104 | locItem = locationList.get_children()[0] | ||
518 | 105 | loc_x, loc_y, loc_w, loc_h = locItem.globalRect | ||
519 | 106 | self.pointing_device.move(loc_x + 10, loc_y + loc_h / 2) | ||
520 | 107 | self.pointing_device.press() | ||
521 | 108 | self.pointing_device.move(loc_x + loc_w - 10, loc_y + loc_h / 2) | ||
522 | 109 | self.pointing_device.release() | ||
523 | 110 | |||
524 | 111 | # toolbar disappears since no locations defined | ||
525 | 112 | self.assertThat(self.main_window.get_toolbar().opened, Eventually(Equals(False))) | ||
526 | 113 | |||
527 | 114 | def test_toolbar_opened_when_location_is_defined(self): | ||
528 | 115 | """Toolbar is visible since there's a location defined""" | ||
529 | 116 | self._open_location_manager() | ||
530 | 117 | toolbar = self.main_window.get_toolbar() | ||
531 | 118 | self.assertThat(toolbar.opened, Eventually(Equals(True))) | ||
532 | 0 | 119 | ||
533 | === modified file 'tests/autopilot/ubuntu_weather_app/tests/test_mainview.py' | |||
534 | --- tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-05-31 13:21:10 +0000 | |||
535 | +++ tests/autopilot/ubuntu_weather_app/tests/test_mainview.py 2013-06-20 16:20:34 +0000 | |||
536 | @@ -12,15 +12,18 @@ | |||
537 | 12 | from testtools.matchers import Equals | 12 | from testtools.matchers import Equals |
538 | 13 | from autopilot.matchers import Eventually | 13 | from autopilot.matchers import Eventually |
539 | 14 | 14 | ||
544 | 15 | from ubuntu_weather_app.tests import WeatherTestCase | 15 | from ubuntu_weather_app.tests import WeatherTestCase, DatabaseMixin |
545 | 16 | 16 | from ubuntu_weather_app.tests.weatherdata import locations_data | |
546 | 17 | 17 | ||
547 | 18 | class TestMainView(WeatherTestCase): | 18 | class TestMainView(WeatherTestCase, DatabaseMixin): |
548 | 19 | """Tests creating weather""" | 19 | """Tests creating weather""" |
549 | 20 | 20 | ||
550 | 21 | """ This is needed to wait for the application to start. | 21 | """ This is needed to wait for the application to start. |
551 | 22 | In the testfarm, the application may take some time to show up.""" | 22 | In the testfarm, the application may take some time to show up.""" |
552 | 23 | def setUp(self): | 23 | def setUp(self): |
553 | 24 | self.clean_db() | ||
554 | 25 | self.launch_and_quit_app() | ||
555 | 26 | self.save_locations_to_storage(locations_data) | ||
556 | 24 | super(TestMainView, self).setUp() | 27 | super(TestMainView, self).setUp() |
557 | 25 | self.assertThat( | 28 | self.assertThat( |
558 | 26 | self.main_window.get_qml_view().visible, Eventually(Equals(True))) | 29 | self.main_window.get_qml_view().visible, Eventually(Equals(True))) |
559 | @@ -28,6 +31,20 @@ | |||
560 | 28 | def tearDown(self): | 31 | def tearDown(self): |
561 | 29 | super(TestMainView, self).tearDown() | 32 | super(TestMainView, self).tearDown() |
562 | 30 | 33 | ||
565 | 31 | def test_tabs(self): | 34 | def test_switch_tabs(self): |
566 | 32 | tabs = self.main_window.get_tabs() | 35 | """Test start of app with two locations and switch from first to |
567 | 36 | second tab""" | ||
568 | 37 | # first tab should be visible after start | ||
569 | 38 | tabs = self.main_window.get_tabs() | ||
570 | 39 | tabObjects = self.main_window.get_objects('LocationTab','LocationTab') | ||
571 | 33 | self.assertThat(tabs.selectedTabIndex, Eventually(Equals(0))) | 40 | self.assertThat(tabs.selectedTabIndex, Eventually(Equals(0))) |
572 | 41 | self.assertThat(tabObjects[0].visible, Eventually(Equals(True))) | ||
573 | 42 | self.assertThat(tabObjects[1].visible, Eventually(Equals(False))) | ||
574 | 43 | self.assertThat(tabObjects[0].title, Eventually(Equals("London"))) | ||
575 | 44 | # switch to next tab | ||
576 | 45 | self.main_window.switch_to_tab(1) | ||
577 | 46 | self.assertThat(tabs.selectedTabIndex, Eventually(Equals(1))) | ||
578 | 47 | self.assertThat(tabObjects[0].visible, Eventually(Equals(False))) | ||
579 | 48 | self.assertThat(tabObjects[1].visible, Eventually(Equals(True))) | ||
580 | 49 | self.assertThat(tabObjects[1].title, Eventually(Equals("Hamburg"))) | ||
581 | 50 | |||
582 | 34 | 51 | ||
583 | === added file 'tests/autopilot/ubuntu_weather_app/tests/weatherdata.py' | |||
584 | --- tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 1970-01-01 00:00:00 +0000 | |||
585 | +++ tests/autopilot/ubuntu_weather_app/tests/weatherdata.py 2013-06-20 16:20:34 +0000 | |||
586 | @@ -0,0 +1,10 @@ | |||
587 | 1 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- | ||
588 | 2 | # Copyright 2013 Canonical | ||
589 | 3 | # | ||
590 | 4 | # This program is free software: you can redistribute it and/or modify it | ||
591 | 5 | # under the terms of the GNU General Public License version 3, as published | ||
592 | 6 | # by the Free Software Foundation. | ||
593 | 7 | locations_data = [] | ||
594 | 8 | locations_data.append( """{"daily":{"request":{"type":"daily","url":"http://api.openweathermap.org/data/2.5/forecast/daily?id=2643743&cnt=10&units=metric"},"results":[{"timestamp":1371556800,"pressure":1018.07,"metric":{"eve":18.45,"morn":20.61,"night":12.92,"max":20.61,"day":20.61,"min":12.92},"wind_speed":1.77,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":99,"humidity":77,"imperial":{"eve":65.21000000000001,"morn":69.098,"night":55.256,"max":69.098,"day":69.098,"min":55.256}},{"timestamp":1371643200,"pressure":1018.59,"metric":{"eve":19.63,"morn":14.05,"night":15.99,"max":20.92,"day":18.54,"min":14.05},"wind_speed":1.63,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":31,"humidity":97,"imperial":{"eve":67.334,"morn":57.290000000000006,"night":60.782,"max":69.656,"day":65.372,"min":57.290000000000006}},{"timestamp":1371729600,"pressure":1016.49,"metric":{"eve":18.31,"morn":16.07,"night":14.48,"max":19.64,"day":16.82,"min":14.48},"wind_speed":1.76,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":211,"humidity":92,"imperial":{"eve":64.958,"morn":60.926,"night":58.064,"max":67.352,"day":62.275999999999996,"min":58.064}},{"timestamp":1371816000,"pressure":1015.82,"metric":{"eve":18.09,"morn":13.73,"night":14.89,"max":18.65,"day":17.55,"min":13.73},"wind_speed":3.27,"condition":{"icon":"03d","description":"scattered clouds","id":802,"main":"Clouds"},"wind_deg":257,"humidity":78,"imperial":{"eve":64.562,"morn":56.714,"night":58.80200000000001,"max":65.57,"day":63.59,"min":56.714}},{"timestamp":1371902400,"pressure":1003.45,"metric":{"eve":13.5,"morn":12.02,"night":13.04,"max":13.98,"day":13.98,"min":12.02},"wind_speed":6.11,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":215,"humidity":84,"imperial":{"eve":56.3,"morn":53.635999999999996,"night":55.471999999999994,"max":57.164,"day":57.164,"min":53.635999999999996}},{"timestamp":1371988800,"pressure":1011.26,"metric":{"eve":13.66,"morn":12.54,"night":12.4,"max":15.18,"day":15.18,"min":12.4},"wind_speed":4.46,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":290,"humidity":82,"imperial":{"eve":56.588,"morn":54.572,"night":54.32,"max":59.324,"day":59.324,"min":54.32}},{"timestamp":1372075200,"pressure":1018.06,"metric":{"eve":14.96,"morn":11.73,"night":12.42,"max":14.96,"day":14.62,"min":11.73},"wind_speed":6.44,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":292,"humidity":0,"imperial":{"eve":58.928,"morn":53.114000000000004,"night":54.356,"max":58.928,"day":58.316,"min":53.114000000000004}},{"timestamp":1372161600,"pressure":1023.37,"metric":{"eve":15.08,"morn":12.04,"night":11.13,"max":15.8,"day":15.8,"min":11.13},"wind_speed":5.25,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":294,"humidity":0,"imperial":{"eve":59.144000000000005,"morn":53.672,"night":52.034000000000006,"max":60.44,"day":60.44,"min":52.034000000000006}},{"timestamp":1372248000,"pressure":1023.86,"metric":{"eve":14.99,"morn":11.59,"night":11.29,"max":15.91,"day":15.91,"min":11.29},"wind_speed":4.64,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":247,"humidity":0,"imperial":{"eve":58.982,"morn":52.862,"night":52.322,"max":60.638000000000005,"day":60.638000000000005,"min":52.322}},{"timestamp":1372334400,"pressure":1022.68,"metric":{"eve":14.6,"morn":11.33,"night":10.22,"max":15.73,"day":15.73,"min":10.22},"wind_speed":4.34,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":294,"humidity":0,"imperial":{"eve":58.28,"morn":52.394000000000005,"night":50.396,"max":60.314,"day":60.314,"min":50.396}}]},"format":1,"current":{"request":{"type":"current","url":"http://api.openweathermap.org/data/2.5/weather?id=2643743&units=metric"},"results":{"timestamp":1371568737,"pressure":1013,"service_id":2643743,"metric":{"temp_min":19,"temp":20.61,"temp_max":22.22},"date":null,"condition":{"icon":"03d","description":"scattered clouds","id":802,"main":"Clouds"},"wind_deg":98.5007,"humidity":80,"wind_speed_mph":1.0998249,"imperial":{"temp_min":66.2,"temp":69.098,"temp_max":71.99600000000001},"service":"openweathermap","wind_speed_kmh":1.77}},"location":{"service_id":2643743,"name":"London","country":"GB","service":"openweathermap"}}""") | ||
595 | 9 | |||
596 | 10 | locations_data.append("""{"daily":{"request":{"type":"daily","url":"http://api.openweathermap.org/data/2.5/forecast/daily?id=2911298&cnt=10&units=metric"},"results":[{"timestamp":1371553200,"pressure":1026.02,"metric":{"eve":24.71,"morn":25.5,"night":18.12,"max":25.5,"day":25.5,"min":18.12},"wind_speed":2.52,"condition":{"icon":"01d","description":"sky is clear","id":800,"main":"Clear"},"wind_deg":89,"humidity":70,"imperial":{"eve":76.47800000000001,"morn":77.9,"night":64.616,"max":77.9,"day":77.9,"min":64.616}},{"timestamp":1371639600,"pressure":1023.37,"metric":{"eve":29.17,"morn":20.41,"night":22.73,"max":30.39,"day":29.24,"min":20.41},"wind_speed":5.28,"condition":{"icon":"02d","description":"few clouds","id":801,"main":"Clouds"},"wind_deg":147,"humidity":69,"imperial":{"eve":84.506,"morn":68.738,"night":72.914,"max":86.702,"day":84.632,"min":68.738}},{"timestamp":1371726000,"pressure":1015.84,"metric":{"eve":25.49,"morn":24.61,"night":19.26,"max":29.68,"day":26.55,"min":19.26},"wind_speed":4.91,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":197,"humidity":84,"imperial":{"eve":77.882,"morn":76.298,"night":66.668,"max":85.424,"day":79.78999999999999,"min":66.668}},{"timestamp":1371812400,"pressure":1016.63,"metric":{"eve":17.09,"morn":16.63,"night":14.89,"max":19.75,"day":19.75,"min":14.89},"wind_speed":6.37,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":217,"humidity":91,"imperial":{"eve":62.762,"morn":61.934,"night":58.80200000000001,"max":67.55000000000001,"day":67.55000000000001,"min":58.80200000000001}},{"timestamp":1371898800,"pressure":1017.64,"metric":{"eve":18.15,"morn":16.27,"night":14.89,"max":19.34,"day":18.23,"min":14.89},"wind_speed":5.96,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":197,"humidity":83,"imperial":{"eve":64.67,"morn":61.286,"night":58.80200000000001,"max":66.812,"day":64.814,"min":58.80200000000001}},{"timestamp":1371985200,"pressure":1011.58,"metric":{"eve":15.16,"morn":14.29,"night":14.3,"max":15.93,"day":15.43,"min":14.29},"wind_speed":7.46,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":211,"humidity":86,"imperial":{"eve":59.288,"morn":57.721999999999994,"night":57.74,"max":60.674,"day":59.774,"min":57.721999999999994}},{"timestamp":1372071600,"pressure":1021.31,"metric":{"eve":17.86,"morn":14.88,"night":13.72,"max":17.97,"day":17.97,"min":13.72},"wind_speed":4.75,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":205,"humidity":0,"imperial":{"eve":64.148,"morn":58.784000000000006,"night":56.696,"max":64.346,"day":64.346,"min":56.696}},{"timestamp":1372158000,"pressure":1026.21,"metric":{"eve":16.23,"morn":13.89,"night":12.53,"max":16.75,"day":16.75,"min":12.53},"wind_speed":3.7,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":277,"humidity":0,"imperial":{"eve":61.214,"morn":57.002,"night":54.554,"max":62.150000000000006,"day":62.150000000000006,"min":54.554}},{"timestamp":1372244400,"pressure":1028.72,"metric":{"eve":16.24,"morn":13.84,"night":12.09,"max":16.71,"day":16.71,"min":12.09},"wind_speed":5.86,"condition":{"icon":"10d","description":"moderate rain","id":501,"main":"Rain"},"wind_deg":249,"humidity":0,"imperial":{"eve":61.232,"morn":56.912,"night":53.762,"max":62.078,"day":62.078,"min":53.762}},{"timestamp":1372330800,"pressure":1024.91,"metric":{"eve":16.15,"morn":12.93,"night":10.44,"max":16.33,"day":16.33,"min":10.44},"wind_speed":3.21,"condition":{"icon":"10d","description":"light rain","id":500,"main":"Rain"},"wind_deg":271,"humidity":0,"imperial":{"eve":61.06999999999999,"morn":55.274,"night":50.792,"max":61.394,"day":61.394,"min":50.792}}]},"db":{"updated":"2013-06-18T16:03:34.203Z","id":2},"format":1,"current":{"request":{"type":"current","url":"http://api.openweathermap.org/data/2.5/weather?id=2911298&units=metric"},"results":{"timestamp":1371568800,"pressure":1016,"service_id":2911298,"metric":{"temp_min":25,"temp":25.5,"temp_max":26},"date":null,"condition":{"icon":"01d","description":"Sky is Clear","id":800,"main":"Clear"},"wind_deg":100,"humidity":53,"wind_speed_mph":2.8583019999999997,"imperial":{"temp_min":77,"temp":77.9,"temp_max":78.80000000000001},"service":"openweathermap","wind_speed_kmh":4.6}},"location":{"service_id":2911298,"name":"Hamburg","country":"DE","service":"openweathermap"}}""") | ||
597 | 0 | 11 | ||
598 | === modified file 'ubuntu-weather-app.qml' | |||
599 | --- ubuntu-weather-app.qml 2013-06-17 19:22:19 +0000 | |||
600 | +++ ubuntu-weather-app.qml 2013-06-20 16:20:34 +0000 | |||
601 | @@ -54,15 +54,17 @@ | |||
602 | 54 | tabsObject.destroy() | 54 | tabsObject.destroy() |
603 | 55 | } | 55 | } |
604 | 56 | var tabsString = "import QtQuick 2.0; import Ubuntu.Components 0.1; import Ubuntu.Components.Popups 0.1; import \"components\" as Components; " | 56 | var tabsString = "import QtQuick 2.0; import Ubuntu.Components 0.1; import Ubuntu.Components.Popups 0.1; import \"components\" as Components; " |
606 | 57 | + "Tabs {id: tabs; anchors.fill: parent;" | 57 | + "Tabs {id: tabs; objectName: 'rootTabs'; anchors.fill: parent;" |
607 | 58 | if(locLength > 0) { | 58 | if(locLength > 0) { |
608 | 59 | for(var x=0;x<locLength;x++) { | 59 | for(var x=0;x<locLength;x++) { |
609 | 60 | tabsString += "Components.LocationTab {title: '"+locations[x].location.name+"'; locationIndex: "+x+"} " | 60 | tabsString += "Components.LocationTab {title: '"+locations[x].location.name+"'; locationIndex: "+x+"} " |
610 | 61 | }; | 61 | }; |
611 | 62 | } | 62 | } |
612 | 63 | tabsString += "}"; // END Tabs componen | 63 | tabsString += "}"; // END Tabs componen |
614 | 64 | if(bigLoading !== null) | 64 | if(bigLoading !== null) { |
615 | 65 | bigLoading.destroy(); | 65 | bigLoading.destroy(); |
616 | 66 | tabs.visible = false; | ||
617 | 67 | } | ||
618 | 66 | loading.running = false; | 68 | loading.running = false; |
619 | 67 | tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs") | 69 | tabsObject = Qt.createQmlObject(tabsString, tabPage, "tabs") |
620 | 68 | if(focusToLast) | 70 | if(focusToLast) |
621 | @@ -107,10 +109,6 @@ | |||
622 | 107 | }) | 109 | }) |
623 | 108 | } | 110 | } |
624 | 109 | 111 | ||
625 | 110 | Components.AddLocationPage { | ||
626 | 111 | id: addLocationDialog | ||
627 | 112 | } | ||
628 | 113 | |||
629 | 114 | Components.SettingsPage { | 112 | Components.SettingsPage { |
630 | 115 | id: settingsPage | 113 | id: settingsPage |
631 | 116 | } | 114 | } |
632 | @@ -133,12 +131,11 @@ | |||
633 | 133 | 131 | ||
634 | 134 | Page { | 132 | Page { |
635 | 135 | id: tabPage | 133 | id: tabPage |
636 | 136 | title: "Simple page" | ||
637 | 137 | visible: false | 134 | visible: false |
638 | 138 | ActivityIndicator{id:loading; running: false; z: 1; anchors{top: parent.top; topMargin: units.gu(0.5); right: parent.right; rightMargin: units.gu(1)}} | 135 | ActivityIndicator{id:loading; running: false; z: 1; anchors{top: parent.top; topMargin: units.gu(0.5); right: parent.right; rightMargin: units.gu(1)}} |
639 | 139 | Tabs { | 136 | Tabs { |
640 | 140 | id: tabs | 137 | id: tabs |
642 | 141 | objectName: "Tabs" | 138 | objectName: "LoadingTabs" |
643 | 142 | anchors.fill: parent | 139 | anchors.fill: parent |
644 | 143 | Tab { | 140 | Tab { |
645 | 144 | title: "Loading..." | 141 | title: "Loading..." |
FAILED: Continuous integration, rev:47 91.189. 93.125: 8080/job/ ubuntu- weather- app-ci/ 25/ 91.189. 93.125: 8080/job/ ubuntu- weather- app-quantal- amd64-ci/ 22/console 91.189. 93.125: 8080/job/ ubuntu- weather- app-raring- amd64-ci/ 25/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: 91.189. 93.125: 8080/job/ ubuntu- weather- app-ci/ 25/rebuild
http://