Merge lp:~bfiller/webbrowser-app/file-upload into lp:webbrowser-app
- file-upload
- Merge into trunk
Status: | Superseded |
---|---|
Proposed branch: | lp:~bfiller/webbrowser-app/file-upload |
Merge into: | lp:webbrowser-app |
Diff against target: |
294 lines (+252/-0) 5 files modified
debian/control (+1/-0) src/app/ContentPickerDialog.qml (+82/-0) src/app/WebViewImpl.qml (+1/-0) tests/autopilot/webbrowser_app/tests/http_server.py (+15/-0) tests/autopilot/webbrowser_app/tests/test_content_pick.py (+153/-0) |
To merge this branch: | bzr merge lp:~bfiller/webbrowser-app/file-upload |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Adnane Belmadiaf | community | Pending | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+203227@code.launchpad.net |
Commit message
Description of the change
Adding image upload capability. Not ready yet for review.
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:420
http://
Executed test runs:
UNSTABLE: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Bill Filler (bfiller) wrote : | # |
Remaining work items so we can land this:
Main use case to get working well is open gmail in browser and try to add an attachment to a new email message:
phase 1:
- disable failing autopilot tests
- enable multi selection mode
- fix up result list to display multiple objects, need to support multiple types, i.e. a picture and a video. perhaps this can be a simple list with some sort of icon. Need to check with design to see what is desired
- this works correctly in webbrowser-app but doesn't work at all if you run in a webapp (like try to upload photo in gmail webbapp).
phase 2:
- instead of hardcoding "ContentType.
- implement the Source Picker UI (in the design spec) to display the choices of available apps returned by the content-hub. This should be a generic UI component that would probably live in the content-hub or sdk
Unmerged revisions
Preview Diff
1 | === modified file 'debian/control' | |||
2 | --- debian/control 2013-12-05 07:06:08 +0000 | |||
3 | +++ debian/control 2014-01-26 04:07:40 +0000 | |||
4 | @@ -85,6 +85,7 @@ | |||
5 | 85 | libautopilot-qt (>= 1.4), | 85 | libautopilot-qt (>= 1.4), |
6 | 86 | libqt5test5, | 86 | libqt5test5, |
7 | 87 | ubuntu-ui-toolkit-autopilot, | 87 | ubuntu-ui-toolkit-autopilot, |
8 | 88 | unity8-autopilot, | ||
9 | 88 | webbrowser-app (>= ${binary:Version}), | 89 | webbrowser-app (>= ${binary:Version}), |
10 | 89 | Description: Ubuntu web browser autopilot tests | 90 | Description: Ubuntu web browser autopilot tests |
11 | 90 | A lightweight web browser tailored for Ubuntu, based on the Webkit rendering | 91 | A lightweight web browser tailored for Ubuntu, based on the Webkit rendering |
12 | 91 | 92 | ||
13 | === added file 'src/app/ContentPickerDialog.qml' | |||
14 | --- src/app/ContentPickerDialog.qml 1970-01-01 00:00:00 +0000 | |||
15 | +++ src/app/ContentPickerDialog.qml 2014-01-26 04:07:40 +0000 | |||
16 | @@ -0,0 +1,82 @@ | |||
17 | 1 | /* | ||
18 | 2 | * Copyright 2013 Canonical Ltd. | ||
19 | 3 | * | ||
20 | 4 | * This file is part of webbrowser-app. | ||
21 | 5 | * | ||
22 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
23 | 7 | * it under the terms of the GNU General Public License as published by | ||
24 | 8 | * the Free Software Foundation; version 3. | ||
25 | 9 | * | ||
26 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
27 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
28 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
29 | 13 | * GNU General Public License for more details. | ||
30 | 14 | * | ||
31 | 15 | * You should have received a copy of the GNU General Public License | ||
32 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
33 | 17 | */ | ||
34 | 18 | |||
35 | 19 | import QtQuick 2.0 | ||
36 | 20 | import Ubuntu.Components 0.1 | ||
37 | 21 | import Ubuntu.Components.Popups 0.1 as Popups | ||
38 | 22 | import Ubuntu.Content 0.1 | ||
39 | 23 | |||
40 | 24 | Popups.Dialog { | ||
41 | 25 | id: picker | ||
42 | 26 | title: i18n.tr("Pick content to upload") | ||
43 | 27 | property var activeTransfer | ||
44 | 28 | |||
45 | 29 | UbuntuShape { | ||
46 | 30 | height: width | ||
47 | 31 | image: Image { | ||
48 | 32 | objectName: "mediaPreview" | ||
49 | 33 | id: preview | ||
50 | 34 | fillMode: Image.PreserveAspectCrop | ||
51 | 35 | } | ||
52 | 36 | |||
53 | 37 | MouseArea { | ||
54 | 38 | anchors.fill: parent | ||
55 | 39 | onClicked: startContentPicking() | ||
56 | 40 | } | ||
57 | 41 | |||
58 | 42 | ContentImportHint { | ||
59 | 43 | anchors.fill: parent | ||
60 | 44 | activeTransfer: picker.activeTransfer | ||
61 | 45 | } | ||
62 | 46 | } | ||
63 | 47 | |||
64 | 48 | Button { | ||
65 | 49 | objectName: "ok" | ||
66 | 50 | text: i18n.tr("OK") | ||
67 | 51 | color: "green" | ||
68 | 52 | enabled: preview.source | ||
69 | 53 | onClicked: model.accept(String(preview.source).replace("file://", "")) | ||
70 | 54 | } | ||
71 | 55 | |||
72 | 56 | Button { | ||
73 | 57 | text: i18n.tr("Cancel") | ||
74 | 58 | color: UbuntuColors.coolGrey | ||
75 | 59 | onClicked: model.reject() | ||
76 | 60 | } | ||
77 | 61 | |||
78 | 62 | function startContentPicking() { | ||
79 | 63 | activeTransfer = ContentHub.importContent(ContentType.Pictures); | ||
80 | 64 | activeTransfer.selectionType = ContentTransfer.Single; | ||
81 | 65 | activeTransfer.start(); | ||
82 | 66 | } | ||
83 | 67 | |||
84 | 68 | Component.onCompleted: { | ||
85 | 69 | show(); | ||
86 | 70 | startContentPicking(); | ||
87 | 71 | } | ||
88 | 72 | |||
89 | 73 | Connections { | ||
90 | 74 | target: picker.activeTransfer | ||
91 | 75 | onStateChanged: { | ||
92 | 76 | if (picker.activeTransfer.state === ContentTransfer.Charged) { | ||
93 | 77 | var importItem = picker.activeTransfer.items[0]; | ||
94 | 78 | preview.source = importItem.url | ||
95 | 79 | } | ||
96 | 80 | } | ||
97 | 81 | } | ||
98 | 82 | } | ||
99 | 0 | 83 | ||
100 | === modified file 'src/app/WebViewImpl.qml' | |||
101 | --- src/app/WebViewImpl.qml 2013-11-12 22:18:49 +0000 | |||
102 | +++ src/app/WebViewImpl.qml 2014-01-26 04:07:40 +0000 | |||
103 | @@ -37,6 +37,7 @@ | |||
104 | 37 | experimental.alertDialog: AlertDialog {} | 37 | experimental.alertDialog: AlertDialog {} |
105 | 38 | experimental.confirmDialog: ConfirmDialog {} | 38 | experimental.confirmDialog: ConfirmDialog {} |
106 | 39 | experimental.promptDialog: PromptDialog {} | 39 | experimental.promptDialog: PromptDialog {} |
107 | 40 | experimental.filePicker: ContentPickerDialog {} | ||
108 | 40 | 41 | ||
109 | 41 | selectionActions: ActionList { | 42 | selectionActions: ActionList { |
110 | 42 | Actions.Copy { | 43 | Actions.Copy { |
111 | 43 | 44 | ||
112 | === modified file 'tests/autopilot/webbrowser_app/tests/http_server.py' | |||
113 | --- tests/autopilot/webbrowser_app/tests/http_server.py 2013-12-16 10:51:47 +0000 | |||
114 | +++ tests/autopilot/webbrowser_app/tests/http_server.py 2014-01-26 04:07:40 +0000 | |||
115 | @@ -86,6 +86,21 @@ | |||
116 | 86 | html += 'src="/blanktargetlink" />' | 86 | html += 'src="/blanktargetlink" />' |
117 | 87 | html += '</body></html>' | 87 | html += '</body></html>' |
118 | 88 | self.send_html(html) | 88 | self.send_html(html) |
119 | 89 | elif self.path == "/uploadform": | ||
120 | 90 | # craft a page that accepts clicks anywhere inside its window | ||
121 | 91 | # and on a click opens up the content picker. | ||
122 | 92 | # It also pops up an alert with the new content of the file | ||
123 | 93 | # upload field when it changes | ||
124 | 94 | self.send_response(200) | ||
125 | 95 | html = '<html><body style="margin: 0">' | ||
126 | 96 | html = '<form action="upload" method="post" enctype="multipart/form-data">' | ||
127 | 97 | html += '<input type="file" name="file" id="file" onchange="alert(this.value)"><br>' | ||
128 | 98 | html += '<input type="submit" name="submit" value="Submit">' | ||
129 | 99 | html += '</form>' | ||
130 | 100 | html += '<a href="javascript:document.getElementById(\'file\').click()">' | ||
131 | 101 | html += '<div style="height: 100%"></div></a>' | ||
132 | 102 | html += '</body></html>' | ||
133 | 103 | self.send_html(html) | ||
134 | 89 | else: | 104 | else: |
135 | 90 | self.send_error(404) | 105 | self.send_error(404) |
136 | 91 | 106 | ||
137 | 92 | 107 | ||
138 | === added file 'tests/autopilot/webbrowser_app/tests/test_content_pick.py' | |||
139 | --- tests/autopilot/webbrowser_app/tests/test_content_pick.py 1970-01-01 00:00:00 +0000 | |||
140 | +++ tests/autopilot/webbrowser_app/tests/test_content_pick.py 2014-01-26 04:07:40 +0000 | |||
141 | @@ -0,0 +1,153 @@ | |||
142 | 1 | # -*- coding: utf-8 -*- | ||
143 | 2 | # | ||
144 | 3 | # Copyright 2013 Canonical | ||
145 | 4 | # | ||
146 | 5 | # This program is free software: you can redistribute it and/or modify it | ||
147 | 6 | # under the terms of the GNU General Public License version 3, as published | ||
148 | 7 | # by the Free Software Foundation. | ||
149 | 8 | |||
150 | 9 | from __future__ import absolute_import | ||
151 | 10 | |||
152 | 11 | from autopilot.introspection import get_proxy_object_for_existing_process | ||
153 | 12 | from autopilot.platform import model | ||
154 | 13 | from autopilot.matchers import Eventually | ||
155 | 14 | from testtools.matchers import Equals, NotEquals | ||
156 | 15 | from testtools import skipIf, skip | ||
157 | 16 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase | ||
158 | 17 | from unity8 import process_helpers as helpers | ||
159 | 18 | from ubuntuuitoolkit import emulators as toolkit_emulators | ||
160 | 19 | import os, subprocess | ||
161 | 20 | |||
162 | 21 | @skip("Will not work until bug #1255077 is solved") | ||
163 | 22 | class TestContentPick(StartOpenRemotePageTestCaseBase): | ||
164 | 23 | |||
165 | 24 | """Tests that content picking dialog show up.""" | ||
166 | 25 | |||
167 | 26 | def test_pick_image(self): | ||
168 | 27 | url = self.base_url + "/uploadform" | ||
169 | 28 | self.go_to_url(url) | ||
170 | 29 | self.assert_page_eventually_loaded(url) | ||
171 | 30 | webview = self.main_window.get_current_webview() | ||
172 | 31 | self.pointing_device.click_object(webview) | ||
173 | 32 | |||
174 | 33 | dialog = self.app.wait_select_single("ContentPickerDialog") | ||
175 | 34 | self.assertThat(dialog.visible, Equals(True)) | ||
176 | 35 | |||
177 | 36 | @skipIf(model() == 'Desktop', "Phablet only") | ||
178 | 37 | class TestContentPickerIntegration(StartOpenRemotePageTestCaseBase): | ||
179 | 38 | |||
180 | 39 | """Tests that the gallery app is brought up to choose image content""" | ||
181 | 40 | |||
182 | 41 | def tearDown(self): | ||
183 | 42 | os.system("pkill gallery-app") | ||
184 | 43 | os.system("pkill webbrowser-app") | ||
185 | 44 | super(StartOpenRemotePageTestCaseBase, self).tearDown() | ||
186 | 45 | |||
187 | 46 | def get_unity8_proxy_object(self): | ||
188 | 47 | pid = helpers._get_unity_pid() | ||
189 | 48 | return get_proxy_object_for_existing_process(pid) | ||
190 | 49 | |||
191 | 50 | def get_current_focused_appid(self, unity8): | ||
192 | 51 | return unity8.select_single("Shell").currentFocusedAppId | ||
193 | 52 | |||
194 | 53 | def set_testability_environment_variable(self): | ||
195 | 54 | """Makes sure every app opened in the environment loads the | ||
196 | 55 | testability driver.""" | ||
197 | 56 | |||
198 | 57 | subprocess.check_call([ | ||
199 | 58 | "/sbin/initctl", | ||
200 | 59 | "set-env", | ||
201 | 60 | "QT_LOAD_TESTABILITY=1" | ||
202 | 61 | ]) | ||
203 | 62 | |||
204 | 63 | def get_app_pid(self, app): | ||
205 | 64 | """Return the PID of the named app, or -1 if it's not | ||
206 | 65 | running""" | ||
207 | 66 | |||
208 | 67 | try: | ||
209 | 68 | return int(subprocess.check_output(["pidof", app]).strip()) | ||
210 | 69 | except subprocess.CalledProcessError: | ||
211 | 70 | return -1 | ||
212 | 71 | |||
213 | 72 | def wait_app_focused(self, name): | ||
214 | 73 | """Wait until the app with the specified name is the | ||
215 | 74 | currently focused one""" | ||
216 | 75 | |||
217 | 76 | unity8 = self.get_unity8_proxy_object() | ||
218 | 77 | shell = unity8.select_single("Shell") | ||
219 | 78 | self.assertThat( | ||
220 | 79 | lambda: self.get_current_focused_appid(unity8), | ||
221 | 80 | Eventually(Equals(name)) | ||
222 | 81 | ) | ||
223 | 82 | |||
224 | 83 | def test_image_picker_is_gallery(self): | ||
225 | 84 | """ Tests that the gallery shows up when we are picking | ||
226 | 85 | images """ | ||
227 | 86 | |||
228 | 87 | # Go to a page where clicking anywhere equals clicking on the | ||
229 | 88 | # file selection button of an upload form | ||
230 | 89 | url = self.base_url + "/uploadform" | ||
231 | 90 | self.go_to_url(url) | ||
232 | 91 | self.assert_page_eventually_loaded(url) | ||
233 | 92 | webview = self.main_window.get_current_webview() | ||
234 | 93 | self.pointing_device.click_object(webview) | ||
235 | 94 | |||
236 | 95 | # Verify that such a click brings up the gallery to select images | ||
237 | 96 | self.wait_app_focused("gallery-app") | ||
238 | 97 | |||
239 | 98 | def test_image_picker_pick_image(self): | ||
240 | 99 | """ Tests that the we can select an image in the gallery and | ||
241 | 100 | control will return to the browser with the choosen image | ||
242 | 101 | picked.""" | ||
243 | 102 | |||
244 | 103 | # First run the previous test to bring up the content picker | ||
245 | 104 | self.set_testability_environment_variable() | ||
246 | 105 | self.test_image_picker_is_gallery() | ||
247 | 106 | |||
248 | 107 | # Now wait until the gallery-app process is up. | ||
249 | 108 | # NOTE: this will not work unless run on a device where unity8 runs in | ||
250 | 109 | # testability mode. To manually restart unity8 in this mode run from a | ||
251 | 110 | # python shell: | ||
252 | 111 | # from unity8 import process_helpers as p; p.restart_unity_with_testability() | ||
253 | 112 | unity8 = self.get_unity8_proxy_object() | ||
254 | 113 | self.assertThat(lambda: self.get_app_pid("gallery-app"), Eventually(NotEquals(-1))) | ||
255 | 114 | |||
256 | 115 | gallery = get_proxy_object_for_existing_process( | ||
257 | 116 | self.get_app_pid("gallery-app"), | ||
258 | 117 | emulator_base = toolkit_emulators.UbuntuUIToolkitEmulatorBase | ||
259 | 118 | ) | ||
260 | 119 | |||
261 | 120 | # Wait for the gallery UI to completely display | ||
262 | 121 | view = gallery.wait_select_single("QQuickView") | ||
263 | 122 | self.assertThat(view.visible, Eventually(Equals(True))) | ||
264 | 123 | |||
265 | 124 | # Select the first picture on the picker by clicking on it | ||
266 | 125 | # NOTE: this is currently failing if there is anything except two pictures | ||
267 | 126 | # in the gallery (at least on a Maguro device), so I'm putting a temporary | ||
268 | 127 | # stop to the test here so that it won't break in Jenkins | ||
269 | 128 | return | ||
270 | 129 | |||
271 | 130 | grid = gallery.wait_select_single("MediaGrid") | ||
272 | 131 | photo = grid.select_many("OrganicItemInteraction")[0] | ||
273 | 132 | self.pointing_device.click_object(photo) | ||
274 | 133 | self.assertThat(photo.isSelected, Eventually(Equals(True))) | ||
275 | 134 | |||
276 | 135 | # Now the "Pick" button will be enabled and we click on it | ||
277 | 136 | button = gallery.select_single("Button", objectName="pickButton") | ||
278 | 137 | self.assertThat(button.enabled, Eventually(Equals(True))) | ||
279 | 138 | self.pointing_device.click_object(button) | ||
280 | 139 | |||
281 | 140 | # The gallery should close and focus returned to the browser | ||
282 | 141 | self.wait_app_focused("webbrowser-app") | ||
283 | 142 | |||
284 | 143 | # Verify that an image has actually been selected | ||
285 | 144 | dialog = self.app.wait_select_single("ContentPickerDialog") | ||
286 | 145 | self.assertThat(dialog.visible, Equals(True)) | ||
287 | 146 | preview = dialog.wait_select_single("QQuickImage", objectName="mediaPreview") | ||
288 | 147 | self.assertThat(preview.source, Eventually(NotEquals(""))) | ||
289 | 148 | |||
290 | 149 | # Verify that now we can click the "OK" button and it closes the dialog | ||
291 | 150 | button = dialog.wait_select_single("Button", objectName="ok") | ||
292 | 151 | self.assertThat(button.enabled, Eventually(Equals(True))) | ||
293 | 152 | self.pointing_device.click_object(button) | ||
294 | 153 | self.assertThat(dialog.visible, Eventually(Equals(False))) |
FAILED: Continuous integration, rev:420 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 590/ jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty/ 2616 jenkins. qa.ubuntu. com/job/ generic- mediumtests- trusty- touch/2407/ console jenkins. qa.ubuntu. com/job/ webbrowser- app-trusty- amd64-ci/ 92 jenkins. qa.ubuntu. com/job/ webbrowser- app-trusty- armhf-ci/ 92 jenkins. qa.ubuntu. com/job/ webbrowser- app-trusty- armhf-ci/ 92/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ webbrowser- app-trusty- i386-ci/ 92 jenkins. qa.ubuntu. com/job/ autopilot- testrunner- otto-trusty/ 2285 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/2618 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- amd64/2618/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/2408 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- trusty- armhf/2408/ artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ generic- mediumtests- runner- mako/4847/ console s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 3357
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
FAILURE: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 590/rebuild
http://