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: | Leonardo Arias Fonseca |
| 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
- 64. By Leonardo Arias Fonseca
-
Assert that there is at least one result displayed.
| Leonardo Arias Fonseca (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.