Merge lp:~dobey/ubuntuone-credentials/update-13-10 into lp:ubuntuone-credentials/stable-13-10

Proposed by dobey
Status: Merged
Approved by: dobey
Approved revision: 33
Merged at revision: 33
Proposed branch: lp:~dobey/ubuntuone-credentials/update-13-10
Merge into: lp:ubuntuone-credentials/stable-13-10
Diff against target: 750 lines (+432/-7)
20 files modified
CMakeLists.txt (+1/-1)
libubuntuoneauth/errormessages.h (+3/-1)
libubuntuoneauth/network.cpp (+0/-2)
libubuntuoneauth/responses.h (+1/-1)
online-accounts-provider/ButtonRow.qml (+2/-0)
online-accounts-provider/CMakeLists.txt (+2/-0)
online-accounts-provider/ExistingAccount.qml (+4/-0)
online-accounts-provider/LoginForm.qml (+4/-1)
online-accounts-provider/Main.qml (+12/-0)
online-accounts-provider/NewAccount.qml (+6/-0)
online-accounts-provider/RegisterForm.qml (+7/-0)
online-accounts-provider/tests/CMakeLists.txt (+10/-0)
online-accounts-provider/tests/autopilot/TestWrapperExisting.qml (+42/-0)
online-accounts-provider/tests/autopilot/TestWrapperNew.qml (+48/-0)
online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/__init__.py (+124/-0)
online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/__init__.py (+1/-0)
online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/test_main.py (+144/-0)
online-accounts-provider/tests/autopilot/run (+12/-0)
qml-credentials-service/CMakeLists.txt (+3/-0)
qml-credentials-service/ubuntuone_credentials_service.cpp (+6/-1)
To merge this branch: bzr merge lp:~dobey/ubuntuone-credentials/update-13-10
Reviewer Review Type Date Requested Status
Mike McCracken (community) Approve
Review via email: mp+189411@code.launchpad.net

Commit message

