Merge lp:~ahayzen/music-app/ap-helper-refactor-001 into lp:music-app/trusty

Proposed by Andrew Hayzen
Status: Merged
Approved by: Victor Thompson
Approved revision: 592
Merged at revision: 592
Proposed branch: lp:~ahayzen/music-app/ap-helper-refactor-001
Merge into: lp:music-app/trusty
Diff against target: 455 lines (+133/-79)
5 files modified
MusicTracks.qml (+2/-0)
music-app.qml (+2/-1)
tests/autopilot/music_app/__init__.py (+78/-8)
tests/autopilot/music_app/tests/__init__.py (+25/-24)
tests/autopilot/music_app/tests/test_music.py (+26/-46)
To merge this branch: bzr merge lp:~ahayzen/music-app/ap-helper-refactor-001
Reviewer Review Type Date Requested Status
Victor Thompson Approve
Ubuntu Phone Apps Jenkins Bot continuous-integration Approve
Nicholas Skaggs (community) Approve
Review via email: mp+231466@code.launchpad.net

Commit message

* Initial conversion of splitting the helpers

Description of the change

* Initial conversion of splitting the helpers

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)
585. By Andrew Hayzen

* Add property for pointing_device to keep old tests running

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
586. By Andrew Hayzen

* Fix incorrect property

Revision history for this message
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote :
review: Needs Fixing (continuous-integration)
587. By Andrew Hayzen

* Fix for tracksTab name change

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
Nicholas Skaggs (nskaggs) wrote :

This all looks excellent. I will note that it might be useful to start converting strings from " to '. It will make Leo happy :-)

588. By Andrew Hayzen

* Fix typo

Revision history for this message
Nicholas Skaggs (nskaggs) :
review: Approve
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
Victor Thompson (vthompson) wrote :

Echoing inline comments:

tests/autopilot/music_app/__init__.py L70: Minor gripe, "open_tracks" isn't very descriptive if someone wants to reuse it. We should maybe try to be consistent here and call this the "Songs tab" also, we mix the use of tab and page... which could lead to confusion for future coders and ourselves.

tests/autopilot/music_app/__init__.py L73: Question: is ":return:" some sort of docstring standard? I'm not sure what to make of it.

tests/autopilot/music_app/__init__.py L102: Question: What is "Page10" could this please be clarified?

review: Needs Fixing
Revision history for this message
Andrew Hayzen (ahayzen) wrote :

I deliberately used tracks as I was going to refer to anything on the tracks tab as tracks and the songs page as songs to avoid the current confusion. This makes sense because the file called MusicTracks.qml only the title of the tab is called Songs.

:return: was used in other apps autopilot tests so I copied them and yes it is todo with docstring standard IIRC

bug 1341671 and bug 1337004 relate to Page10, but in summary it appears as Page10 or Page11 (depending on Ubuntu.Components version and comes from the filename) this is a known issue and other apps have to do this in their tests as well. Page10 for us = MusicTracks {}

Revision history for this message
Victor Thompson (vthompson) wrote :

Ok, please rename "open_tracks" as "open_tracks_tab". Also, please add some commentary regarding those bugs for the "Page10" issue specifically stating that this represents MusicTracks, just above the Page10 class declaration.

review: Needs Fixing
Revision history for this message
Victor Thompson (vthompson) wrote :

Or really what that function should be called is "get_tracks_page"... it just needs something because "open_tracks" could mean so many things

589. By Andrew Hayzen

* Change open_tracks to open_tracks_tab
* Add code comments

590. By Andrew Hayzen

* Switch open_tracks_tab to get_tracks_page

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
Victor Thompson (vthompson) wrote :

This is a bit silly to ask you to change, but you've modified the line of code 3 or so times already. Could you change the commentary "switch to track tabs" to state "tab", singular?

591. By Andrew Hayzen

* Fix for grammatical error

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
Victor Thompson (vthompson) wrote :

Unfortunately you'll have to merge with trunk and resolve 1 conflict.

592. By Andrew Hayzen

* Merge of trunk

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
Victor Thompson (vthompson) wrote :

