Merge lp:~elopio/u1-test-utils/dash-tests into lp:~canonical-isd-hackers/u1-test-utils/test-in-dash-payments
- dash-tests
- Merge into test-in-dash-payments
Status: | Merged |
---|---|
Approved by: | Leo Arias |
Approved revision: | 64 |
Merged at revision: | 64 |
Proposed branch: | lp:~elopio/u1-test-utils/dash-tests |
Merge into: | lp:~canonical-isd-hackers/u1-test-utils/test-in-dash-payments |
Diff against target: |
386 lines (+147/-127) 5 files modified
tests/dash.py (+83/-65) tests/schema.py (+3/-0) tests/test_dash.py (+34/-28) tests/test_purchase_good.py (+26/-33) tests/test_session.py (+1/-1) |
To merge this branch: | bzr merge lp:~elopio/u1-test-utils/dash-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincent Ladeuil (community) | Approve | ||
Review via email:
|
This proposal supersedes a proposal from 2013-05-20.
Commit message
Added tests for the dash functions we use, cleaned the purchase tests and make sure they will work with the local servers.
Description of the change

Leo Arias (elopio) wrote : | # |
> 44 + # TODO We should check if the result is visible, instead of checking
> if
> 45 + # there are visible categories. I don't know how to do it, I'll ask
> 46 + # --elopio - 2013-05-19
>
> I thought the following was doing that:
>
> 91 - refresh_results_fn = lambda: len(category.
> 92 - test.assertThat
> 93 - # Select first result as soon as it appears
> 94 - return category.
>
> This also ensures that there is at least one result which the following
> doesn't seem to care about:
>
> 40 + return category.
You are right. I copied that part of the code. Thanks.
> I'm not sure about why you thunk some methods to functions but as long as
> daughter classes can still redefine the methods, I don't have strong
> objections either.
My goal is to put this in a custom autopilot emulator that inherits from the one in unity. We still need a little work from the autopilot team for that.
Preview Diff
1 | === modified file 'tests/dash.py' |
2 | --- tests/dash.py 2013-05-17 16:24:59 +0000 |
3 | +++ tests/dash.py 2013-06-19 20:36:26 +0000 |
4 | @@ -4,13 +4,69 @@ |
5 | GreaterThan, |
6 | NotEquals, |
7 | ) |
8 | -from unity.emulators import dash as udash |
9 | - |
10 | - |
11 | -def wait_for_category(test, scope, category_name): |
12 | - get_category = lambda: scope.get_category_by_name(category_name) |
13 | - test.assertThat(get_category, Eventually(NotEquals(None))) |
14 | - return get_category() |
15 | + |
16 | + |
17 | +def search_music_scope(test, query): |
18 | + test.addCleanup(test.unity.dash.ensure_hidden) |
19 | + test.unity.dash.reveal_music_scope() |
20 | + test.addCleanup(clear_music_scope_search, test) |
21 | + test.keyboard.type(query) |
22 | + music_scope = test.unity.dash.get_current_scope() |
23 | + # Wait for a category to appear. |
24 | + test.assertThat( |
25 | + music_scope.get_num_visible_categories, |
26 | + Eventually(GreaterThan(0))) |
27 | + |
28 | + |
29 | +def clear_music_scope_search(test): |
30 | + dash = test.unity.dash |
31 | + if (not dash.visible) or (dash.get_current_scope() != 'music.scope'): |
32 | + dash.reveal_music_scope() |
33 | + dash.clear_search() |
34 | + |
35 | + |
36 | +def get_first_result_from_category(test, category_name): |
37 | + current_scope = test.unity.dash.get_current_scope() |
38 | + category = current_scope.get_category_by_name(category_name) |
39 | + test.assertTrue(category.is_visible) |
40 | + get_number_of_results = lambda: len(category.get_results()) |
41 | + test.assertThat(get_number_of_results, Eventually(GreaterThan(0))) |
42 | + return category.get_results()[0] |
43 | + |
44 | + |
45 | +def preview_result(test, result): |
46 | + current_scope = test.unity.dash.get_current_scope() |
47 | + test.assertThat(current_scope.get_num_visible_categories(), GreaterThan(0)) |
48 | + result.preview() |
49 | + _wait_for_preview_animation(test) |
50 | + |
51 | + |
52 | +def _wait_for_preview_animation(test): |
53 | + test.assertThat( |
54 | + test.unity.dash.view.get_preview_container, |
55 | + Eventually(NotEquals(None))) |
56 | + preview_container = test.unity.dash.view.get_preview_container() |
57 | + test.assertThat( |
58 | + preview_container.animating, Eventually(Equals(False))) |
59 | + |
60 | + |
61 | +def ensure_preview_closed(test): |
62 | + if test.unity.dash.preview_displaying: |
63 | + close_preview(test) |
64 | + |
65 | + |
66 | +def close_preview(test): |
67 | + test.assertTrue(test.unity.dash.preview_displaying) |
68 | + test.keyboard.press_and_release('Escape') |
69 | + |
70 | + |
71 | +def get_current_preview(test): |
72 | + test.assertThat( |
73 | + test.unity.dash.view.get_preview_container, |
74 | + Eventually(NotEquals(None))) |
75 | + container = test.unity.dash.view.get_preview_container() |
76 | + test.assertThat(container.waiting_preview, Eventually(Equals(False))) |
77 | + return container.current_preview |
78 | |
79 | |
80 | class Window(object): |
81 | @@ -23,37 +79,17 @@ |
82 | """The first window opened when the dash is activated.""" |
83 | |
84 | def get_result(self, test): |
85 | - scope = test.unity.dash.get_current_scope() |
86 | - # Wait for the category we care about to appear (that's the one where |
87 | - # goods can be bought). |
88 | - category = scope.get_category_by_name('More suggestions') |
89 | - |
90 | - refresh_results_fn = lambda: len(category.get_results()) |
91 | - test.assertThat(refresh_results_fn, Eventually(GreaterThan(0))) |
92 | - # Select first result as soon as it appears |
93 | - return category.get_results()[0] |
94 | + # XXX Currently we can't force the Music Store to return a result, |
95 | + # so for now we will just use the first one. --elopio - 2013-05-19 |
96 | + return get_first_result_from_category(test, 'More suggestions') |
97 | |
98 | def get_preview(self, test, good): |
99 | - test.unity.dash.ensure_visible() |
100 | - test.addCleanup(test.unity.dash.ensure_hidden) |
101 | - # Use the scope required by the test |
102 | - if test.scope_name == 'music': |
103 | - test.unity.dash.reveal_music_scope() |
104 | - # Start the search |
105 | - test.keyboard.type(good.search) |
106 | + search_music_scope(test, good.search) |
107 | result = self.get_result(test) |
108 | - # The name of the result is different between home scope and music scope |
109 | - # :-/ -- vila 2013-04-04 |
110 | - test.assertTrue(good.name in result.name) |
111 | - # We got the right one, preview it |
112 | - result.preview() |
113 | - test.assertThat(test.unity.dash.view.preview_displaying, |
114 | - Eventually(Equals(True))) |
115 | - test.assertThat(test.unity.dash.view.get_preview_container, |
116 | - Eventually(NotEquals(None))) |
117 | - container = test.unity.dash.view.get_preview_container() |
118 | + test.addCleanup(ensure_preview_closed, test) |
119 | + preview_result(test, result) |
120 | # We have the preview now |
121 | - return Preview(self.user, good, container) |
122 | + return Preview(self.user, good) |
123 | |
124 | |
125 | class WindowWithGood(Window): |
126 | @@ -69,24 +105,13 @@ |
127 | |
128 | class Preview(WindowWithGood): |
129 | |
130 | - def __init__(self, user, good, container): |
131 | + _DOWNLOAD_BUTTON_ID = 'show_purchase_preview' |
132 | + |
133 | + def __init__(self, user, good): |
134 | super(Preview, self).__init__(user, good) |
135 | - self.container = container |
136 | - |
137 | - |
138 | - def get_dash_preview(self): |
139 | - content = self.container.get_children_by_type(udash.PreviewContent)[0] |
140 | - preview = content.get_current_preview() |
141 | - return preview |
142 | - |
143 | - def good_displayed(self): |
144 | - preview = self.get_dash_preview() |
145 | - # FIXME: At some point, self.good.name == preview.text_boxes[0].text |
146 | - # used to be True... we need some other way now -- vila 2013-04-03 |
147 | - return True |
148 | - |
149 | - def get_message_replacing_action(self): |
150 | - preview = self.get_dash_preview() |
151 | + |
152 | + def get_message_replacing_action(self, test): |
153 | + preview = get_current_preview() |
154 | # FIXME: Far from pretty but at least we can get it. There are two |
155 | # issues below: [2] may break if more StaticCairoTexts are added and |
156 | # the 'get_properties()['text'] may be brittle (but that would mean |
157 | @@ -96,21 +121,14 @@ |
158 | message = preview.text_boxes[2].get_properties()['text'] |
159 | return message |
160 | |
161 | - def get_download_button(self): |
162 | - preview = self.get_dash_preview() |
163 | - # FIXME: Urgh, we can't access the action button by name anymore, |
164 | - # relying on the fact that there is only one button for now. -- vila |
165 | - # 2013-05-17 |
166 | - download = preview.get_children_by_type(udash.ActionButton)[0] |
167 | + def get_download_button(self, test): |
168 | + preview = get_current_preview(test) |
169 | + download = preview.get_action_by_id(self._DOWNLOAD_BUTTON_ID) |
170 | return download |
171 | |
172 | def click_download(self, test): |
173 | - download = self.get_download_button() |
174 | - # FIXME: MusicPreview should allow executing the action but it's |
175 | - # currently broken (http://pad.lv/1163930) -- vila 2013-04-03 |
176 | - mouse = udash.get_mouse() |
177 | - mouse.move(download.x, download.y) |
178 | - mouse.click() |
179 | + preview = get_current_preview(test) |
180 | + preview.execute_action_by_id(self._DOWNLOAD_BUTTON_ID) |
181 | # FIXME: The current implementation diverges from the design spec by |
182 | # going straight to the web without presenting a window explaining why |
183 | # the good can't be bought while also displaying the good. As of today, |
184 | @@ -124,8 +142,8 @@ |
185 | |
186 | def __init__(self, user, good): |
187 | super(GotoU1, self).__init__(user, good) |
188 | - if self.user.logged_in: |
189 | - if self.user.payment_method == 'expired': |
190 | + if self.user.is_logged_in(): |
191 | + if self.user.get_payment_type() == 'expired': |
192 | self.message = ('Your card has expired.' |
193 | 'To add a new payment method, please visit...') |
194 | else: |
195 | |
196 | === modified file 'tests/schema.py' |
197 | --- tests/schema.py 2013-05-10 06:21:41 +0000 |
198 | +++ tests/schema.py 2013-06-19 20:36:26 +0000 |
199 | @@ -15,5 +15,8 @@ |
200 | class ubuntuone(schema.Section): |
201 | ubuntuone_server_url = schema.StringOption() |
202 | |
203 | + class musicsearch(schema.Section): |
204 | + musicsearch_server_url = schema.StringOption() |
205 | + |
206 | |
207 | schema = InDashPaymentsSchema |
208 | |
209 | === modified file 'tests/test_dash.py' |
210 | --- tests/test_dash.py 2013-05-17 13:00:48 +0000 |
211 | +++ tests/test_dash.py 2013-06-19 20:36:26 +0000 |
212 | @@ -1,34 +1,40 @@ |
213 | -import autopilot |
214 | +import unity.tests as utests |
215 | + |
216 | from autopilot.matchers import Eventually |
217 | -from testtools.matchers import Contains, Equals, GreaterThan |
218 | -import unity.tests as utests |
219 | +from testtools.matchers import Equals |
220 | + |
221 | +from tests import dash |
222 | |
223 | |
224 | class TestDash(utests.UnityTestCase): |
225 | |
226 | - # This test needs to be upgraded to catch up with autopilot and unity |
227 | - # recent versions. |
228 | - def xtest_select_preview(self): |
229 | - self.unity.dash.ensure_visible() |
230 | + def setUp(self): |
231 | + super(TestDash, self).setUp() |
232 | self.addCleanup(self.unity.dash.ensure_hidden) |
233 | - scope = self.unity.dash.get_current_scope() |
234 | - self.keyboard.type("hendrix") |
235 | - results_category = scope.get_category_by_name("More suggestions") |
236 | - refresh_results_fn = lambda: len(results_category.get_results()) |
237 | - self.assertThat(refresh_results_fn, Eventually(GreaterThan(1))) |
238 | - # Select first result |
239 | - self.keyboard.press_and_release('Enter') |
240 | - # We have the preview now |
241 | - self.keyboard.press_and_release('Enter') |
242 | - self.assertTrue(self.bamf.wait_until_application_is_running( |
243 | - 'firefox.desktop', 10.0)) |
244 | - firefox = self.bamf.get_running_applications_by_desktop_file( |
245 | - 'firefox.desktop')[0] |
246 | - self.addCleanup(firefox.get_windows()[0].close) |
247 | - # FIXME: We can't get the right title as we receive the window too |
248 | - # soon. -- vila 2013-02-21 |
249 | -# for w in firefox.get_windows(): |
250 | -# print 'title: %s' % (w.title) |
251 | -# import pdb; pdb.set_trace() |
252 | -# self.assertEqual('Log in - Mozilla Firefox', |
253 | -# firefox.get_windows()[0].title) |
254 | + |
255 | + def test_open_music_scope(self): |
256 | + self.unity.dash.reveal_music_scope() |
257 | + current_scope = self.unity.dash.get_current_scope() |
258 | + self.assertEquals(current_scope.name, 'music.scope') |
259 | + |
260 | + def test_search_music_scope(self): |
261 | + dash.search_music_scope(self, 'Hendrix') |
262 | + first_result = dash.get_first_result_from_category( |
263 | + self, 'More suggestions') |
264 | + self.assertIn('Hendrix', first_result.name) |
265 | + |
266 | + def test_open_and_close_music_result(self): |
267 | + dash.search_music_scope(self, 'Hendrix') |
268 | + first_result = dash.get_first_result_from_category( |
269 | + self, 'More suggestions') |
270 | + dash.preview_result(self, first_result) |
271 | + self.assertThat( |
272 | + self.unity.dash.preview_displaying, Eventually(Equals(True))) |
273 | + preview = dash.get_current_preview(self) |
274 | + self.assertIn('Hendrix', preview.text_boxes[0].text) |
275 | + self.assertEquals(preview.get_num_actions(), 1) |
276 | + download_button = preview.get_action_by_id('show_purchase_preview') |
277 | + self.assertEqual(download_button.label, 'Download') |
278 | + dash.close_preview(self) |
279 | + self.assertThat( |
280 | + self.unity.dash.preview_displaying, Eventually(Equals(False))) |
281 | |
282 | === modified file 'tests/test_purchase_good.py' |
283 | --- tests/test_purchase_good.py 2013-05-17 13:00:48 +0000 |
284 | +++ tests/test_purchase_good.py 2013-06-19 20:36:26 +0000 |
285 | @@ -1,3 +1,6 @@ |
286 | +import os |
287 | +import subprocess |
288 | + |
289 | from sst import actions as sactions |
290 | |
291 | # FIXME do not use django config to get the server settings. |
292 | @@ -22,9 +25,24 @@ |
293 | # Set the urls of the servers that will be used by the user. |
294 | self.user.set_servers_data( |
295 | sso_server_url=conf.settings.OPENID_SSO_SERVER_URL, |
296 | + pay_server_url=conf.settings.PAY_SERVER_URL, |
297 | + consumer_id=conf.settings.CONSUMER_ID, |
298 | ubuntuone_server_url=conf.settings.UBUNTUONE_SERVER_URL) |
299 | # Arbitrarily using a good that is known to work |
300 | self.good = goods.Good(u'Jimi Hendrix', 'hendrix') |
301 | + self._run_music_lens() |
302 | + |
303 | + def _run_music_lens(self): |
304 | + os.environ['MUSICSTORE_URI'] = ( |
305 | + conf.settings.MUSICSEARCH_SERVER_URL + '/v1/') |
306 | + os.environ['U1_STAGING_AUTHENTICATION'] = ( |
307 | + conf.settings.OPENID_SSO_SERVER_URL + '/') |
308 | + os.environ['U1_STAGING_WEBAPI'] = ( |
309 | + conf.settings.UBUNTUONE_SERVER_URL + '/') |
310 | + os.system('pkill unity-music') |
311 | + subprocess.Popen( |
312 | + '/usr/lib/x86_64-linux-gnu/unity-lens-music/' |
313 | + 'unity-musicstore-daemon') |
314 | |
315 | def preview_good(self): |
316 | home = dash.Home(self.user) |
317 | @@ -39,22 +57,10 @@ |
318 | |
319 | class TestUserCannotPay(TestPurchaseGood): |
320 | |
321 | - scenarios = [(name, {'scope_name': name}) for name in ('home', 'music',)] |
322 | - |
323 | def test_user_not_logged_in(self): |
324 | self.assertFalse(self.user.is_logged_in()) |
325 | self.preview_good() |
326 | - if self.scope_name == 'music': |
327 | - # There is a workaround in place for the music scope only that |
328 | - # forbids testing the rest of the workflow |
329 | - self.assertIs(None, self.preview.get_download_button()) |
330 | - message = self.preview.get_message_replacing_action() |
331 | - self.assertEqual('Before you can purchase music you need' |
332 | - ' to log in to the Ubuntu One app', message) |
333 | - return |
334 | - goto_u1 = self.purchase_good() |
335 | - # diverges from the design spec, we go directly to the web |
336 | - # self.assertTrue(goto_u1.good_displayed()) |
337 | + self.purchase_good() |
338 | browser = browsers.Browser(self) |
339 | # We've been redirected to the web |
340 | browser.switch_to_new_window(self) |
341 | @@ -65,27 +71,14 @@ |
342 | def test_no_payment_method_stored(self): |
343 | # Log in with a newly created user, and set no payment method to him. |
344 | self.user.login(self) |
345 | - self.user.payment_method = None |
346 | + self.assertIs(self.user.get_payment_type(), None) |
347 | self.preview_good() |
348 | goto_u1 = self.purchase_good() |
349 | self.assertTrue(goto_u1.good_displayed()) |
350 | self.assertIn('add a payment method', goto_u1.message) |
351 | - # The default browser is launched to propose paying |
352 | - browser = goto_u1.click_goto_u1() |
353 | - # User is sent to the web |
354 | - self.assertTrue(browser.is_running()) |
355 | - self.assertEqual('https://pay.ubuntu.com', browser.current_url) |
356 | - |
357 | - def test_pay_method_expired(self): |
358 | - # Users's payment has expired |
359 | - self.user.login(self) |
360 | - self.user.payment_method = 'expired' |
361 | - self.preview_good() |
362 | - goto_u1 = self.purchase_good() |
363 | - self.assertTrue(goto_u1.good_displayed()) |
364 | - self.assertIn('card has expired', goto_u1.message) |
365 | - # The default browser is launched to propose paying |
366 | - browser = goto_u1.click_goto_u1() |
367 | - # User is sent to the web |
368 | - self.assertTrue(browser.is_running()) |
369 | - self.assertEqual('https://pay.ubuntu.com', browser.current_url) |
370 | + self.skipTest('We are blocked at this point because of bug #1185486.') |
371 | + # The default browser is launched to propose paying |
372 | + #browser = goto_u1.click_goto_u1() |
373 | + # User is sent to the web |
374 | + #self.assertTrue(browser.is_running()) |
375 | + #self.assertEqual(conf.settings.PAY_SERVER_URL, browser.current_url) |
376 | |
377 | === modified file 'tests/test_session.py' |
378 | --- tests/test_session.py 2013-02-20 15:53:53 +0000 |
379 | +++ tests/test_session.py 2013-06-19 20:36:26 +0000 |
380 | @@ -1,6 +1,6 @@ |
381 | import tests |
382 | |
383 | -from gi.repository import Gio, Gtk |
384 | +from gi.repository import Gio |
385 | |
386 | class TestGSettings(tests.TestCase): |
387 |
44 + # TODO We should check if the result is visible, instead of checking if
45 + # there are visible categories. I don't know how to do it, I'll ask
46 + # --elopio - 2013-05-19
I thought the following was doing that:
91 - refresh_results_fn = lambda: len(category. get_results( )) (refresh_ results_ fn, Eventually( GreaterThan( 0))) get_results( )[0]
92 - test.assertThat
93 - # Select first result as soon as it appears
94 - return category.
This also ensures that there is at least one result which the following
doesn't seem to care about:
40 + return category. get_results( )[0]
I'm not sure about why you thunk some methods to functions but as long as
daughter classes can still redefine the methods, I don't have strong
objections either.