[Michael McCracken]

    - Hide keyboard when user submits form, making error message visible. (LP: #1231580)
    - Use email-specific keyboard layout and avoid storing passwords in predictive input dictionary. (LP: #1235282)
    - Provide general user-friendly error message for network errors. (LP: #1233951)
    - Delete incomplete account when user uses back button to cancel account creation. (LP: #1234285)
    - Add GUI-level autopilot functional test suite to online-accounts-provider.

To post a comment you must log in.
Revision history for this message
Mike McCracken (mikemc) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'CMakeLists.txt'
2--- CMakeLists.txt 2013-09-16 17:44:17 +0000
3+++ CMakeLists.txt 2013-10-04 19:17:45 +0000
4@@ -10,7 +10,7 @@
5 SET (AUTH_LIB_API_VERSION 2.0)
6 SET (AUTH_LIB_NAME ubuntuoneauth-${AUTH_LIB_API_VERSION})
7
8-# these names are also used in qml-credentials-service/qmldir, be sure to change them in both places
9+# these names are used in qml-credentials-service/qmldir.template
10 SET (QML_MODULE_NAME UbuntuOne)
11 SET (QML_PLUGIN_API_VERSION 1.0)
12 SET (QML_PLUGIN_NAME UbuntuOneCredentialsPlugin-${QML_PLUGIN_API_VERSION})
13
14=== modified file 'libubuntuoneauth/errormessages.h'
15--- libubuntuoneauth/errormessages.h 2013-06-14 22:30:19 +0000
16+++ libubuntuoneauth/errormessages.h 2013-10-04 19:17:45 +0000
17@@ -1,6 +1,9 @@
18 #ifndef ERROR_MESSAGES_H
19 #define ERROR_MESSAGES_H
20
21+
22+#define NO_HTTP_REASON "No HTTP error reason"
23+
24 #define LOGIN_FAILED "LOGIN_FAILED"
25 #define CAPTCHA_REQUIRED "CAPTCHA_REQUIRED"
26 #define INVALID_CREDENTIALS "INVALID_CREDENTIALS"
27@@ -11,7 +14,6 @@
28 #define CAN_NOT_RESET_PASSWORD "CAN_NOT_RESET_PASSWORD"
29 #define ALREADY_REGISTERED "ALREADY_REGISTERED"
30
31-
32 enum ErrorCodes
33 {
34 CODE_LOGIN_FAILED = 0,
35
36=== modified file 'libubuntuoneauth/network.cpp'
37--- libubuntuoneauth/network.cpp 2013-07-23 15:47:07 +0000
38+++ libubuntuoneauth/network.cpp 2013-10-04 19:17:45 +0000
39@@ -28,8 +28,6 @@
40 #include "responses.h"
41 #include "requests.h"
42
43-#define NO_HTTP_REASON QString("No HTTP error reason")
44-
45 namespace UbuntuOne {
46
47 Network::Network(QObject *parent)
48
49=== modified file 'libubuntuoneauth/responses.h'
50--- libubuntuoneauth/responses.h 2013-06-14 22:39:59 +0000
51+++ libubuntuoneauth/responses.h 2013-10-04 19:17:45 +0000
52@@ -131,4 +131,4 @@
53
54 } /* end UbuntuOne namespace */
55
56-#endif /* _REQUESTS_H_ */
57+#endif /* _RESPONSES_H_ */
58
59=== modified file 'online-accounts-provider/ButtonRow.qml'
60--- online-accounts-provider/ButtonRow.qml 2013-09-13 18:49:09 +0000
61+++ online-accounts-provider/ButtonRow.qml 2013-10-04 19:17:45 +0000
62@@ -7,6 +7,7 @@
63 spacing: units.gu(1)
64 Button {
65 id: btnCancel
66+ objectName: "cancelButton"
67 text: "Cancel"
68 color: "#1c091a"
69 height: parent.height
70@@ -17,6 +18,7 @@
71 }
72 Button {
73 id: btnContinue
74+ objectName: "continueButton"
75 text: "Continue"
76 color: "#cc3300"
77 height: parent.height
78
79=== modified file 'online-accounts-provider/CMakeLists.txt'
80--- online-accounts-provider/CMakeLists.txt 2013-08-26 19:51:56 +0000
81+++ online-accounts-provider/CMakeLists.txt 2013-10-04 19:17:45 +0000
82@@ -4,3 +4,5 @@
83 set (QML_PLUGIN_INSTALL_DIR share/accounts/qml-plugins/ubuntuone/)
84
85 install (FILES ${QML_PLUGIN_FILES} DESTINATION ${QML_PLUGIN_INSTALL_DIR})
86+
87+add_subdirectory(tests)
88\ No newline at end of file
89
90=== modified file 'online-accounts-provider/ExistingAccount.qml'
91--- online-accounts-provider/ExistingAccount.qml 2013-09-12 14:59:06 +0000
92+++ online-accounts-provider/ExistingAccount.qml 2013-10-04 19:17:45 +0000
93@@ -33,6 +33,7 @@
94 anchors.right: parent.right
95
96 ListItem.SingleValue {
97+ objectName: "emailListItem"
98 text: "Email"
99 value: account.displayName
100 }
101@@ -45,6 +46,7 @@
102
103 ListItem.SingleControl {
104 control: Button {
105+ objectName: "removeAccountButton"
106 text: "Remove account…"
107 width: parent.width - units.gu(4)
108 onClicked: PopupUtils.open(removalConfirmationComponent);
109@@ -64,6 +66,7 @@
110
111 Button {
112 text: "Remove"
113+ objectName: "confirmRemoveAccountButton"
114 onClicked: {
115 PopupUtils.close(dialog);
116 console.debug("Removing account ID: " + account.accountId);
117@@ -76,6 +79,7 @@
118
119 Button {
120 text: "Cancel"
121+ objectName: "cancelRemoveAccountButton"
122 onClicked: {
123 console.log("User cancelled account removal");
124 PopupUtils.close(dialog);
125
126=== modified file 'online-accounts-provider/LoginForm.qml'
127--- online-accounts-provider/LoginForm.qml 2013-09-13 18:31:34 +0000
128+++ online-accounts-provider/LoginForm.qml 2013-10-04 19:17:45 +0000
129@@ -19,7 +19,7 @@
130
131 TextField {
132 id: passwordTextField
133-
134+ objectName: "loginFormPasswordTextField"
135 placeholderText: "Your password"
136 echoMode: TextInput.Password
137 width: main.width - (2 * main.anchors.margins)
138@@ -27,6 +27,7 @@
139 Keys.onReturnPressed: main.processForm();
140 KeyNavigation.tab: twoFactorUI.visible ? twoFactorTextField : emailTextField /* from main */
141 KeyNavigation.backtab: emailTextField /* from main */
142+ inputMethodHints: Qt.ImhSensitiveData
143 }
144
145 Label {
146@@ -36,6 +37,7 @@
147 }
148
149 ButtonRow {
150+ objectName: "buttonRow-LoginForm-noTwoFactor"
151 anchors.left: parent.left
152 anchors.right: parent.right
153
154@@ -54,6 +56,7 @@
155
156 TextField {
157 id: twoFactorTextField
158+ objectName: "twoFactorTextField"
159 placeholderText: "2-factor device code"
160 echoMode: TextInput.Password
161 width: main.width - (2 * main.anchors.margins)
162
163=== modified file 'online-accounts-provider/Main.qml'
164--- online-accounts-provider/Main.qml 2013-09-13 18:31:34 +0000
165+++ online-accounts-provider/Main.qml 2013-10-04 19:17:45 +0000
166@@ -53,6 +53,17 @@
167 }
168
169 Connections {
170+ target: rootFlickable.parent.parent.tools.back;
171+ onTriggered: {
172+ console.debug("page back button clicked, deleting incomplete account.");
173+ if(account.accountId != 0) {
174+ account.remove(Account.RemoveCredentials);
175+ editPageLoader.item.resetUI();
176+ }
177+ }
178+ }
179+
180+ Connections {
181 target: account
182 onSynced: {
183 console.debug("Account id " + account.accountId + " synced. account.displayName: " + account.displayName)
184@@ -67,6 +78,7 @@
185
186 Rectangle {
187 id: loadingOverlay
188+ objectName: "loadingOverlay"
189 opacity: 0.7
190 color: "white"
191 visible: false
192
193=== modified file 'online-accounts-provider/NewAccount.qml'
194--- online-accounts-provider/NewAccount.qml 2013-09-13 19:28:05 +0000
195+++ online-accounts-provider/NewAccount.qml 2013-10-04 19:17:45 +0000
196@@ -55,6 +55,7 @@
197
198 Label {
199 id: errorLabel
200+ objectName: "errorLabel"
201 text: ""
202 font.bold: true
203 color: "red"
204@@ -75,6 +76,7 @@
205
206 TextField {
207 id: emailTextField
208+ objectName: "emailTextField"
209 placeholderText: "Your email"
210 width: main.width - (2 * main.anchors.margins)
211 anchors.left: parent.left
212@@ -83,6 +85,7 @@
213 focus: true
214 KeyNavigation.tab: loginForm.visible ? loginForm.passwordTextField : registerForm.nameTextField
215 KeyNavigation.backtab: loginForm.visible ? ( loginForm.twoFactorVisible ? loginForm.twoFactorTextField : loginForm.passwordTextField) : registerForm.confirmPasswordTextField
216+ inputMethodHints: Qt.ImhEmailCharactersOnly
217 }
218
219 Row {
220@@ -93,6 +96,7 @@
221
222 Switch {
223 id: newUserToggleSwitch
224+ objectName: "newUserToggleSwitch"
225 checked: false
226
227 onCheckedChanged: {
228@@ -196,6 +200,7 @@
229 immediately.
230 */
231 function processForm() {
232+ Qt.inputMethod.hide();
233 loadingOverlay.visible = true;
234 formSubmitTimer.running = true;
235 }
236@@ -249,6 +254,7 @@
237 }
238
239 function validateInput() {
240+ console.debug("in validateInput, emailTextField.text = " + emailTextField.text);
241 formValid = emailTextField.acceptableInput;
242 if(!formValid) {
243 showError("Please enter a valid email address.");
244
245=== modified file 'online-accounts-provider/RegisterForm.qml'
246--- online-accounts-provider/RegisterForm.qml 2013-09-13 18:31:34 +0000
247+++ online-accounts-provider/RegisterForm.qml 2013-10-04 19:17:45 +0000
248@@ -19,6 +19,7 @@
249
250 TextField {
251 id: nameTextField
252+ objectName: "nameTextField"
253 placeholderText: "Your name"
254 width: main.width - (2 * main.anchors.margins)
255 KeyNavigation.tab: passwordTextField
256@@ -27,26 +28,31 @@
257
258 TextField {
259 id: passwordTextField
260+ objectName: "passwordTextField"
261 placeholderText: "Password with at least 8 characters"
262 echoMode: TextInput.Password
263 width: main.width - (2 * main.anchors.margins)
264 KeyNavigation.tab: confirmPasswordTextField
265 KeyNavigation.backtab: nameTextField
266+ inputMethodHints: Qt.ImhSensitiveData
267 }
268
269 TextField {
270 id: confirmPasswordTextField
271+ objectName: "confirmPasswordTextField"
272 placeholderText: "Re-type password"
273 echoMode: TextInput.Password
274 width: main.width - (2 * main.anchors.margins)
275 KeyNavigation.tab: emailTextField /* from main */
276 KeyNavigation.backtab: passwordTextField
277+ inputMethodHints: Qt.ImhSensitiveData
278 }
279
280 Row {
281 spacing: units.gu(2)
282 CheckBox {
283 id: termsAndConditionsCheckBox
284+ objectName: "termsAndConditionsCheckBox"
285 checked: false
286 }
287
288@@ -58,6 +64,7 @@
289 }
290
291 ButtonRow {
292+ objectName: "buttonRow-RegisterForm"
293 anchors.left: parent.left
294 anchors.right: parent.right
295 }
296
297=== added directory 'online-accounts-provider/tests'
298=== added file 'online-accounts-provider/tests/CMakeLists.txt'
299--- online-accounts-provider/tests/CMakeLists.txt 1970-01-01 00:00:00 +0000
300+++ online-accounts-provider/tests/CMakeLists.txt 2013-10-04 19:17:45 +0000
301@@ -0,0 +1,10 @@
302+SET (TESTS_TARGET test-online-accounts-provider)
303+
304+add_custom_target(online-accounts-provider-autopilot-tests
305+ COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/autopilot/run ${CMAKE_CURRENT_BINARY_DIR}
306+ DEPENDS ${QML_PLUGIN_NAME}
307+)
308+
309+add_custom_target(online-accounts-provider-qmlunit-tests
310+ COMMAND qmltestrunner -input ${CMAKE_CURRENT_SOURCE_DIR}/unit
311+)
312
313=== added directory 'online-accounts-provider/tests/autopilot'
314=== added file 'online-accounts-provider/tests/autopilot/TestWrapperExisting.qml'
315--- online-accounts-provider/tests/autopilot/TestWrapperExisting.qml 1970-01-01 00:00:00 +0000
316+++ online-accounts-provider/tests/autopilot/TestWrapperExisting.qml 2013-10-04 19:17:45 +0000
317@@ -0,0 +1,42 @@
318+import QtQuick 2.0
319+import Ubuntu.Components 0.1
320+import Ubuntu.OnlineAccounts 0.1
321+import UbuntuOne 1.0
322+
323+
324+MainView {
325+
326+ objectName: "mainView"
327+
328+ applicationName: "Ubuntu One UOA Provider Plugin Tester"
329+
330+ width: units.gu(100)
331+ height: units.gu(100)
332+
333+ Page {
334+ title: "testing"
335+ objectName: "testingPage"
336+
337+ Rectangle {
338+ id: fakeAccount
339+ objectName: "FakeExistingUOAAccount"
340+ property var accountId: 47
341+ signal synced
342+
343+ property string displayName: "my@email.com"
344+ function remove(){
345+ }
346+ }
347+
348+ Loader {
349+ id: loader
350+ property var account: fakeAccount
351+
352+ anchors.fill: parent
353+
354+ source: "../../Main.qml"
355+
356+ }
357+
358+ }
359+}
360\ No newline at end of file
361
362=== added file 'online-accounts-provider/tests/autopilot/TestWrapperNew.qml'
363--- online-accounts-provider/tests/autopilot/TestWrapperNew.qml 1970-01-01 00:00:00 +0000
364+++ online-accounts-provider/tests/autopilot/TestWrapperNew.qml 2013-10-04 19:17:45 +0000
365@@ -0,0 +1,48 @@
366+import QtQuick 2.0
367+import Ubuntu.Components 0.1
368+import Ubuntu.OnlineAccounts 0.1
369+import UbuntuOne 1.0
370+
371+
372+MainView {
373+
374+ objectName: "mainView"
375+
376+ applicationName: "Ubuntu One UOA Provider Plugin Tester"
377+
378+ width: units.gu(100)
379+ height: units.gu(100)
380+
381+ Page {
382+ title: "testing"
383+ id: testingPage
384+ objectName: "testingPage"
385+
386+ Rectangle {
387+ id: fakeAccount
388+ objectName: "FakeNewUOAAccount"
389+ property var accountId: 0
390+ signal synced
391+
392+ property string displayName: ""
393+ function sync() {
394+ }
395+
396+ /* fake to avoid creating a UOA account */
397+ property var objectHandle: Qt.createQmlObject('import QtQuick 2.0; Rectangle {}',
398+ testingPage,
399+ "dynamically-created-fakerect");
400+ }
401+
402+ Loader {
403+ id: loader
404+ property var account: fakeAccount
405+
406+ anchors.fill: parent
407+
408+ source: "../../Main.qml"
409+
410+ }
411+
412+ }
413+}
414\ No newline at end of file
415
416=== added directory 'online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests'
417=== added file 'online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/__init__.py'
418--- online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/__init__.py 1970-01-01 00:00:00 +0000
419+++ online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/__init__.py 2013-10-04 19:17:45 +0000
420@@ -0,0 +1,124 @@
421+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
422+
423+"""UbuntuOne Credentials Online-Accounts provider plugin autopilot tests."""
424+
425+from os import remove
426+import os.path
427+from tempfile import mktemp
428+import subprocess
429+
430+from autopilot.input import Mouse, Touch, Pointer
431+from autopilot.matchers import Eventually
432+from autopilot.platform import model
433+from testtools.matchers import Is, Not, Equals
434+from autopilot.testcase import AutopilotTestCase
435+
436+
437+def get_module_include_path():
438+ return os.path.abspath(
439+ os.path.join(
440+ os.path.dirname(__file__),
441+ '..',
442+ '..',
443+ '..',
444+ '..',
445+ 'modules')
446+ )
447+
448+
449+class UbuntuTouchAppTestCase(AutopilotTestCase):
450+ """Provides several useful methods for the tests."""
451+
452+ if model() == 'Desktop':
453+ scenarios = [
454+ ('with mouse', dict(input_device_class=Mouse))
455+ ]
456+ else:
457+ scenarios = [
458+ ('with touch', dict(input_device_class=Touch))
459+ ]
460+
461+ @property
462+ def main_window(self):
463+ return MainWindow(self.app)
464+
465+ def setUp(self):
466+ self.pointing_device = Pointer(self.input_device_class.create())
467+ super(UbuntuTouchAppTestCase, self).setUp()
468+ self.launch_test_qml()
469+
470+ def launch_test_qml(self):
471+ # If the test class has defined a 'test_qml' class attribute then we
472+ # write it to disk and launch it inside the QML Scene. If not, then we
473+ # silently do nothing (presumably the test has something else planned).
474+ arch = subprocess.check_output(["dpkg-architecture",
475+ "-qDEB_HOST_MULTIARCH"]).strip()
476+
477+ if hasattr(self, 'test_qml') and isinstance(self.test_qml, basestring):
478+ qml_path = mktemp(suffix='.qml')
479+ open(qml_path, 'w').write(self.test_qml)
480+ self.addCleanup(remove, qml_path)
481+
482+ self.app = self.launch_test_application(
483+ "/usr/lib/" + arch + "/qt5/bin/qmlscene",
484+ "-I", get_module_include_path(),
485+ qml_path,
486+ app_type='qt')
487+
488+ if hasattr(self, 'test_qml_file') and isinstance(self.test_qml_file, basestring):
489+ qml_path = self.test_qml_file
490+ self.app = self.launch_test_application(
491+ "/usr/lib/" + arch + "/qt5/bin/qmlscene",
492+ "-I", get_module_include_path(),
493+ qml_path,
494+ app_type='qt')
495+
496+ self.assertThat(self.get_qml_view().visible, Eventually(Equals(True)))
497+
498+ def get_qml_view(self):
499+ """Get the main QML view"""
500+
501+ return self.app.select_single("QQuickView")
502+
503+ def get_mainview(self):
504+ """Get the QML MainView"""
505+
506+ mainView = self.app.select_single("MainView")
507+ self.assertThat(mainView, Not(Is(None)))
508+ return mainView
509+
510+ def get_object(self, objectName):
511+ """Get a object based on the objectName"""
512+
513+ obj = self.app.select_single(objectName=objectName)
514+ self.assertThat(obj, Not(Is(None)))
515+ return obj
516+
517+ def mouse_click(self, objectName):
518+ """Move mouse on top of the object and click on it"""
519+
520+ obj = self.get_object(objectName)
521+ self.pointing_device.move_to_object(obj)
522+ self.pointing_device.click()
523+
524+ def mouse_press(self, objectName):
525+ """Move mouse on top of the object and press and hold mouse button"""
526+
527+ obj = self.get_object(objectName)
528+ self.pointing_device.move_to_object(obj)
529+ self.pointing_device.press()
530+
531+ def mouse_release(self):
532+ """Release mouse button"""
533+
534+ self.pointing_device.release()
535+
536+ def type_string(self, string):
537+ """Type a string with keyboard"""
538+
539+ self.keyboard.type(string)
540+
541+ def type_key(self, key):
542+ """Type a single key with keyboard"""
543+
544+ self.keyboard.key(key)
545
546=== added directory 'online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main'
547=== added file 'online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/__init__.py'
548--- online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/__init__.py 1970-01-01 00:00:00 +0000
549+++ online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/__init__.py 2013-10-04 19:17:45 +0000
550@@ -0,0 +1,1 @@
551+""" A Generic test suite """
552
553=== added file 'online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/test_main.py'
554--- online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/test_main.py 1970-01-01 00:00:00 +0000
555+++ online-accounts-provider/tests/autopilot/UbuntuOneCredentialsProviderAutopilotTests/main/test_main.py 2013-10-04 19:17:45 +0000
556@@ -0,0 +1,144 @@
557+# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
558+
559+"""Tests for launching the plugin"""
560+
561+from autopilot.matchers import Eventually
562+from testtools.matchers import Equals
563+import os
564+from UbuntuOneCredentialsProviderAutopilotTests import UbuntuTouchAppTestCase
565+
566+
567+class NewUOAAccountTests(UbuntuTouchAppTestCase):
568+
569+ test_qml_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
570+ "../../")
571+ test_qml_filename = "TestWrapperNew.qml"
572+ test_qml_file = os.path.join(test_qml_path, test_qml_filename)
573+
574+ def setUp(self):
575+ super(NewUOAAccountTests, self).setUp()
576+ self.uoa_account = self.get_object(objectName="FakeNewUOAAccount")
577+
578+ def test_select_mainView(self):
579+ mainView = self.get_mainview()
580+ self.assertThat(mainView.visible, Eventually(Equals(True)))
581+
582+ def test_loadingOverlay_starts_invisible(self):
583+ overlay = self.get_object(objectName="loadingOverlay")
584+ self.assertThat(overlay.visible, Eventually(Equals(False)))
585+
586+ def test_email_field_visible_focused(self):
587+ emailTextField = self.get_object(objectName="emailTextField")
588+ self.assertThat(emailTextField.visible, Eventually(Equals(True)))
589+ self.assertThat(emailTextField.focus, Eventually(Equals(True)))
590+
591+ def test_login_initial_state(self):
592+ passwordTextField = self.get_object("loginFormPasswordTextField")
593+ self.assertThat(passwordTextField.visible, Eventually(Equals(True)))
594+ twoFactorTextField = self.get_object(objectName="twoFactorTextField")
595+ self.assertThat(twoFactorTextField.visible, Eventually(Equals(False)))
596+
597+ def test_switch_to_newuser(self):
598+
599+ self.mouse_click(objectName="newUserToggleSwitch")
600+
601+ passwordField = self.get_object("loginFormPasswordTextField")
602+ self.assertThat(passwordField.visible, Eventually(Equals(False)))
603+
604+ nameTextField = self.get_object("nameTextField")
605+ self.assertThat(nameTextField.visible, Eventually(Equals(True)))
606+
607+ def click_continuebutton_from(self, parentObjectName):
608+ parent = self.get_object(parentObjectName)
609+ continueButton = parent.select_single(objectName="continueButton")
610+ self.pointing_device.move_to_object(continueButton)
611+ self.pointing_device.click()
612+
613+ def test_login_error_on_no_input(self):
614+ errorTextField = self.get_object("errorLabel")
615+ self.assertThat(errorTextField.visible, Eventually(Equals(False)))
616+ self.click_continuebutton_from("buttonRow-LoginForm-noTwoFactor")
617+ self.assertThat(errorTextField.visible, Eventually(Equals(True)))
618+
619+ def test_login_error_on_bad_email(self):
620+ errorTextField = self.get_object("errorLabel")
621+ self.assertThat(errorTextField.visible, Eventually(Equals(False)))
622+ self.mouse_click("emailTextField")
623+ self.type_string("this isn't a valid email")
624+
625+ self.click_continuebutton_from("buttonRow-LoginForm-noTwoFactor")
626+ self.assertThat(errorTextField.visible, Eventually(Equals(True)))
627+
628+ def _setup_newuser_errors(self):
629+ self.emailTextField = self.get_object("emailTextField")
630+ self.mouse_click("emailTextField")
631+ self.type_string("valid@email.com")
632+ self.assertThat(self.emailTextField.acceptableInput,
633+ Eventually(Equals(True)))
634+ self.errorTextField = self.get_object("errorLabel")
635+ self.mouse_click(objectName="newUserToggleSwitch")
636+
637+ def test_newuser_error_on_no_name(self):
638+ self._setup_newuser_errors()
639+ self.click_continuebutton_from("buttonRow-RegisterForm")
640+ self.assertThat(self.errorTextField.visible, Eventually(Equals(True)))
641+
642+ def test_newuser_error_on_no_password(self):
643+ self._setup_newuser_errors()
644+ self.mouse_click("nameTextField")
645+ self.type_string("A Name")
646+ self.click_continuebutton_from("buttonRow-RegisterForm")
647+ self.assertThat(self.errorTextField.visible, Eventually(Equals(True)))
648+
649+ def test_newuser_error_on_no_password_match(self):
650+ self._setup_newuser_errors()
651+ self.mouse_click("nameTextField")
652+ self.type_string("A Name")
653+
654+ self.mouse_click("passwordTextField")
655+ self.type_string("12345678910111213141516")
656+ self.mouse_click("confirmPasswordTextField")
657+ self.type_string("123456789ABCDEF")
658+ self.mouse_click(objectName="termsAndConditionsCheckBox")
659+ self.click_continuebutton_from("buttonRow-RegisterForm")
660+ self.assertThat(self.errorTextField.visible, Eventually(Equals(True)))
661+
662+ def test_newuser_error_on_short_password(self):
663+ self._setup_newuser_errors()
664+ self.mouse_click("nameTextField")
665+ self.type_string("A Name")
666+ self.mouse_click("passwordTextField")
667+ self.type_string("123")
668+ self.mouse_click("confirmPasswordTextField")
669+ self.type_string("123")
670+ self.mouse_click(objectName="termsAndConditionsCheckBox")
671+ self.click_continuebutton_from("buttonRow-RegisterForm")
672+ self.assertThat(self.errorTextField.visible, Eventually(Equals(True)))
673+
674+
675+class ExistingUOAAccountTests(UbuntuTouchAppTestCase):
676+
677+ test_qml_path = os.path.join(os.path.dirname(os.path.realpath(__file__)),
678+ "../../")
679+ test_qml_filename = "TestWrapperExisting.qml"
680+ test_qml_file = os.path.join(test_qml_path, test_qml_filename)
681+
682+ def setUp(self):
683+ super(ExistingUOAAccountTests, self).setUp()
684+ self.uoa_account = self.get_object(objectName="FakeExistingUOAAccount")
685+
686+ def test_show_remove_account_dialog(self):
687+
688+ self.mouse_click(objectName="removeAccountButton")
689+
690+ confirmRemoveButton = self.get_object("confirmRemoveAccountButton")
691+
692+ self.assertThat(confirmRemoveButton.visible,
693+ Eventually(Equals(True)))
694+
695+ self.mouse_click(objectName="cancelRemoveAccountButton")
696+
697+ def test_shows_expected_email(self):
698+ emailListItem = self.get_object("emailListItem")
699+ self.assertThat(emailListItem.value,
700+ Eventually(Equals("my@email.com")))
701
702=== added file 'online-accounts-provider/tests/autopilot/run'
703--- online-accounts-provider/tests/autopilot/run 1970-01-01 00:00:00 +0000
704+++ online-accounts-provider/tests/autopilot/run 2013-10-04 19:17:45 +0000
705@@ -0,0 +1,12 @@
706+#!/bin/bash
707+
708+if [[ -z `which autopilot` ]]; then
709+ echo "Autopilot is not installed. Skip"
710+ exit
711+fi
712+
713+SCRIPTPATH=`dirname $0`
714+pushd ${SCRIPTPATH}
715+export QML2_IMPORT_PATH=/usr/lib/i386-linux-gnu/ubuntu-system-settings/private:$1/../../qml-credentials-service
716+autopilot run UbuntuOneCredentialsProviderAutopilotTests
717+popd
718
719=== modified file 'qml-credentials-service/CMakeLists.txt'
720--- qml-credentials-service/CMakeLists.txt 2013-08-21 20:49:46 +0000
721+++ qml-credentials-service/CMakeLists.txt 2013-10-04 19:17:45 +0000
722@@ -23,3 +23,6 @@
723 )
724
725 install (CODE "execute_process(COMMAND qmlplugindump ${QML_MODULE_NAME} ${QML_PLUGIN_API_VERSION} ${CMAKE_INSTALL_PREFIX}/${QML_MODULE_INSTALL_DIR} OUTPUT_FILE ${CMAKE_INSTALL_PREFIX}/${QML_MODULE_INSTALL_DIR}/${QML_MODULE_NAME}/${QML_MODULE_NAME}.qmltypes)")
726+
727+add_custom_command(TARGET ${QML_PLUGIN_NAME} POST_BUILD
728+ COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR} ${QML_MODULE_NAME})
729\ No newline at end of file
730
731=== modified file 'qml-credentials-service/ubuntuone_credentials_service.cpp'
732--- qml-credentials-service/ubuntuone_credentials_service.cpp 2013-08-26 18:42:47 +0000
733+++ qml-credentials-service/ubuntuone_credentials_service.cpp 2013-10-04 19:17:45 +0000
734@@ -1,4 +1,5 @@
735 #include "ubuntuone_credentials_service.h"
736+#include "errormessages.h"
737 #include <QDebug>
738
739 UbuntuOneCredentialsService::UbuntuOneCredentialsService(QQuickItem *parent):
740@@ -153,5 +154,9 @@
741 void UbuntuOneCredentialsService::handleError(const ErrorResponse& error)
742 {
743 _state = IDLE;
744- emit loginOrRegisterError(error.message());
745+ if (error.httpStatus() == 0 || error.httpReason() == NO_HTTP_REASON) {
746+ emit loginOrRegisterError("Network error - please retry.");
747+ } else {
748+ emit loginOrRegisterError(error.message());
749+ }
750 }

Subscribers

People subscribed via source and target branches

to all changes: