Merge lp:~osomon/webbrowser-app/historyUpdateOnLoadCommitted into lp:webbrowser-app
- historyUpdateOnLoadCommitted
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Olivier Tilloy |
Approved revision: | 1029 |
Merged at revision: | 1372 |
Proposed branch: | lp:~osomon/webbrowser-app/historyUpdateOnLoadCommitted |
Merge into: | lp:webbrowser-app |
Diff against target: |
391 lines (+229/-40) 6 files modified
src/app/webbrowser/Browser.qml (+29/-2) src/app/webbrowser/history-model.cpp (+37/-1) src/app/webbrowser/history-model.h (+2/-1) tests/autopilot/webbrowser_app/tests/http_server.py (+32/-1) tests/autopilot/webbrowser_app/tests/test_history.py (+80/-34) tests/unittests/history-model/tst_HistoryModelTests.cpp (+49/-1) |
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/historyUpdateOnLoadCommitted |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Riccardo Padovani (community) | Approve | ||
PS Jenkins bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+259361@code.launchpad.net |
Commit message
Store entries in the history database on load committed, not load succeeded.
This ensures that content-initiated navigations are also stored.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1018
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Riccardo Padovani (rpadovani) wrote : | # |
+ browser.
Why this and not
browser.
?
I mean, we're updating the database, it's better to do it with last data we have, isn't it?
Olivier Tilloy (osomon) wrote : | # |
> + browser.
> webviewInternal
>
> Why this and not
>
> browser.
>
> ?
>
> I mean, we're updating the database, it's better to do it with last data we
> have, isn't it?
Some pages dynamically update the title to convey live information (like the ugly "scrolling title" effect, see e.g. http://
This is consistent with how chromium on desktop behaves.
Riccardo Padovani (rpadovani) wrote : | # |
Looks good to me now :-)
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1019
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1020
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1020
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1020
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
FAILURE: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1020
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1021. By Olivier Tilloy
-
Merge the latest changes from trunk and resolve conflicts.
- 1022. By Olivier Tilloy
-
Add an update(…) method to HistoryModel, to allow updating the title and icon of an entry without incrementing the corresponding number of visits.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1022
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1023. By Olivier Tilloy
-
Simplify code a bit.
Do not prevent dynamic favicon updates from updating the history database, to be consistent with what chromium does.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1023
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1024. By Olivier Tilloy
-
Add some autopilot tests to verify that favicons are stored and updated in the history database.
- 1025. By Olivier Tilloy
-
Factor out common code.
- 1026. By Olivier Tilloy
-
Add autopilot tests to verify that a page’s title is stored in history, but not dynamically updated.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1025
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 1027. By Olivier Tilloy
-
Add an autopilot test to verify that history.pushState() inserts a new entry in the history database.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1026
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1027
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Riccardo Padovani (rpadovani) wrote : | # |
I only read the code and seems good to me, just a couple of very little improvements inline.
I'll test asap.
- 1028. By Olivier Tilloy
-
Swap the order in which conditions are evaluated, from cheapest to most expensive.
- 1029. By Olivier Tilloy
-
Move code out of else block to avoid compiler warning (control reaches end of non-void function [-Wreturn-type]).
Olivier Tilloy (osomon) wrote : | # |
Thanks, those were very good points, I addressed them.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1029
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Riccardo Padovani (rpadovani) wrote : | # |
Thanks! Tested a bit and seems to work like a charm.
Preview Diff
1 | === modified file 'src/app/webbrowser/Browser.qml' |
2 | --- src/app/webbrowser/Browser.qml 2016-02-23 11:24:33 +0000 |
3 | +++ src/app/webbrowser/Browser.qml 2016-03-01 09:31:14 +0000 |
4 | @@ -1263,20 +1263,47 @@ |
5 | } |
6 | } |
7 | |
8 | + QtObject { |
9 | + id: webviewInternal |
10 | + property url storedUrl: "" |
11 | + property bool titleSet: false |
12 | + property string title: "" |
13 | + } |
14 | onLoadEvent: { |
15 | if (event.type == Oxide.LoadEvent.TypeCommitted) { |
16 | chrome.findInPageMode = false |
17 | + webviewInternal.titleSet = false |
18 | + webviewInternal.title = title |
19 | } |
20 | |
21 | if (webviewimpl.incognito) { |
22 | return |
23 | } |
24 | |
25 | - if (event.type == Oxide.LoadEvent.TypeSucceeded && |
26 | - 300 > event.httpStatusCode && event.httpStatusCode >= 200) { |
27 | + if ((event.type == Oxide.LoadEvent.TypeCommitted) && |
28 | + !event.isError && |
29 | + (300 > event.httpStatusCode) && (event.httpStatusCode >= 200)) { |
30 | + webviewInternal.storedUrl = event.url |
31 | HistoryModel.add(event.url, title, icon) |
32 | } |
33 | } |
34 | + onTitleChanged: { |
35 | + if (!webviewInternal.titleSet && webviewInternal.storedUrl.toString()) { |
36 | + // Record the title to avoid updating the history database |
37 | + // every time the page dynamically updates its title. |
38 | + // We don’t want pages that update their title every second |
39 | + // to achieve an ugly "scrolling title" effect to flood the |
40 | + // history database with updates. |
41 | + webviewInternal.titleSet = true |
42 | + webviewInternal.title = title |
43 | + HistoryModel.update(webviewInternal.storedUrl, title, icon) |
44 | + } |
45 | + } |
46 | + onIconChanged: { |
47 | + if (webviewInternal.storedUrl.toString()) { |
48 | + HistoryModel.update(webviewInternal.storedUrl, webviewInternal.title, icon) |
49 | + } |
50 | + } |
51 | |
52 | onGeolocationPermissionRequested: requestGeolocationPermission(request) |
53 | |
54 | |
55 | === modified file 'src/app/webbrowser/history-model.cpp' |
56 | --- src/app/webbrowser/history-model.cpp 2015-10-07 11:10:14 +0000 |
57 | +++ src/app/webbrowser/history-model.cpp 2016-03-01 09:31:14 +0000 |
58 | @@ -1,5 +1,5 @@ |
59 | /* |
60 | - * Copyright 2013-2015 Canonical Ltd. |
61 | + * Copyright 2013-2016 Canonical Ltd. |
62 | * |
63 | * This file is part of webbrowser-app. |
64 | * |
65 | @@ -301,6 +301,42 @@ |
66 | } |
67 | |
68 | /*! |
69 | + Update an existing entry in the model. |
70 | + |
71 | + If no entry with the same URL exists yet, do nothing (and return false). |
72 | + Otherwise the title and icon of the existing entry are updated (the number |
73 | + of visits remains unchanged). |
74 | + |
75 | + Return true if an update actually happened, false otherwise. |
76 | +*/ |
77 | +bool HistoryModel::update(const QUrl& url, const QString& title, const QUrl& icon) |
78 | +{ |
79 | + if (url.isEmpty()) { |
80 | + return false; |
81 | + } |
82 | + int index = getEntryIndex(url); |
83 | + if (index == -1) { |
84 | + return false; |
85 | + } |
86 | + QVector<int> roles; |
87 | + const HistoryEntry& entry = m_entries.at(index); |
88 | + if (title != entry.title) { |
89 | + m_entries[index].title = title; |
90 | + roles << Title; |
91 | + } |
92 | + if (icon != entry.icon) { |
93 | + m_entries[index].icon = icon; |
94 | + roles << Icon; |
95 | + } |
96 | + if (roles.isEmpty()) { |
97 | + return false; |
98 | + } |
99 | + Q_EMIT dataChanged(this->index(index, 0), this->index(index, 0), roles); |
100 | + updateExistingEntryInDatabase(entry); |
101 | + return true; |
102 | +} |
103 | + |
104 | +/*! |
105 | Remove a given URL from the history model. |
106 | |
107 | If the URL was not previously visited, do nothing. |
108 | |
109 | === modified file 'src/app/webbrowser/history-model.h' |
110 | --- src/app/webbrowser/history-model.h 2015-10-07 11:10:14 +0000 |
111 | +++ src/app/webbrowser/history-model.h 2016-03-01 09:31:14 +0000 |
112 | @@ -1,5 +1,5 @@ |
113 | /* |
114 | - * Copyright 2013-2015 Canonical Ltd. |
115 | + * Copyright 2013-2016 Canonical Ltd. |
116 | * |
117 | * This file is part of webbrowser-app. |
118 | * |
119 | @@ -62,6 +62,7 @@ |
120 | void setDatabasePath(const QString& path); |
121 | |
122 | Q_INVOKABLE int add(const QUrl& url, const QString& title, const QUrl& icon); |
123 | + Q_INVOKABLE bool update(const QUrl& url, const QString& title, const QUrl& icon); |
124 | Q_INVOKABLE void removeEntryByUrl(const QUrl& url); |
125 | Q_INVOKABLE void removeEntriesByDate(const QDate& date); |
126 | Q_INVOKABLE void removeEntriesByDomain(const QString& domain); |
127 | |
128 | === modified file 'tests/autopilot/webbrowser_app/tests/http_server.py' |
129 | --- tests/autopilot/webbrowser_app/tests/http_server.py 2015-10-26 11:09:25 +0000 |
130 | +++ tests/autopilot/webbrowser_app/tests/http_server.py 2016-03-01 09:31:14 +0000 |
131 | @@ -1,6 +1,6 @@ |
132 | # -*- coding: utf-8 -*- |
133 | # |
134 | -# Copyright 2013-2015 Canonical |
135 | +# Copyright 2013-2016 Canonical |
136 | # |
137 | # This program is free software: you can redistribute it and/or modify it |
138 | # under the terms of the GNU General Public License version 3, as published |
139 | @@ -215,6 +215,37 @@ |
140 | "}, function() { location.href = '/test1' } " + |
141 | ", function() { location.href = '/test2' })</script>" |
142 | ) |
143 | + elif self.path == "/favicon": |
144 | + self.send_response(200) |
145 | + html = '<html><head><link rel="icon" type="image/png" ' |
146 | + html += 'href="/assets/icon1.png"></head>' |
147 | + html += '<body>favicon</body></html>' |
148 | + self.send_html(html) |
149 | + elif self.path == "/changingfavicon": |
150 | + self.send_response(200) |
151 | + html = '<html><head><link id="favicon" rel="shortcut icon" ' |
152 | + html += 'type="image/png" href="icon0.png"></head><body><script>' |
153 | + html += 'var i = 0; window.setInterval(function() {' |
154 | + html += 'document.getElementById("favicon").href = ++i + ' |
155 | + html += '".png"; }, 1000);</script></body></html>' |
156 | + self.send_html(html) |
157 | + elif self.path == "/changingtitle": |
158 | + self.send_response(200) |
159 | + html = '<html><head><title>title0</title></head><body><script>' |
160 | + html += 'var i = 0; window.setInterval(function() { ' |
161 | + html += 'document.title = "title" + ++i; }, 500);</script></body>' |
162 | + html += '</html>' |
163 | + self.send_html(html) |
164 | + elif self.path == "/pushstate": |
165 | + self.send_response(200) |
166 | + html = '<html><head><title>push state</title></head>' |
167 | + html += '<body style="margin: 0"><a id="link">' |
168 | + html += '<div style="height: 100%"></div></a><script>' |
169 | + html += 'document.getElementById("link").addEventListener("click",' |
170 | + html += ' function(e) { document.title = "state pushed"; ' |
171 | + html += 'history.pushState(null, null, "/statepushed"); });' |
172 | + html += '</script></body></html>' |
173 | + self.send_html(html) |
174 | else: |
175 | self.send_error(404) |
176 | |
177 | |
178 | === modified file 'tests/autopilot/webbrowser_app/tests/test_history.py' |
179 | --- tests/autopilot/webbrowser_app/tests/test_history.py 2015-11-23 10:25:26 +0000 |
180 | +++ tests/autopilot/webbrowser_app/tests/test_history.py 2016-03-01 09:31:14 +0000 |
181 | @@ -1,6 +1,6 @@ |
182 | # -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*- |
183 | # |
184 | -# Copyright 2015 Canonical |
185 | +# Copyright 2015-2016 Canonical |
186 | # |
187 | # This program is free software: you can redistribute it and/or modify it |
188 | # under the terms of the GNU General Public License version 3, as published |
189 | @@ -16,7 +16,7 @@ |
190 | |
191 | import time |
192 | |
193 | -from testtools.matchers import Equals |
194 | +from testtools.matchers import EndsWith, Equals, StartsWith |
195 | from autopilot.matchers import Eventually |
196 | |
197 | from webbrowser_app.tests import StartOpenRemotePageTestCaseBase |
198 | @@ -24,45 +24,36 @@ |
199 | |
200 | class TestHistory(StartOpenRemotePageTestCaseBase): |
201 | |
202 | - def test_history_not_save_404(self): |
203 | - url = self.base_url + "/404page" |
204 | - self.main_window.go_to_url(url) |
205 | - self.main_window.wait_until_page_loaded(url) |
206 | - |
207 | - # A valid url to be sure the fact the 404 page isn't present in the |
208 | - # history view isn't a timing issue. |
209 | - url = self.base_url + "/test2" |
210 | - self.main_window.go_to_url(url) |
211 | - self.main_window.wait_until_page_loaded(url) |
212 | - |
213 | - history = self.open_history() |
214 | - |
215 | - # We have domains with subsections only on mobiles. |
216 | - # On wide we take all the entries directly |
217 | + def expect_history_entries(self, ordered_urls): |
218 | + history = self.main_window.get_history_view() |
219 | if self.main_window.wide: |
220 | - delegates = history.get_entries() |
221 | - |
222 | - # 2 addresses: /test1 and /test2 |
223 | self.assertThat(lambda: len(history.get_entries()), |
224 | - Eventually(Equals(2))) |
225 | - self.assertThat(sorted([delegate.url for delegate in delegates]), |
226 | - Equals(sorted([self.url, url]))) |
227 | + Eventually(Equals(len(ordered_urls)))) |
228 | + entries = history.get_entries() |
229 | else: |
230 | - # 1 domain: the local one |
231 | - domain_entries = history.get_domain_entries() |
232 | self.assertThat(lambda: len(history.get_domain_entries()), |
233 | Eventually(Equals(1))) |
234 | - |
235 | - self.pointing_device.click_object(domain_entries[0]) |
236 | + self.pointing_device.click_object(history.get_domain_entries()[0]) |
237 | expanded_history = self.main_window.get_expanded_history_view() |
238 | - |
239 | - # 2 addresses: /test1 and /test2 |
240 | self.assertThat(lambda: len(expanded_history.get_entries()), |
241 | - Eventually(Equals(2))) |
242 | - |
243 | - delegates = expanded_history.get_entries() |
244 | - self.assertThat(sorted([delegate.url for delegate in delegates]), |
245 | - Equals(sorted([self.url, url]))) |
246 | + Eventually(Equals(len(ordered_urls)))) |
247 | + entries = expanded_history.get_entries() |
248 | + self.assertThat([entry.url for entry in entries], Equals(ordered_urls)) |
249 | + return entries |
250 | + |
251 | + def test_404_not_saved(self): |
252 | + url = self.base_url + "/notfound" |
253 | + self.main_window.go_to_url(url) |
254 | + self.main_window.wait_until_page_loaded(url) |
255 | + |
256 | + # A valid url to be sure the fact the 404 page isn't present in the |
257 | + # history view isn't a timing issue. |
258 | + url = self.base_url + "/test2" |
259 | + self.main_window.go_to_url(url) |
260 | + self.main_window.wait_until_page_loaded(url) |
261 | + |
262 | + self.open_history() |
263 | + self.expect_history_entries([url, self.url]) |
264 | |
265 | def test_expanded_history_view_header_swallows_clicks(self): |
266 | # Regression test for https://launchpad.net/bugs/1518904 |
267 | @@ -78,3 +69,58 @@ |
268 | # There should be only one instance on the expanded history view. |
269 | # If there’s more, the following call will raise an exception. |
270 | self.main_window.get_expanded_history_view() |
271 | + |
272 | + def test_favicon_saved(self): |
273 | + # Regression test for https://launchpad.net/bugs/1549780 |
274 | + url = self.base_url + "/favicon" |
275 | + self.main_window.go_to_url(url) |
276 | + self.main_window.wait_until_page_loaded(url) |
277 | + self.open_history() |
278 | + first = self.expect_history_entries([url, self.url])[0] |
279 | + self.assertThat(first.url, Equals(url)) |
280 | + favicon = self.base_url + "/assets/icon1.png" |
281 | + self.assertThat(first.icon, Equals(favicon)) |
282 | + |
283 | + def test_favicon_updated(self): |
284 | + # Verify that a page dynamically updating its favicon |
285 | + # triggers an update in the history database. |
286 | + url = self.base_url + "/changingfavicon" |
287 | + self.main_window.go_to_url(url) |
288 | + self.main_window.wait_until_page_loaded(url) |
289 | + self.open_history() |
290 | + first = self.expect_history_entries([url, self.url])[0] |
291 | + indexes = set() |
292 | + while len(indexes) < 3: |
293 | + self.assertThat(first.url, Equals(url)) |
294 | + icon = first.icon |
295 | + self.assertThat(icon, StartsWith(self.base_url)) |
296 | + self.assertThat(icon, EndsWith(".png")) |
297 | + indexes.add(int(first.icon[(len(self.base_url)+1):-4])) |
298 | + |
299 | + def test_title_saved(self): |
300 | + self.open_history() |
301 | + entry = self.expect_history_entries([self.url])[0] |
302 | + self.assertThat(entry.title, Equals("test page 1")) |
303 | + |
304 | + def test_title_not_updated(self): |
305 | + # Verify that a page dynamically updating its title |
306 | + # does NOT trigger an update in the history database. |
307 | + url = self.base_url + "/changingtitle" |
308 | + self.main_window.go_to_url(url) |
309 | + self.main_window.wait_until_page_loaded(url) |
310 | + self.open_history() |
311 | + first = self.expect_history_entries([url, self.url])[0] |
312 | + for i in range(10): |
313 | + self.assertThat(first.title, Equals("title0")) |
314 | + time.sleep(0.5) |
315 | + |
316 | + def test_pushstate_updates_history(self): |
317 | + url = self.base_url + "/pushstate" |
318 | + self.main_window.go_to_url(url) |
319 | + self.main_window.wait_until_page_loaded(url) |
320 | + webview = self.main_window.get_current_webview() |
321 | + self.pointing_device.click_object(webview) |
322 | + pushed = self.base_url + "/statepushed" |
323 | + self.main_window.wait_until_page_loaded(pushed) |
324 | + self.open_history() |
325 | + self.expect_history_entries([pushed, url, self.url]) |
326 | |
327 | === modified file 'tests/unittests/history-model/tst_HistoryModelTests.cpp' |
328 | --- tests/unittests/history-model/tst_HistoryModelTests.cpp 2015-10-07 11:10:14 +0000 |
329 | +++ tests/unittests/history-model/tst_HistoryModelTests.cpp 2016-03-01 09:31:14 +0000 |
330 | @@ -1,5 +1,5 @@ |
331 | /* |
332 | - * Copyright 2013 Canonical Ltd. |
333 | + * Copyright 2013-2016 Canonical Ltd. |
334 | * |
335 | * This file is part of webbrowser-app. |
336 | * |
337 | @@ -136,6 +136,54 @@ |
338 | QVERIFY(roles.contains(HistoryModel::Visits)); |
339 | } |
340 | |
341 | + void shouldUpdateAttributes() |
342 | + { |
343 | + qRegisterMetaType<QVector<int> >(); |
344 | + QSignalSpy spyChanged(model, SIGNAL(dataChanged(const QModelIndex&, const QModelIndex&, const QVector<int>&))); |
345 | + QUrl url(QStringLiteral("http://example.org/")); |
346 | + QCOMPARE(model->add(url, QStringLiteral(""), QUrl()), 1); |
347 | + |
348 | + QVERIFY(!model->update(QUrl(), QStringLiteral(""), QUrl())); |
349 | + QVERIFY(spyChanged.isEmpty()); |
350 | + |
351 | + QVERIFY(!model->update(QUrl(QStringLiteral("http://example.com/")), QStringLiteral(""), QUrl())); |
352 | + QVERIFY(spyChanged.isEmpty()); |
353 | + |
354 | + QVERIFY(!model->update(url, QStringLiteral(""), QUrl())); |
355 | + QVERIFY(spyChanged.isEmpty()); |
356 | + |
357 | + QVERIFY(model->update(url, QStringLiteral("title update"), QUrl())); |
358 | + QCOMPARE(spyChanged.count(), 1); |
359 | + QList<QVariant> args = spyChanged.takeFirst(); |
360 | + QCOMPARE(args.at(0).toModelIndex().row(), 0); |
361 | + QCOMPARE(args.at(1).toModelIndex().row(), 0); |
362 | + QVector<int> roles = args.at(2).value<QVector<int> >(); |
363 | + QCOMPARE(roles.size(), 1); |
364 | + QVERIFY(roles.contains(HistoryModel::Title)); |
365 | + QCOMPARE(model->get(0)[QStringLiteral("visits")].toInt(), 1); |
366 | + |
367 | + QVERIFY(model->update(url, QStringLiteral("title update"), QUrl(QStringLiteral("image://webicon/123")))); |
368 | + QCOMPARE(spyChanged.count(), 1); |
369 | + args = spyChanged.takeFirst(); |
370 | + QCOMPARE(args.at(0).toModelIndex().row(), 0); |
371 | + QCOMPARE(args.at(1).toModelIndex().row(), 0); |
372 | + roles = args.at(2).value<QVector<int> >(); |
373 | + QCOMPARE(roles.size(), 1); |
374 | + QVERIFY(roles.contains(HistoryModel::Icon)); |
375 | + QCOMPARE(model->get(0)[QStringLiteral("visits")].toInt(), 1); |
376 | + |
377 | + QVERIFY(model->update(url, QStringLiteral("title update 2"), QUrl(QStringLiteral("image://webicon/1234")))); |
378 | + QCOMPARE(spyChanged.count(), 1); |
379 | + args = spyChanged.takeFirst(); |
380 | + QCOMPARE(args.at(0).toModelIndex().row(), 0); |
381 | + QCOMPARE(args.at(1).toModelIndex().row(), 0); |
382 | + roles = args.at(2).value<QVector<int> >(); |
383 | + QCOMPARE(roles.size(), 2); |
384 | + QVERIFY(roles.contains(HistoryModel::Title)); |
385 | + QVERIFY(roles.contains(HistoryModel::Icon)); |
386 | + QCOMPARE(model->get(0)[QStringLiteral("visits")].toInt(), 1); |
387 | + } |
388 | + |
389 | void shouldNotifyWhenHidingOrUnHidingExistingEntry() |
390 | { |
391 | qRegisterMetaType<QVector<int> >(); |
FAILED: Continuous integration, rev:1017 jenkins. qa.ubuntu. com/job/ webbrowser- app-ci/ 1778/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 2861/console jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- amd64-ci/ 535 jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 535 jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- armhf-ci/ 535/artifact/ work/output/ *zip*/output. zip jenkins. qa.ubuntu. com/job/ webbrowser- app-vivid- i386-ci/ 535 jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- runner- vivid-mako/ 2451/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2859 jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 2859/artifact/ work/output/ *zip*/output. zip s-jenkins. ubuntu- ci:8080/ job/touch- flash-device/ 20559
http://
Executed test runs:
FAILURE: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
FAILURE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/webbrowser- app-ci/ 1778/rebuild
http://