Everything LGTM!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'MusicTracks.qml'
2--- MusicTracks.qml 2014-08-11 13:29:08 +0000
3+++ MusicTracks.qml 2014-08-21 18:57:12 +0000
4@@ -32,6 +32,7 @@
5
6 MusicPage {
7 id: mainpage
8+ objectName: "tracksPage"
9 title: i18n.tr("Songs")
10
11 ListView {
12@@ -57,6 +58,7 @@
13 ListItemWithActions {
14 id: track
15 color: "transparent"
16+ objectName: "tracksTabListItem" + index
17 width: parent.width
18 height: styleMusic.common.itemHeight
19
20
21=== modified file 'music-app.qml'
22--- music-app.qml 2014-08-21 17:18:50 +0000
23+++ music-app.qml 2014-08-21 18:57:12 +0000
24@@ -740,6 +740,7 @@
25
26 SongsModel {
27 id: allSongsModel
28+ objectName: "allSongsModel"
29 store: musicStore
30 }
31
32@@ -1060,7 +1061,7 @@
33 property bool loading: false
34 property var model: []
35 id: tracksTab
36- objectName: "trackstab"
37+ objectName: "tracksTab"
38 anchors.fill: parent
39 title: page.title
40
41
42=== modified file 'tests/autopilot/music_app/__init__.py'
43--- tests/autopilot/music_app/__init__.py 2014-08-18 19:35:31 +0000
44+++ tests/autopilot/music_app/__init__.py 2014-08-21 18:57:12 +0000
45@@ -10,13 +10,87 @@
46 from time import sleep
47
48
49+class MusicAppException(Exception):
50+ """Exception raised when there's an error in the Music App."""
51+
52+
53+class MusicApp(object):
54+ """Autopilot helper object for the Music application."""
55+
56+ def __init__(self, app_proxy):
57+ self.app = app_proxy
58+ self.main_view = self.app.wait_select_single(MainView)
59+ self.player = self.app.select_single(Player, objectName='player')
60+
61+ def populate_queue(self):
62+ tracksPage = self.get_tracks_page() # switch to track tab
63+
64+ # get and click to play first track
65+ track = tracksPage.get_track(0)
66+ self.app.pointing_device.click_object(track)
67+
68+ # TODO: when using bottom edge wait for .isReady on tracksPage
69+
70+ def get_tracks_page(self):
71+ """Open the Tracks tab.
72+
73+ :return: The autopilot custom proxy object for the TracksPage.
74+
75+ """
76+ self.main_view.switch_to_tab('tracksTab')
77+
78+ return self.main_view.select_single(
79+ Page10, objectName='tracksPage')
80+
81+ @property
82+ def loaded(self):
83+ return (not self.main_view.select_single("ActivityIndicator",
84+ objectName="LoadingSpinner").running and
85+ self.main_view.select_single("*", "allSongsModel").populated)
86+
87+
88+class Page(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
89+ """Autopilot helper for Pages."""
90+ def __init__(self, *args):
91+ super(Page, self).__init__(*args)
92+ # XXX we need a better way to keep reference to the main view.
93+ # --elopio - 2014-01-31
94+ self.main_view = self.get_root_instance().select_single(MainView)
95+
96+
97+class MusicPage(Page):
98+ def __init__(self, *args):
99+ super(Page, self).__init__(*args)
100+
101+
102+# FIXME: Represents MusicTracks related to bug 1341671 and bug 1337004
103+class Page10(MusicPage):
104+ """ Autopilot helper for the tracks page """
105+ def __init__(self, *args):
106+ super(MusicPage, self).__init__(*args)
107+
108+ def get_track(self, i):
109+ return (self.wait_select_single("ListItemWithActions",
110+ objectName="tracksTabListItem" + str(i)))
111+
112+
113+class Player(ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase):
114+ """Autopilot helper for Player """
115+
116+
117 class MainView(ubuntuuitoolkit.MainView):
118-
119- """An emulator class that makes it easy to interact with the
120- music-app.
121- """
122+ """Autopilot custom proxy object for the MainView."""
123 retry_delay = 0.2
124
125+ def __init__(self, *args):
126+ super(MainView, self).__init__(*args)
127+ self.visible.wait_for(True)
128+
129+ # wait for activity indicator to stop spinning
130+ spinner = self.wait_select_single("ActivityIndicator",
131+ objectName="LoadingSpinner")
132+ spinner.running.wait_for(False)
133+
134 def get_toolbar(self):
135 return self.select_single("MusicToolbar",
136 objectName="musicToolbarObject")
137@@ -116,10 +190,6 @@
138 def get_player_control_title(self):
139 return self.select_single("Label", objectName="playercontroltitle")
140
141- def get_spinner(self):
142- return self.select_single("ActivityIndicator",
143- objectName="LoadingSpinner")
144-
145 def get_first_genre_item(self):
146 return self.wait_select_single("*", objectName="genreItemObject")
147
148
149=== modified file 'tests/autopilot/music_app/tests/__init__.py'
150--- tests/autopilot/music_app/tests/__init__.py 2014-08-18 19:35:31 +0000
151+++ tests/autopilot/music_app/tests/__init__.py 2014-08-21 18:57:12 +0000
152@@ -15,10 +15,10 @@
153 import music_app
154
155 import fixtures
156-from music_app import MainView
157+from music_app import MusicApp
158
159 from autopilot import logging as autopilot_logging
160-from autopilot.input import Mouse, Touch, Pointer
161+from autopilot.input import Mouse, Touch
162 from autopilot.platform import model
163 from autopilot.testcase import AutopilotTestCase
164
165@@ -32,7 +32,7 @@
166 logger = logging.getLogger(__name__)
167
168
169-class MusicTestCase(AutopilotTestCase):
170+class BaseTestCaseWithPatchedHome(AutopilotTestCase):
171
172 """A common test case class that provides several useful methods for
173 music-app tests.
174@@ -48,7 +48,7 @@
175 local_location = local_location_dir + "/music-app.qml"
176 installed_location = "/usr/share/music-app/music-app.qml"
177
178- def setup_environment(self):
179+ def get_launcher_method_and_type(self):
180 if os.path.exists(self.local_location):
181 launch = self.launch_test_local
182 test_type = 'local'
183@@ -61,16 +61,15 @@
184 return launch, test_type
185
186 def setUp(self):
187- launch, self.test_type = self.setup_environment()
188- self.home_dir = self._patch_home()
189- self._create_music_library()
190- self.pointing_device = Pointer(self.input_device_class.create())
191- super(MusicTestCase, self).setUp()
192- launch()
193+ super(BaseTestCaseWithPatchedHome, self).setUp()
194+ _, test_type = self.get_launcher_method_and_type()
195+ self.home_dir = self._patch_home(test_type)
196+
197+ self._create_music_library(test_type)
198
199 @autopilot_logging.log_action(logger.info)
200 def launch_test_local(self):
201- self.app = self.launch_test_application(
202+ return self.launch_test_application(
203 base.get_qmlscene_launch_command(),
204 self.local_location,
205 "debug",
206@@ -79,7 +78,7 @@
207
208 @autopilot_logging.log_action(logger.info)
209 def launch_test_installed(self):
210- self.app = self.launch_test_application(
211+ return self.launch_test_application(
212 base.get_qmlscene_launch_command(),
213 self.installed_location,
214 "debug",
215@@ -88,7 +87,7 @@
216
217 @autopilot_logging.log_action(logger.info)
218 def launch_test_click(self):
219- self.app = self.launch_click_package(
220+ return self.launch_click_package(
221 "com.ubuntu.music",
222 emulator_base=ubuntuuitoolkit.UbuntuUIToolkitCustomProxyObjectBase)
223
224@@ -109,12 +108,12 @@
225 '.Xauthority')),
226 os.path.join(directory, '.Xauthority'))
227
228- def _patch_home(self):
229+ def _patch_home(self, test_type):
230 """ mock /home for testing purposes to preserve user data
231 """
232 # click requires apparmor profile, and writing to special dir
233 # but the desktop can write to a traditional /tmp directory
234- if self.test_type == 'click':
235+ if test_type == 'click':
236 env_dir = os.path.join(os.environ.get('HOME'), 'autopilot',
237 'fakeenv')
238
239@@ -175,8 +174,8 @@
240 logger.debug("Patched home to fake home directory %s" % temp_dir)
241 return temp_dir
242
243- def _create_music_library(self):
244- logger.debug("Creating music library for %s test" % self.test_type)
245+ def _create_music_library(self, test_type):
246+ logger.debug("Creating music library for %s test" % test_type)
247 logger.debug("Home set to %s" % self.home_dir)
248 musicpath = os.path.join(self.home_dir, 'Music')
249 logger.debug("Music path set to %s" % musicpath)
250@@ -245,10 +244,12 @@
251 os.remove(in_filename)
252 os.rename(out_filename, in_filename)
253
254- @property
255- def player(self):
256- return self.main_view.get_player()
257-
258- @property
259- def main_view(self):
260- return self.app.select_single(MainView)
261+
262+class MusicAppTestCase(BaseTestCaseWithPatchedHome):
263+
264+ """Base test case that launches the music-app."""
265+
266+ def setUp(self):
267+ super(MusicAppTestCase, self).setUp()
268+ launcher_method, _ = self.get_launcher_method_and_type()
269+ self.app = MusicApp(launcher_method())
270
271=== modified file 'tests/autopilot/music_app/tests/test_music.py'
272--- tests/autopilot/music_app/tests/test_music.py 2014-08-14 16:52:12 +0000
273+++ tests/autopilot/music_app/tests/test_music.py 2014-08-21 18:57:12 +0000
274@@ -15,40 +15,31 @@
275 from testtools.matchers import Equals, Is, Not, LessThan, NotEquals
276
277
278-from music_app.tests import MusicTestCase
279+from music_app.tests import MusicAppTestCase
280
281 logger = logging.getLogger(__name__)
282
283
284-class TestMainWindow(MusicTestCase):
285+class TestMainWindow(MusicAppTestCase):
286
287 def setUp(self):
288 super(TestMainWindow, self).setUp()
289- self.assertThat(
290- self.main_view.visible, Eventually(Equals(True)))
291
292- # wait for activity indicator to stop spinning
293- spinner = lambda: self.main_view.get_spinner().running
294- self.assertThat(spinner, Eventually(Equals(False)))
295 self.trackTitle = u"Gran Vals"
296 self.artistName = u"Francisco Tárrega"
297 self.lastTrackTitle = u"TestMP3Title"
298
299- def populate_and_play_queue(self):
300- first_genre_item = self.main_view.get_first_genre_item()
301- self.pointing_device.click_object(first_genre_item)
302-
303- song = self.main_view.get_album_page_listview_tracktitle(
304- self.trackTitle)
305- self.pointing_device.click_object(song)
306-
307- def populate_and_play_queue_from_songs_tab(self):
308- # switch to songs tab
309- self.main_view.switch_to_tab("trackstab")
310-
311- # get track item to add to queue
312- trackitem = self.main_view.get_songs_tab_tracktitle(self.trackTitle)
313- self.pointing_device.click_object(trackitem)
314+ @property
315+ def main_view(self):
316+ return self.app.main_view
317+
318+ @property
319+ def player(self):
320+ return self.app.player
321+
322+ @property
323+ def pointing_device(self):
324+ return self.app.app.pointing_device
325
326 def turn_shuffle_off(self):
327 if self.player.shuffle:
328@@ -90,8 +81,7 @@
329 """ tests if the music library is populated from our
330 fake mediascanner database"""
331
332- # populate queue
333- self.populate_and_play_queue_from_songs_tab()
334+ self.app.populate_queue() # populate queue
335
336 title = lambda: self.player.currentMetaTitle
337 artist = lambda: self.player.currentMetaArtist
338@@ -146,8 +136,7 @@
339 def test_play_pause_now_playing(self):
340 """ Test playing and pausing a track (Music Library must exist) """
341
342- # populate queue
343- self.populate_and_play_queue_from_songs_tab()
344+ self.app.populate_queue() # populate queue
345
346 playbutton = self.main_view.get_now_playing_play_button()
347
348@@ -165,8 +154,7 @@
349 def test_next_previous(self):
350 """ Test going to next track (Music Library must exist) """
351
352- # populate queue
353- self.populate_and_play_queue_from_songs_tab()
354+ self.app.populate_queue() # populate queue
355
356 playbutton = self.main_view.get_now_playing_play_button()
357
358@@ -222,8 +210,7 @@
359 def test_mp3(self):
360 """ Test that mp3 "plays" or at least doesn't crash on load """
361
362- # populate queue
363- self.populate_and_play_queue_from_songs_tab()
364+ self.app.populate_queue() # populate queue
365
366 playbutton = self.main_view.get_now_playing_play_button()
367
368@@ -265,8 +252,7 @@
369 def test_shuffle(self):
370 """ Test shuffle (Music Library must exist) """
371
372- # populate queue
373- self.populate_and_play_queue_from_songs_tab()
374+ self.app.populate_queue() # populate queue
375
376 """ Track is playing, shuffle is turned on"""
377 forwardbutton = self.main_view.get_forward_button()
378@@ -386,8 +372,7 @@
379 # get number of tracks in queue before queuing a track
380 initialtracksCount = self.main_view.get_queue_track_count()
381
382- # populate queue
383- self.populate_and_play_queue_from_songs_tab()
384+ self.app.populate_queue() # populate queue
385
386 # verify track queue has added all songs to initial value
387 endtracksCount = self.main_view.get_queue_track_count()
388@@ -414,7 +399,7 @@
389 initialtracksCount = self.main_view.get_queue_track_count()
390
391 # switch to songs tab
392- self.main_view.switch_to_tab("trackstab")
393+ self.main_view.switch_to_tab("tracksTab")
394
395 # get track item to swipe and queue
396 trackitem = self.main_view.get_songs_tab_tracktitle(self.trackTitle)
397@@ -457,7 +442,7 @@
398 selecting a song to add it to a new playlist. """
399
400 # switch to songs tab
401- self.main_view.switch_to_tab("trackstab")
402+ self.main_view.switch_to_tab("tracksTab")
403
404 # get track item to swipe and queue
405 trackitem = self.main_view.get_songs_tab_tracktitle(self.trackTitle)
406@@ -563,8 +548,7 @@
407 """tests navigating to the Now Playing queue, swiping to delete a
408 track, and confirming the delete action. """
409
410- # populate queue
411- self.populate_and_play_queue_from_songs_tab()
412+ self.app.populate_queue() # populate queue
413
414 # get initial queue count
415 initialqueueCount = self.main_view.get_queue_track_count()
416@@ -597,8 +581,7 @@
417 def test_playback_stops_when_last_song_ends_and_repeat_off(self):
418 """Check that playback stops when the last song in the queue ends"""
419
420- # populate queue
421- self.populate_and_play_queue_from_songs_tab()
422+ self.app.populate_queue() # populate queue
423
424 self.turn_shuffle_off()
425 self.turn_repeat_off()
426@@ -616,8 +599,7 @@
427 def test_playback_repeats_when_last_song_ends_and_repeat_on(self):
428 """With repeat on, the 1st song should play after the last one ends"""
429
430- # populate queue
431- self.populate_and_play_queue_from_songs_tab()
432+ self.app.populate_queue() # populate queue
433
434 self.turn_shuffle_off()
435 self.turn_repeat_on()
436@@ -636,8 +618,7 @@
437 def test_pressing_next_from_last_song_plays_first_when_repeat_on(self):
438 """With repeat on, skipping the last song jumps to the first track"""
439
440- # populate queue
441- self.populate_and_play_queue_from_songs_tab()
442+ self.app.populate_queue() # populate queue
443
444 self.turn_shuffle_off()
445 self.turn_repeat_on()
446@@ -655,8 +636,7 @@
447 def test_pressing_prev_from_first_song_plays_last_when_repeat_on(self):
448 """With repeat on, 'previous' from the 1st song plays the last one."""
449
450- # populate queue
451- self.populate_and_play_queue_from_songs_tab()
452+ self.app.populate_queue() # populate queue
453
454 self.turn_shuffle_off()
455 self.turn_repeat_on()

Subscribers

People subscribed via source and target branches

to status/vote changes: