Merge lp:~dobey/pay-ui/js-dialogs into lp:pay-ui

Proposed by dobey
Status: Merged
Approved by: dobey
Approved revision: 119
Merged at revision: 120
Proposed branch: lp:~dobey/pay-ui/js-dialogs
Merge into: lp:pay-ui
Diff against target: 523 lines (+396/-16)
8 files modified
app/components/AlertDialog.qml (+31/-0)
app/components/BeforeUnloadDialog.qml (+37/-0)
app/components/ConfirmDialog.qml (+37/-0)
app/components/ModalDialog.qml (+32/-0)
app/components/PromptDialog.qml (+51/-0)
app/ui/UbuntuPurchaseWebkit.qml (+6/-0)
tests/autopilot/pay_ui/tests/mock_server.py (+104/-12)
tests/autopilot/pay_ui/tests/test_pay_ui.py (+98/-4)
To merge this branch: bzr merge lp:~dobey/pay-ui/js-dialogs
Reviewer Review Type Date Requested Status
Alejandro J. Cura (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+253280@code.launchpad.net

Commit message

Add support for JS dialogs in the web view.

Description of the change

Please do not top approve, as landing clicks in the store requires a bit of manual work still.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~dobey/pay-ui/js-dialogs updated
118. By dobey

Add the ModalDialog from webbrowser-app as well, needed by JS dialogs.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~dobey/pay-ui/js-dialogs updated
119. By dobey

Update tests.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Alejandro J. Cura (alecu) wrote :

Branch looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'app/components/AlertDialog.qml'
2--- app/components/AlertDialog.qml 1970-01-01 00:00:00 +0000
3+++ app/components/AlertDialog.qml 2015-03-25 20:08:56 +0000
4@@ -0,0 +1,31 @@
5+/*
6+ * Copyright 2013-2014 Canonical Ltd.
7+ *
8+ * This file is part of webbrowser-app.
9+ *
10+ * webbrowser-app is free software; you can redistribute it and/or modify
11+ * it under the terms of the GNU General Public License as published by
12+ * the Free Software Foundation; version 3.
13+ *
14+ * webbrowser-app is distributed in the hope that it will be useful,
15+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
16+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+ * GNU General Public License for more details.
18+ *
19+ * You should have received a copy of the GNU General Public License
20+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
21+ */
22+
23+import QtQuick 2.0
24+import Ubuntu.Components 1.1
25+
26+ModalDialog {
27+ objectName: "alertDialog"
28+ title: i18n.dtr("webbrowser-app", "JavaScript Alert")
29+
30+ Button {
31+ objectName: "dialogOkButton"
32+ text: i18n.dtr("webbrowser-app", "OK")
33+ onClicked: model.accept()
34+ }
35+}
36
37=== added file 'app/components/BeforeUnloadDialog.qml'
38--- app/components/BeforeUnloadDialog.qml 1970-01-01 00:00:00 +0000
39+++ app/components/BeforeUnloadDialog.qml 2015-03-25 20:08:56 +0000
40@@ -0,0 +1,37 @@
41+/*
42+ * Copyright 2014 Canonical Ltd.
43+ *
44+ * This file is part of webbrowser-app.
45+ *
46+ * webbrowser-app is free software; you can redistribute it and/or modify
47+ * it under the terms of the GNU General Public License as published by
48+ * the Free Software Foundation; version 3.
49+ *
50+ * webbrowser-app is distributed in the hope that it will be useful,
51+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
52+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
53+ * GNU General Public License for more details.
54+ *
55+ * You should have received a copy of the GNU General Public License
56+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
57+ */
58+
59+import QtQuick 2.0
60+import Ubuntu.Components 1.1
61+
62+ModalDialog {
63+ title: i18n.dtr("webbrowser-app", "Confirm Navigation")
64+ objectName: "beforeUnloadDialog"
65+
66+ Button {
67+ objectName: "leaveButton"
68+ text: i18n.dtr("webbrowser-app", "Leave")
69+ onClicked: model.accept()
70+ }
71+
72+ Button {
73+ objectName: "stayButton"
74+ text: i18n.dtr("webbrowser-app", "Stay")
75+ onClicked: model.reject()
76+ }
77+}
78
79=== added file 'app/components/ConfirmDialog.qml'
80--- app/components/ConfirmDialog.qml 1970-01-01 00:00:00 +0000
81+++ app/components/ConfirmDialog.qml 2015-03-25 20:08:56 +0000
82@@ -0,0 +1,37 @@
83+/*
84+ * Copyright 2013-2014 Canonical Ltd.
85+ *
86+ * This file is part of webbrowser-app.
87+ *
88+ * webbrowser-app is free software; you can redistribute it and/or modify
89+ * it under the terms of the GNU General Public License as published by
90+ * the Free Software Foundation; version 3.
91+ *
92+ * webbrowser-app is distributed in the hope that it will be useful,
93+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
94+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
95+ * GNU General Public License for more details.
96+ *
97+ * You should have received a copy of the GNU General Public License
98+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
99+ */
100+
101+import QtQuick 2.0
102+import Ubuntu.Components 1.1
103+
104+ModalDialog {
105+ objectName: "confirmDialog"
106+ title: i18n.dtr("webbrowser-app", "JavaScript Confirmation")
107+
108+ Button {
109+ objectName: "dialogOkButton"
110+ text: i18n.dtr("webbrowser-app", "OK")
111+ onClicked: model.accept()
112+ }
113+
114+ Button {
115+ objectName: "dialogCancelButton"
116+ text: i18n.dtr("webbrowser-app", "Cancel")
117+ onClicked: model.reject()
118+ }
119+}
120
121=== added file 'app/components/ModalDialog.qml'
122--- app/components/ModalDialog.qml 1970-01-01 00:00:00 +0000
123+++ app/components/ModalDialog.qml 2015-03-25 20:08:56 +0000
124@@ -0,0 +1,32 @@
125+/*
126+ * Copyright 2014 Canonical Ltd.
127+ *
128+ * This file is part of webbrowser-app.
129+ *
130+ * webbrowser-app is free software; you can redistribute it and/or modify
131+ * it under the terms of the GNU General Public License as published by
132+ * the Free Software Foundation; version 3.
133+ *
134+ * webbrowser-app is distributed in the hope that it will be useful,
135+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
136+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
137+ * GNU General Public License for more details.
138+ *
139+ * You should have received a copy of the GNU General Public License
140+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
141+ */
142+
143+import QtQuick 2.0
144+import Ubuntu.Components 1.1
145+import Ubuntu.Components.Popups 1.0 as Popups
146+
147+Popups.Dialog {
148+ text: model.message
149+
150+ // Set the parent at construction time, instead of letting show()
151+ // set it later on, which for some reason results in the size of
152+ // the dialog not being updated.
153+ parent: QuickUtils.rootItem(this)
154+
155+ Component.onCompleted: show()
156+}
157
158=== added file 'app/components/PromptDialog.qml'
159--- app/components/PromptDialog.qml 1970-01-01 00:00:00 +0000
160+++ app/components/PromptDialog.qml 2015-03-25 20:08:56 +0000
161@@ -0,0 +1,51 @@
162+/*
163+ * Copyright 2013-2014 Canonical Ltd.
164+ *
165+ * This file is part of webbrowser-app.
166+ *
167+ * webbrowser-app is free software; you can redistribute it and/or modify
168+ * it under the terms of the GNU General Public License as published by
169+ * the Free Software Foundation; version 3.
170+ *
171+ * webbrowser-app is distributed in the hope that it will be useful,
172+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
173+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
174+ * GNU General Public License for more details.
175+ *
176+ * You should have received a copy of the GNU General Public License
177+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
178+ */
179+
180+import QtQuick 2.0
181+import Ubuntu.Components 1.1
182+
183+ModalDialog {
184+ title: i18n.dtr("webbrowser-app", "JavaScript Prompt")
185+
186+ TextField {
187+ objectName: "dialogInput"
188+ id: input
189+ text: model.defaultValue
190+ onAccepted: model.accept(input.text)
191+ }
192+
193+ Button {
194+ objectName: "dialogOkButton"
195+ text: i18n.dtr("webbrowser-app", "OK")
196+ color: "green"
197+ onClicked: model.accept(input.text)
198+ }
199+
200+ Button {
201+ objectName: "dialogCancelButton"
202+ text: i18n.dtr("webbrowser-app", "Cancel")
203+ color: UbuntuColors.coolGrey
204+ onClicked: model.reject()
205+ }
206+
207+ Binding {
208+ target: model
209+ property: "currentValue"
210+ value: input.text
211+ }
212+}
213
214=== modified file 'app/ui/UbuntuPurchaseWebkit.qml'
215--- app/ui/UbuntuPurchaseWebkit.qml 2015-01-07 03:46:02 +0000
216+++ app/ui/UbuntuPurchaseWebkit.qml 2015-03-25 20:08:56 +0000
217@@ -80,6 +80,12 @@
218 anchors.fill: parent
219 anchors.bottomMargin: pageWebkit.keyboardSize
220
221+ // We need to specify the dialogs to use for JS dialogs here.
222+ alertDialog: AlertDialog {}
223+ confirmDialog: ConfirmDialog {}
224+ promptDialog: PromptDialog {}
225+ beforeUnloadDialog: BeforeUnloadDialog {}
226+
227 onLoadingChanged: {
228 pageWebkit.loading(webView.loading);
229 }
230
231=== modified file 'tests/autopilot/pay_ui/tests/mock_server.py'
232--- tests/autopilot/pay_ui/tests/mock_server.py 2015-02-12 18:15:25 +0000
233+++ tests/autopilot/pay_ui/tests/mock_server.py 2015-03-25 20:08:56 +0000
234@@ -22,7 +22,7 @@
235
236 html_success = """
237 <html>
238- <body bgcolor="green" onClick="window.location.assign('/click/succeeded')">
239+ <body bgcolor="green" onClick="window.location.assign('/paymentmethods/completeadd')">
240 <h1>Placeholder for web interaction</h1>
241 <p>Click anywhere to proceed</p>
242 </body>
243@@ -38,6 +38,80 @@
244 </html>"
245 """
246
247+html_completed = """
248+<html>
249+ <body onLoad="window.location.assign('/click/succeeded')">
250+ </body>
251+</html>
252+"""
253+
254+html_beforeunload = """
255+<html>
256+ <script language="javascript">
257+ window.onbeforeunload = function() {
258+ return 'Really want to add your card?'
259+ }
260+ window.onload = function() {
261+ window.location.assign('/click/cancelled')
262+ }
263+ window.onclick = function() {
264+ window.onbeforeunload = null;
265+ window.location.assign('/paymentmethods/completeadd')
266+ }
267+ </script>
268+ <body bgcolor="yellow">
269+ <h1>Placeholder for web interaction</h1>
270+ <p>Click 'Stay' and then anywhere to proceed.</p>
271+ </body>
272+</html>
273+"""
274+
275+html_alert = """
276+<html>
277+ <body onClick="window.location.assign('/paymentmethods/completeadd')"
278+ onLoad="alert('Click OK to add your card.')">
279+ <h1>Placeholder for web interaction</h1>
280+ <p>Click anywhere to proceed</p>
281+ </body>
282+</html>
283+"""
284+
285+html_confirm = """
286+<html>
287+ <script language="javascript">
288+ window.onload = function() {
289+ if (window.confirm('Do you want to add your card?')) {
290+ window.location.assign('/paymentmethods/completeadd')
291+ } else {
292+ window.location.assign('/click/cancelled')
293+ }
294+ }
295+ </script>
296+ <body bgcolor="pink">
297+ <h1>Placeholder for web interaction</h1>
298+ <p>Click ok to add card, or cancel to not.</p>
299+ </body>
300+</html>
301+"""
302+
303+html_prompt = """
304+<html>
305+ <script language="javascript">
306+ window.onload = function() {
307+ if (window.prompt('Speak friend and enter') == 'friend') {
308+ window.location.assign('/paymentmethods/completeadd')
309+ } else {
310+ window.location.assign('/click/cancelled')
311+ }
312+ }
313+ </script>
314+ <body bgcolor="pink">
315+ <h1>Placeholder for web interaction</h1>
316+ <p>Type friend and ok to add card.</p>
317+ </body>
318+</html>
319+"""
320+
321
322 class MyHandler(BaseHTTPRequestHandler):
323
324@@ -72,17 +146,33 @@
325 self.send_response(404)
326 else:
327 self.send_response(200)
328- if not self.server.interaction_cancel:
329- self.server.payment_types[1]["choices"].append({
330- "currencies": ["USD"],
331- "id": 1999,
332- "requires_interaction": False,
333- "preferred": False,
334- "description": "Yet another payment method"
335- })
336- self.send_header("Content-type", "text/html")
337- self.end_headers()
338- self.wfile.write(bytes(self.interaction_html(), 'UTF-8'))
339+ self.send_header("Content-type", "text/html")
340+ self.end_headers()
341+ test = self.path.split('/')[1]
342+ if test.find('js_alert') != -1:
343+ self.wrile.write(bytes(html_alert, 'UTF-8'))
344+ elif test.find('js_beforeunload') != -1:
345+ self.wfile.write(bytes(html_beforeunload, 'UTF-8'))
346+ elif test.find('js_confirm') != -1:
347+ self.wfile.write(bytes(html_confirm, 'UTF-8'))
348+ elif test.find('js_prompt') != -1:
349+ self.wfile.write(bytes(html_prompt, 'UTF-8'))
350+ else:
351+ self.wfile.write(bytes(self.interaction_html(), 'UTF-8'))
352+
353+ def response_payment_add_complete(self):
354+ """Add the new payment info to the list."""
355+ self.server.payment_types[1]["choices"].append({
356+ "currencies": ["USD"],
357+ "id": 1999,
358+ "requires_interaction": False,
359+ "preferred": False,
360+ "description": "Yet another payment method"
361+ })
362+ self.send_response(200)
363+ self.send_header("Content-type", "text/html")
364+ self.end_headers()
365+ self.wfile.write(bytes(html_completed, 'UTF-8'))
366
367 def response_buy_item(self):
368 response = {
369@@ -153,6 +243,8 @@
370 fail = self.path.find("/fail/") != -1
371 if self.path.find("paymentmethods/add/") != -1:
372 self.response_payment_add()
373+ elif self.path.find("paymentmethods/completeadd") != -1:
374+ self.response_payment_add_complete()
375 elif self.path.find("paymentmethods/") != -1:
376 self.response_payment_types(fail)
377 elif self.path.find("creditcard_interaction/") != -1:
378
379=== modified file 'tests/autopilot/pay_ui/tests/test_pay_ui.py'
380--- tests/autopilot/pay_ui/tests/test_pay_ui.py 2015-02-12 18:15:25 +0000
381+++ tests/autopilot/pay_ui/tests/test_pay_ui.py 2015-03-25 20:08:56 +0000
382@@ -15,7 +15,9 @@
383 # along with this program. If not, see <http://www.gnu.org/licenses/>.
384
385 import fixtures
386+import testtools
387 import ubuntuuitoolkit
388+
389 from testtools.matchers import Equals, NotEquals
390 from autopilot.matchers import Eventually
391
392@@ -30,7 +32,8 @@
393 self.mock_server = mock_server.MockServer()
394 self.addCleanup(self.mock_server.shutdown)
395 self.useFixture(fixtures.EnvironmentVariable(
396- 'PAY_BASE_URL', self.mock_server.url()))
397+ 'PAY_BASE_URL',
398+ self.mock_server.url() + '/' + self.id().split('.')[-1]))
399 self.useFixture(fixtures.EnvironmentVariable(
400 'U1_SEARCH_BASE_URL', self.mock_server.url('iteminfo/')))
401 self.useFixture(fixtures.EnvironmentVariable('GET_CREDENTIALS', '0'))
402@@ -41,12 +44,12 @@
403 return self.app.process.wait(timeout=30)
404
405 def tap(self, objectName):
406- item = self.main_view.select_single(objectName=objectName)
407+ item = self.main_view.wait_select_single(objectName=objectName)
408 self.assertThat(item.enabled, Equals(True))
409 self.main_view.pointing_device.click_object(item)
410
411 def type_text(self, objectName, text):
412- item = self.main_view.select_single(
413+ item = self.main_view.wait_select_single(
414 ubuntuuitoolkit.TextField, objectName=objectName)
415 item.write(text)
416
417@@ -68,6 +71,7 @@
418 payment_types = self.main_view.select_single(objectName="paymentTypes")
419 self.assertThat(payment_types.get_option_count(), Equals(3))
420 self.tap('addCreditCardLabel')
421+ self.take_screenshot('add_card_page')
422 self.tap('webView')
423 self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
424
425@@ -76,7 +80,97 @@
426 payment_types = self.main_view.select_single(objectName="paymentTypes")
427 self.assertThat(payment_types.get_option_count(), Equals(3))
428 self.tap('addCreditCardLabel')
429- self.tap('webView')
430+ self.take_screenshot('add_card_page')
431+ self.tap('webView')
432+ self.assertThat(payment_types.get_option_count, Eventually(Equals(3)))
433+
434+ @testtools.skip('JS Alert dialog seems to not work.')
435+ def test_add_credit_card_js_alert(self):
436+ payment_types = self.main_view.select_single(objectName="paymentTypes")
437+ self.assertThat(payment_types.get_option_count(), Equals(3))
438+ self.tap('addCreditCardLabel')
439+ self.take_screenshot('add_card_page')
440+ self.tap('dialogOkbutton')
441+ self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
442+
443+ def test_add_credit_card_js_beforeunload(self):
444+ payment_types = self.main_view.select_single(objectName="paymentTypes")
445+ self.assertThat(payment_types.get_option_count(), Equals(3))
446+ self.tap('addCreditCardLabel')
447+ self.take_screenshot('add_card_page')
448+ self.tap('stayButton')
449+ self.tap('webView')
450+ self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
451+
452+ @testtools.skip('Clicking add card link second seems to not work.')
453+ def test_add_credit_card_js_beforeunload_twice(self):
454+ payment_types = self.main_view.select_single(objectName="paymentTypes")
455+ self.assertThat(payment_types.get_option_count(), Equals(3))
456+ self.tap('addCreditCardLabel')
457+ self.take_screenshot('add_card_page')
458+ dialog = self.main_view.wait_select_single(
459+ objectName="beforeUnloadDialog")
460+ self.tap('leaveButton')
461+ dialog.wait_until_destroyed()
462+ self.take_screenshot('beforeunload_left')
463+ self.tap('addCreditCardLabel')
464+ dialog = self.main_view.wait_select_single(
465+ objectName="beforeUnloadDialog")
466+ self.take_screenshot('beforeunload_back')
467+ self.tap('stayButton')
468+ dialog.wait_until_destroyed()
469+ self.tap('webView')
470+ self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
471+
472+ def test_add_credit_card_js_beforeunload_cancelled(self):
473+ payment_types = self.main_view.select_single(objectName="paymentTypes")
474+ self.assertThat(payment_types.get_option_count(), Equals(3))
475+ self.tap('addCreditCardLabel')
476+ self.take_screenshot('add_card_page')
477+ self.tap('leaveButton')
478+ self.take_screenshot('beforeunload_cancelled')
479+ self.assertThat(payment_types.get_option_count, Eventually(Equals(3)))
480+
481+ def test_add_credit_card_js_confirm_ok(self):
482+ payment_types = self.main_view.select_single(objectName="paymentTypes")
483+ self.assertThat(payment_types.get_option_count(), Equals(3))
484+ self.tap('addCreditCardLabel')
485+ self.take_screenshot('add_card_page')
486+ self.tap('dialogOkButton')
487+ self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
488+
489+ def test_add_credit_card_js_confirm_cancel(self):
490+ payment_types = self.main_view.select_single(objectName="paymentTypes")
491+ self.assertThat(payment_types.get_option_count(), Equals(3))
492+ self.tap('addCreditCardLabel')
493+ self.take_screenshot('add_card_page')
494+ self.tap('dialogCancelButton')
495+ self.assertThat(payment_types.get_option_count, Eventually(Equals(3)))
496+
497+ def test_add_credit_card_js_prompt_ok(self):
498+ payment_types = self.main_view.select_single(objectName="paymentTypes")
499+ self.assertThat(payment_types.get_option_count(), Equals(3))
500+ self.tap('addCreditCardLabel')
501+ self.take_screenshot('add_card_page')
502+ self.type_text('dialogInput', 'friend')
503+ self.tap('dialogOkButton')
504+ self.assertThat(payment_types.get_option_count, Eventually(Equals(4)))
505+
506+ def test_add_credit_card_js_prompt_ok_wrong_text(self):
507+ payment_types = self.main_view.select_single(objectName="paymentTypes")
508+ self.assertThat(payment_types.get_option_count(), Equals(3))
509+ self.tap('addCreditCardLabel')
510+ self.take_screenshot('add_card_page')
511+ self.type_text('dialogInput', 'amigo')
512+ self.tap('dialogOkButton')
513+ self.assertThat(payment_types.get_option_count, Eventually(Equals(3)))
514+
515+ def test_add_credit_card_js_prompt_cancel(self):
516+ payment_types = self.main_view.select_single(objectName="paymentTypes")
517+ self.assertThat(payment_types.get_option_count(), Equals(3))
518+ self.tap('addCreditCardLabel')
519+ self.take_screenshot('add_card_page')
520+ self.tap('dialogCancelButton')
521 self.assertThat(payment_types.get_option_count, Eventually(Equals(3)))
522
523 def test_purchase_with_web_interaction_completed(self):

Subscribers

People subscribed via source and target branches

to all changes: