1 /* |
|
2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
|
3 Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> |
|
4 Copyright (C) 2010 Holger Hans Peter Freyther |
|
5 |
|
6 This library is free software; you can redistribute it and/or |
|
7 modify it under the terms of the GNU Library General Public |
|
8 License as published by the Free Software Foundation; either |
|
9 version 2 of the License, or (at your option) any later version. |
|
10 |
|
11 This library is distributed in the hope that it will be useful, |
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 Library General Public License for more details. |
|
15 |
|
16 You should have received a copy of the GNU Library General Public License |
|
17 along with this library; see the file COPYING.LIB. If not, write to |
|
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
|
19 Boston, MA 02110-1301, USA. |
|
20 */ |
|
21 |
|
22 #include "../util.h" |
|
23 #include "../WebCoreSupport/DumpRenderTreeSupportQt.h" |
|
24 #include <QDir> |
|
25 #include <QGraphicsWidget> |
|
26 #include <QLineEdit> |
|
27 #include <QLocale> |
|
28 #include <QMenu> |
|
29 #include <QPushButton> |
|
30 #include <QStyle> |
|
31 #include <QtTest/QtTest> |
|
32 #include <QTextCharFormat> |
|
33 #include <qgraphicsscene.h> |
|
34 #include <qgraphicsview.h> |
|
35 #include <qgraphicswebview.h> |
|
36 #include <qnetworkrequest.h> |
|
37 #include <qwebdatabase.h> |
|
38 #include <qwebelement.h> |
|
39 #include <qwebframe.h> |
|
40 #include <qwebhistory.h> |
|
41 #include <qwebpage.h> |
|
42 #include <qwebsecurityorigin.h> |
|
43 #include <qwebview.h> |
|
44 |
|
45 class EventSpy : public QObject, public QList<QEvent::Type> |
|
46 { |
|
47 Q_OBJECT |
|
48 public: |
|
49 EventSpy(QObject* objectToSpy) |
|
50 { |
|
51 objectToSpy->installEventFilter(this); |
|
52 } |
|
53 |
|
54 virtual bool eventFilter(QObject* receiver, QEvent* event) |
|
55 { |
|
56 append(event->type()); |
|
57 return false; |
|
58 } |
|
59 }; |
|
60 |
|
61 class tst_QWebPage : public QObject |
|
62 { |
|
63 Q_OBJECT |
|
64 |
|
65 public: |
|
66 tst_QWebPage(); |
|
67 virtual ~tst_QWebPage(); |
|
68 |
|
69 public slots: |
|
70 void init(); |
|
71 void cleanup(); |
|
72 void cleanupFiles(); |
|
73 |
|
74 private slots: |
|
75 void initTestCase(); |
|
76 void cleanupTestCase(); |
|
77 |
|
78 void acceptNavigationRequest(); |
|
79 void infiniteLoopJS(); |
|
80 void geolocationRequestJS(); |
|
81 void loadFinished(); |
|
82 void acceptNavigationRequestWithNewWindow(); |
|
83 void userStyleSheet(); |
|
84 void modified(); |
|
85 void contextMenuCrash(); |
|
86 void database(); |
|
87 void createPluginWithPluginsEnabled(); |
|
88 void createPluginWithPluginsDisabled(); |
|
89 void destroyPlugin_data(); |
|
90 void destroyPlugin(); |
|
91 void createViewlessPlugin_data(); |
|
92 void createViewlessPlugin(); |
|
93 void multiplePageGroupsAndLocalStorage(); |
|
94 void cursorMovements(); |
|
95 void textSelection(); |
|
96 void textEditing(); |
|
97 void backActionUpdate(); |
|
98 void frameAt(); |
|
99 void requestCache(); |
|
100 void protectBindingsRuntimeObjectsFromCollector(); |
|
101 void localURLSchemes(); |
|
102 void testOptionalJSObjects(); |
|
103 void testEnablePersistentStorage(); |
|
104 void consoleOutput(); |
|
105 void inputMethods_data(); |
|
106 void inputMethods(); |
|
107 void inputMethodsTextFormat_data(); |
|
108 void inputMethodsTextFormat(); |
|
109 void defaultTextEncoding(); |
|
110 void errorPageExtension(); |
|
111 void errorPageExtensionInIFrames(); |
|
112 void errorPageExtensionInFrameset(); |
|
113 void userAgentApplicationName(); |
|
114 void userAgentLocaleChange(); |
|
115 |
|
116 void viewModes(); |
|
117 |
|
118 void crashTests_LazyInitializationOfMainFrame(); |
|
119 |
|
120 void screenshot_data(); |
|
121 void screenshot(); |
|
122 |
|
123 void originatingObjectInNetworkRequests(); |
|
124 void testJSPrompt(); |
|
125 void showModalDialog(); |
|
126 void testStopScheduledPageRefresh(); |
|
127 void findText(); |
|
128 |
|
129 private: |
|
130 QWebView* m_view; |
|
131 QWebPage* m_page; |
|
132 }; |
|
133 |
|
134 tst_QWebPage::tst_QWebPage() |
|
135 { |
|
136 } |
|
137 |
|
138 tst_QWebPage::~tst_QWebPage() |
|
139 { |
|
140 } |
|
141 |
|
142 void tst_QWebPage::init() |
|
143 { |
|
144 m_view = new QWebView(); |
|
145 m_page = m_view->page(); |
|
146 } |
|
147 |
|
148 void tst_QWebPage::cleanup() |
|
149 { |
|
150 delete m_view; |
|
151 } |
|
152 |
|
153 void tst_QWebPage::cleanupFiles() |
|
154 { |
|
155 QFile::remove("Databases.db"); |
|
156 QDir::current().rmdir("http_www.myexample.com_0"); |
|
157 QFile::remove("http_www.myexample.com_0.localstorage"); |
|
158 } |
|
159 |
|
160 void tst_QWebPage::initTestCase() |
|
161 { |
|
162 cleanupFiles(); // In case there are old files from previous runs |
|
163 } |
|
164 |
|
165 void tst_QWebPage::cleanupTestCase() |
|
166 { |
|
167 cleanupFiles(); // Be nice |
|
168 } |
|
169 |
|
170 class NavigationRequestOverride : public QWebPage |
|
171 { |
|
172 public: |
|
173 NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {} |
|
174 |
|
175 bool m_acceptNavigationRequest; |
|
176 protected: |
|
177 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) { |
|
178 Q_UNUSED(frame); |
|
179 Q_UNUSED(request); |
|
180 Q_UNUSED(type); |
|
181 |
|
182 return m_acceptNavigationRequest; |
|
183 } |
|
184 }; |
|
185 |
|
186 void tst_QWebPage::acceptNavigationRequest() |
|
187 { |
|
188 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); |
|
189 |
|
190 NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); |
|
191 m_view->setPage(newPage); |
|
192 |
|
193 m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>" |
|
194 "<input type='text'><input type='submit'></form></body></html>"), QUrl()); |
|
195 QTRY_COMPARE(loadSpy.count(), 1); |
|
196 |
|
197 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();"); |
|
198 |
|
199 newPage->m_acceptNavigationRequest = true; |
|
200 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();"); |
|
201 QTRY_COMPARE(loadSpy.count(), 2); |
|
202 |
|
203 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?")); |
|
204 |
|
205 // Restore default page |
|
206 m_view->setPage(0); |
|
207 } |
|
208 |
|
209 class JSTestPage : public QWebPage |
|
210 { |
|
211 Q_OBJECT |
|
212 public: |
|
213 JSTestPage(QObject* parent = 0) |
|
214 : QWebPage(parent) {} |
|
215 |
|
216 public slots: |
|
217 bool shouldInterruptJavaScript() { |
|
218 return true; |
|
219 } |
|
220 bool allowGeolocationRequest(QWebFrame *frame) |
|
221 { |
|
222 return m_allowGeolocation; |
|
223 } |
|
224 |
|
225 public: |
|
226 void setGeolocationPermission(bool allow) |
|
227 { |
|
228 m_allowGeolocation = allow; |
|
229 } |
|
230 |
|
231 private: |
|
232 bool m_allowGeolocation; |
|
233 }; |
|
234 |
|
235 void tst_QWebPage::infiniteLoopJS() |
|
236 { |
|
237 #ifdef Q_WS_MAEMO_5 |
|
238 QSKIP("Test never terminates on Maemo 5 : https://bugs.webkit.org/show_bug.cgi?id=38538", SkipAll); |
|
239 #endif |
|
240 JSTestPage* newPage = new JSTestPage(m_view); |
|
241 m_view->setPage(newPage); |
|
242 m_view->setHtml(QString("<html><body>test</body></html>"), QUrl()); |
|
243 m_view->page()->mainFrame()->evaluateJavaScript("var run = true;var a = 1;while(run){a++;}"); |
|
244 delete newPage; |
|
245 } |
|
246 |
|
247 void tst_QWebPage::geolocationRequestJS() |
|
248 { |
|
249 JSTestPage* newPage = new JSTestPage(m_view); |
|
250 newPage->setGeolocationPermission(false); |
|
251 m_view->setPage(newPage); |
|
252 m_view->setHtml(QString("<html><body>test</body></html>"), QUrl()); |
|
253 m_view->page()->mainFrame()->evaluateJavaScript("var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)"); |
|
254 QTest::qWait(2000); |
|
255 QVariant empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode"); |
|
256 |
|
257 QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0); |
|
258 |
|
259 newPage->setGeolocationPermission(true); |
|
260 m_view->page()->mainFrame()->evaluateJavaScript("errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);"); |
|
261 empty = m_view->page()->mainFrame()->evaluateJavaScript("errorCode"); |
|
262 |
|
263 //http://dev.w3.org/geo/api/spec-source.html#position |
|
264 //PositionError: const unsigned short PERMISSION_DENIED = 1; |
|
265 QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1); |
|
266 delete newPage; |
|
267 } |
|
268 |
|
269 void tst_QWebPage::loadFinished() |
|
270 { |
|
271 qRegisterMetaType<QWebFrame*>("QWebFrame*"); |
|
272 qRegisterMetaType<QNetworkRequest*>("QNetworkRequest*"); |
|
273 QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted())); |
|
274 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); |
|
275 |
|
276 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," |
|
277 "<head><meta http-equiv='refresh' content='1'></head>foo \">" |
|
278 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl()); |
|
279 QTRY_COMPARE(spyLoadFinished.count(), 1); |
|
280 |
|
281 QTRY_VERIFY(spyLoadStarted.count() > 1); |
|
282 QTRY_VERIFY(spyLoadFinished.count() > 1); |
|
283 |
|
284 spyLoadFinished.clear(); |
|
285 |
|
286 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," |
|
287 "foo \"><frame src=\"data:text/html,bar\"></frameset>"), QUrl()); |
|
288 QTRY_COMPARE(spyLoadFinished.count(), 1); |
|
289 QCOMPARE(spyLoadFinished.count(), 1); |
|
290 } |
|
291 |
|
292 class ConsolePage : public QWebPage |
|
293 { |
|
294 public: |
|
295 ConsolePage(QObject* parent = 0) : QWebPage(parent) {} |
|
296 |
|
297 virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) |
|
298 { |
|
299 messages.append(message); |
|
300 lineNumbers.append(lineNumber); |
|
301 sourceIDs.append(sourceID); |
|
302 } |
|
303 |
|
304 QStringList messages; |
|
305 QList<int> lineNumbers; |
|
306 QStringList sourceIDs; |
|
307 }; |
|
308 |
|
309 void tst_QWebPage::consoleOutput() |
|
310 { |
|
311 ConsolePage page; |
|
312 page.mainFrame()->evaluateJavaScript("this is not valid JavaScript"); |
|
313 QCOMPARE(page.messages.count(), 1); |
|
314 QCOMPARE(page.lineNumbers.at(0), 1); |
|
315 } |
|
316 |
|
317 class TestPage : public QWebPage |
|
318 { |
|
319 public: |
|
320 TestPage(QObject* parent = 0) : QWebPage(parent) {} |
|
321 |
|
322 struct Navigation { |
|
323 QPointer<QWebFrame> frame; |
|
324 QNetworkRequest request; |
|
325 NavigationType type; |
|
326 }; |
|
327 |
|
328 QList<Navigation> navigations; |
|
329 QList<QWebPage*> createdWindows; |
|
330 |
|
331 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) { |
|
332 Navigation n; |
|
333 n.frame = frame; |
|
334 n.request = request; |
|
335 n.type = type; |
|
336 navigations.append(n); |
|
337 return true; |
|
338 } |
|
339 |
|
340 virtual QWebPage* createWindow(WebWindowType) { |
|
341 QWebPage* page = new TestPage(this); |
|
342 createdWindows.append(page); |
|
343 return page; |
|
344 } |
|
345 }; |
|
346 |
|
347 void tst_QWebPage::acceptNavigationRequestWithNewWindow() |
|
348 { |
|
349 TestPage* page = new TestPage(m_view); |
|
350 page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true); |
|
351 m_page = page; |
|
352 m_view->setPage(m_page); |
|
353 |
|
354 m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); |
|
355 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
356 |
|
357 QFocusEvent fe(QEvent::FocusIn); |
|
358 m_page->event(&fe); |
|
359 |
|
360 QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); |
|
361 |
|
362 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); |
|
363 m_page->event(&keyEnter); |
|
364 |
|
365 QCOMPARE(page->navigations.count(), 2); |
|
366 |
|
367 TestPage::Navigation n = page->navigations.at(1); |
|
368 QVERIFY(n.frame.isNull()); |
|
369 QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); |
|
370 QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked); |
|
371 |
|
372 QCOMPARE(page->createdWindows.count(), 1); |
|
373 } |
|
374 |
|
375 class TestNetworkManager : public QNetworkAccessManager |
|
376 { |
|
377 public: |
|
378 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} |
|
379 |
|
380 QList<QUrl> requestedUrls; |
|
381 QList<QNetworkRequest> requests; |
|
382 |
|
383 protected: |
|
384 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { |
|
385 requests.append(request); |
|
386 requestedUrls.append(request.url()); |
|
387 return QNetworkAccessManager::createRequest(op, request, outgoingData); |
|
388 } |
|
389 }; |
|
390 |
|
391 void tst_QWebPage::userStyleSheet() |
|
392 { |
|
393 TestNetworkManager* networkManager = new TestNetworkManager(m_page); |
|
394 m_page->setNetworkAccessManager(networkManager); |
|
395 networkManager->requestedUrls.clear(); |
|
396 |
|
397 m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64," |
|
398 + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64())); |
|
399 m_view->setHtml("<p>hello world</p>"); |
|
400 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
401 |
|
402 QVERIFY(networkManager->requestedUrls.count() >= 1); |
|
403 QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); |
|
404 } |
|
405 |
|
406 void tst_QWebPage::viewModes() |
|
407 { |
|
408 m_view->setHtml("<body></body>"); |
|
409 m_page->setProperty("_q_viewMode", "minimized"); |
|
410 |
|
411 QVariant empty = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode)\")"); |
|
412 QVERIFY(empty.type() == QVariant::Bool && empty.toBool()); |
|
413 |
|
414 QVariant minimized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: minimized)\")"); |
|
415 QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool()); |
|
416 |
|
417 QVariant maximized = m_page->mainFrame()->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webkit-view-mode: maximized)\")"); |
|
418 QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool()); |
|
419 } |
|
420 |
|
421 void tst_QWebPage::modified() |
|
422 { |
|
423 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub")); |
|
424 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
425 |
|
426 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah")); |
|
427 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
428 |
|
429 QVERIFY(!m_page->isModified()); |
|
430 |
|
431 // m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))"); |
|
432 m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()"); |
|
433 m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');"); |
|
434 |
|
435 QVERIFY(m_page->isModified()); |
|
436 |
|
437 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);"); |
|
438 |
|
439 QVERIFY(!m_page->isModified()); |
|
440 |
|
441 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);"); |
|
442 |
|
443 QVERIFY(m_page->isModified()); |
|
444 |
|
445 QVERIFY(m_page->history()->canGoBack()); |
|
446 QVERIFY(!m_page->history()->canGoForward()); |
|
447 QCOMPARE(m_page->history()->count(), 2); |
|
448 QVERIFY(m_page->history()->backItem().isValid()); |
|
449 QVERIFY(!m_page->history()->forwardItem().isValid()); |
|
450 |
|
451 m_page->history()->back(); |
|
452 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
453 |
|
454 QVERIFY(!m_page->history()->canGoBack()); |
|
455 QVERIFY(m_page->history()->canGoForward()); |
|
456 |
|
457 QVERIFY(!m_page->isModified()); |
|
458 |
|
459 QVERIFY(m_page->history()->currentItemIndex() == 0); |
|
460 |
|
461 m_page->history()->setMaximumItemCount(3); |
|
462 QVERIFY(m_page->history()->maximumItemCount() == 3); |
|
463 |
|
464 QVariant variant("string test"); |
|
465 m_page->history()->currentItem().setUserData(variant); |
|
466 QVERIFY(m_page->history()->currentItem().userData().toString() == "string test"); |
|
467 |
|
468 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is second page")); |
|
469 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is third page")); |
|
470 QVERIFY(m_page->history()->count() == 2); |
|
471 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fourth page")); |
|
472 QVERIFY(m_page->history()->count() == 2); |
|
473 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fifth page")); |
|
474 QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*)))); |
|
475 } |
|
476 |
|
477 void tst_QWebPage::contextMenuCrash() |
|
478 { |
|
479 QWebView view; |
|
480 view.setHtml("<p>test"); |
|
481 view.page()->updatePositionDependentActions(QPoint(0, 0)); |
|
482 QMenu* contextMenu = 0; |
|
483 foreach (QObject* child, view.children()) { |
|
484 contextMenu = qobject_cast<QMenu*>(child); |
|
485 if (contextMenu) |
|
486 break; |
|
487 } |
|
488 QVERIFY(contextMenu); |
|
489 delete contextMenu; |
|
490 } |
|
491 |
|
492 void tst_QWebPage::database() |
|
493 { |
|
494 QString path = QDir::currentPath(); |
|
495 m_page->settings()->setOfflineStoragePath(path); |
|
496 QVERIFY(m_page->settings()->offlineStoragePath() == path); |
|
497 |
|
498 QWebSettings::setOfflineStorageDefaultQuota(1024 * 1024); |
|
499 QVERIFY(QWebSettings::offlineStorageDefaultQuota() == 1024 * 1024); |
|
500 |
|
501 m_page->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true); |
|
502 m_page->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true); |
|
503 |
|
504 QString dbFileName = path + "Databases.db"; |
|
505 |
|
506 if (QFile::exists(dbFileName)) |
|
507 QFile::remove(dbFileName); |
|
508 |
|
509 qRegisterMetaType<QWebFrame*>("QWebFrame*"); |
|
510 QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString))); |
|
511 m_view->setHtml(QString("<html><head><script>var db; db=openDatabase('testdb', '1.0', 'test database API', 50000); </script></head><body><div></div></body></html>"), QUrl("http://www.myexample.com")); |
|
512 QTRY_COMPARE(spy.count(), 1); |
|
513 m_page->mainFrame()->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);"); |
|
514 QTRY_COMPARE(spy.count(),1); |
|
515 |
|
516 m_page->mainFrame()->evaluateJavaScript("localStorage.test='This is a test for local storage';"); |
|
517 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com")); |
|
518 |
|
519 QVariant s1 = m_page->mainFrame()->evaluateJavaScript("localStorage.test"); |
|
520 QCOMPARE(s1.toString(), QString("This is a test for local storage")); |
|
521 |
|
522 m_page->mainFrame()->evaluateJavaScript("sessionStorage.test='This is a test for session storage';"); |
|
523 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com")); |
|
524 QVariant s2 = m_page->mainFrame()->evaluateJavaScript("sessionStorage.test"); |
|
525 QCOMPARE(s2.toString(), QString("This is a test for session storage")); |
|
526 |
|
527 m_view->setHtml(QString("<html><head></head><body><div></div></body></html>"), QUrl("http://www.myexample.com")); |
|
528 m_page->mainFrame()->evaluateJavaScript("var db3; db3=openDatabase('testdb', '1.0', 'test database API', 50000);db3.transaction(function(tx) { tx.executeSql('CREATE TABLE IF NOT EXISTS Test (text TEXT)', []); }, function(tx, result) { }, function(tx, error) { });"); |
|
529 QTest::qWait(200); |
|
530 |
|
531 // Remove all databases. |
|
532 QWebSecurityOrigin origin = m_page->mainFrame()->securityOrigin(); |
|
533 QList<QWebDatabase> dbs = origin.databases(); |
|
534 for (int i = 0; i < dbs.count(); i++) { |
|
535 QString fileName = dbs[i].fileName(); |
|
536 QVERIFY(QFile::exists(fileName)); |
|
537 QWebDatabase::removeDatabase(dbs[i]); |
|
538 QVERIFY(!QFile::exists(fileName)); |
|
539 } |
|
540 QVERIFY(!origin.databases().size()); |
|
541 // Remove removed test :-) |
|
542 QWebDatabase::removeAllDatabases(); |
|
543 QVERIFY(!origin.databases().size()); |
|
544 } |
|
545 |
|
546 class PluginPage : public QWebPage |
|
547 { |
|
548 public: |
|
549 PluginPage(QObject *parent = 0) |
|
550 : QWebPage(parent) {} |
|
551 |
|
552 struct CallInfo |
|
553 { |
|
554 CallInfo(const QString &c, const QUrl &u, |
|
555 const QStringList &pn, const QStringList &pv, |
|
556 QObject *r) |
|
557 : classid(c), url(u), paramNames(pn), |
|
558 paramValues(pv), returnValue(r) |
|
559 {} |
|
560 QString classid; |
|
561 QUrl url; |
|
562 QStringList paramNames; |
|
563 QStringList paramValues; |
|
564 QObject *returnValue; |
|
565 }; |
|
566 |
|
567 QList<CallInfo> calls; |
|
568 |
|
569 protected: |
|
570 virtual QObject *createPlugin(const QString &classid, const QUrl &url, |
|
571 const QStringList ¶mNames, |
|
572 const QStringList ¶mValues) |
|
573 { |
|
574 QObject *result = 0; |
|
575 if (classid == "pushbutton") |
|
576 result = new QPushButton(); |
|
577 else if (classid == "lineedit") |
|
578 result = new QLineEdit(); |
|
579 if (result) |
|
580 result->setObjectName(classid); |
|
581 calls.append(CallInfo(classid, url, paramNames, paramValues, result)); |
|
582 return result; |
|
583 } |
|
584 }; |
|
585 |
|
586 static void createPlugin(QWebView *view) |
|
587 { |
|
588 QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); |
|
589 |
|
590 PluginPage* newPage = new PluginPage(view); |
|
591 view->setPage(newPage); |
|
592 |
|
593 // type has to be application/x-qt-plugin |
|
594 view->setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='pushbutton' id='mybutton'/></body></html>")); |
|
595 QTRY_COMPARE(loadSpy.count(), 1); |
|
596 QCOMPARE(newPage->calls.count(), 0); |
|
597 |
|
598 view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>")); |
|
599 QTRY_COMPARE(loadSpy.count(), 2); |
|
600 QCOMPARE(newPage->calls.count(), 1); |
|
601 { |
|
602 PluginPage::CallInfo ci = newPage->calls.takeFirst(); |
|
603 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); |
|
604 QCOMPARE(ci.url, QUrl()); |
|
605 QCOMPARE(ci.paramNames.count(), 3); |
|
606 QCOMPARE(ci.paramValues.count(), 3); |
|
607 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); |
|
608 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); |
|
609 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); |
|
610 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); |
|
611 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); |
|
612 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); |
|
613 QVERIFY(ci.returnValue != 0); |
|
614 QVERIFY(ci.returnValue->inherits("QPushButton")); |
|
615 } |
|
616 // test JS bindings |
|
617 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(), |
|
618 QString::fromLatin1("[object HTMLObjectElement]")); |
|
619 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.toString()").toString(), |
|
620 QString::fromLatin1("[object HTMLObjectElement]")); |
|
621 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.objectName").toString(), |
|
622 QString::fromLatin1("string")); |
|
623 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.objectName").toString(), |
|
624 QString::fromLatin1("pushbutton")); |
|
625 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.clicked").toString(), |
|
626 QString::fromLatin1("function")); |
|
627 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.clicked.toString()").toString(), |
|
628 QString::fromLatin1("function clicked() {\n [native code]\n}")); |
|
629 |
|
630 view->setHtml(QString("<html><body><table>" |
|
631 "<tr><object type='application/x-qt-plugin' classid='lineedit' id='myedit'/></tr>" |
|
632 "<tr><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></tr>" |
|
633 "</table></body></html>"), QUrl("http://foo.bar.baz")); |
|
634 QTRY_COMPARE(loadSpy.count(), 3); |
|
635 QCOMPARE(newPage->calls.count(), 2); |
|
636 { |
|
637 PluginPage::CallInfo ci = newPage->calls.takeFirst(); |
|
638 QCOMPARE(ci.classid, QString::fromLatin1("lineedit")); |
|
639 QCOMPARE(ci.url, QUrl()); |
|
640 QCOMPARE(ci.paramNames.count(), 3); |
|
641 QCOMPARE(ci.paramValues.count(), 3); |
|
642 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); |
|
643 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); |
|
644 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); |
|
645 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit")); |
|
646 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); |
|
647 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit")); |
|
648 QVERIFY(ci.returnValue != 0); |
|
649 QVERIFY(ci.returnValue->inherits("QLineEdit")); |
|
650 } |
|
651 { |
|
652 PluginPage::CallInfo ci = newPage->calls.takeFirst(); |
|
653 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); |
|
654 QCOMPARE(ci.url, QUrl()); |
|
655 QCOMPARE(ci.paramNames.count(), 3); |
|
656 QCOMPARE(ci.paramValues.count(), 3); |
|
657 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); |
|
658 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); |
|
659 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); |
|
660 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); |
|
661 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); |
|
662 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); |
|
663 QVERIFY(ci.returnValue != 0); |
|
664 QVERIFY(ci.returnValue->inherits("QPushButton")); |
|
665 } |
|
666 } |
|
667 |
|
668 void tst_QWebPage::createPluginWithPluginsEnabled() |
|
669 { |
|
670 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true); |
|
671 createPlugin(m_view); |
|
672 } |
|
673 |
|
674 void tst_QWebPage::createPluginWithPluginsDisabled() |
|
675 { |
|
676 // Qt Plugins should be loaded by QtWebKit even when PluginsEnabled is |
|
677 // false. The client decides whether a Qt plugin is enabled or not when |
|
678 // it decides whether or not to instantiate it. |
|
679 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, false); |
|
680 createPlugin(m_view); |
|
681 } |
|
682 |
|
683 // Standard base class for template PluginTracerPage. In tests it is used as interface. |
|
684 class PluginCounterPage : public QWebPage { |
|
685 public: |
|
686 int m_count; |
|
687 QPointer<QObject> m_widget; |
|
688 QObject* m_pluginParent; |
|
689 PluginCounterPage(QObject* parent = 0) |
|
690 : QWebPage(parent) |
|
691 , m_count(0) |
|
692 , m_widget(0) |
|
693 , m_pluginParent(0) |
|
694 { |
|
695 settings()->setAttribute(QWebSettings::PluginsEnabled, true); |
|
696 } |
|
697 ~PluginCounterPage() |
|
698 { |
|
699 if (m_pluginParent) |
|
700 m_pluginParent->deleteLater(); |
|
701 } |
|
702 }; |
|
703 |
|
704 template<class T> |
|
705 class PluginTracerPage : public PluginCounterPage { |
|
706 public: |
|
707 PluginTracerPage(QObject* parent = 0) |
|
708 : PluginCounterPage(parent) |
|
709 { |
|
710 // this is a dummy parent object for the created plugin |
|
711 m_pluginParent = new T; |
|
712 } |
|
713 virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) |
|
714 { |
|
715 m_count++; |
|
716 m_widget = new T; |
|
717 // need a cast to the specific type, as QObject::setParent cannot be called, |
|
718 // because it is not virtual. Instead it is necesary to call QWidget::setParent, |
|
719 // which also takes a QWidget* instead of a QObject*. Therefore we need to |
|
720 // upcast to T*, which is a QWidget. |
|
721 static_cast<T*>(m_widget.data())->setParent(static_cast<T*>(m_pluginParent)); |
|
722 return m_widget; |
|
723 } |
|
724 }; |
|
725 |
|
726 class PluginFactory { |
|
727 public: |
|
728 enum FactoredType {QWidgetType, QGraphicsWidgetType}; |
|
729 static PluginCounterPage* create(FactoredType type, QObject* parent = 0) |
|
730 { |
|
731 PluginCounterPage* result = 0; |
|
732 switch (type) { |
|
733 case QWidgetType: |
|
734 result = new PluginTracerPage<QWidget>(parent); |
|
735 break; |
|
736 case QGraphicsWidgetType: |
|
737 result = new PluginTracerPage<QGraphicsWidget>(parent); |
|
738 break; |
|
739 default: {/*Oops*/}; |
|
740 } |
|
741 return result; |
|
742 } |
|
743 |
|
744 static void prepareTestData() |
|
745 { |
|
746 QTest::addColumn<int>("type"); |
|
747 QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType; |
|
748 QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType; |
|
749 } |
|
750 }; |
|
751 |
|
752 void tst_QWebPage::destroyPlugin_data() |
|
753 { |
|
754 PluginFactory::prepareTestData(); |
|
755 } |
|
756 |
|
757 void tst_QWebPage::destroyPlugin() |
|
758 { |
|
759 QFETCH(int, type); |
|
760 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view); |
|
761 m_view->setPage(page); |
|
762 |
|
763 // we create the plugin, so the widget should be constructed |
|
764 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>"); |
|
765 m_view->setHtml(content); |
|
766 QVERIFY(page->m_widget); |
|
767 QCOMPARE(page->m_count, 1); |
|
768 |
|
769 // navigate away, the plugin widget should be destructed |
|
770 m_view->setHtml("<html><body>Hi</body></html>"); |
|
771 QTestEventLoop::instance().enterLoop(1); |
|
772 QVERIFY(!page->m_widget); |
|
773 } |
|
774 |
|
775 void tst_QWebPage::createViewlessPlugin_data() |
|
776 { |
|
777 PluginFactory::prepareTestData(); |
|
778 } |
|
779 |
|
780 void tst_QWebPage::createViewlessPlugin() |
|
781 { |
|
782 QFETCH(int, type); |
|
783 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type); |
|
784 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>"); |
|
785 page->mainFrame()->setHtml(content); |
|
786 QCOMPARE(page->m_count, 1); |
|
787 QVERIFY(page->m_widget); |
|
788 QVERIFY(page->m_pluginParent); |
|
789 QVERIFY(page->m_widget->parent() == page->m_pluginParent); |
|
790 delete page; |
|
791 |
|
792 } |
|
793 |
|
794 void tst_QWebPage::multiplePageGroupsAndLocalStorage() |
|
795 { |
|
796 QDir dir(QDir::currentPath()); |
|
797 dir.mkdir("path1"); |
|
798 dir.mkdir("path2"); |
|
799 |
|
800 QWebView view1; |
|
801 QWebView view2; |
|
802 |
|
803 view1.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true); |
|
804 view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path1")); |
|
805 DumpRenderTreeSupportQt::webPageSetGroupName(view1.page(), "group1"); |
|
806 view2.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true); |
|
807 view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path2")); |
|
808 DumpRenderTreeSupportQt::webPageSetGroupName(view2.page(), "group2"); |
|
809 QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()), QString("group1")); |
|
810 QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()), QString("group2")); |
|
811 |
|
812 |
|
813 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); |
|
814 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); |
|
815 |
|
816 view1.page()->mainFrame()->evaluateJavaScript("localStorage.test='value1';"); |
|
817 view2.page()->mainFrame()->evaluateJavaScript("localStorage.test='value2';"); |
|
818 |
|
819 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); |
|
820 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com")); |
|
821 |
|
822 QVariant s1 = view1.page()->mainFrame()->evaluateJavaScript("localStorage.test"); |
|
823 QCOMPARE(s1.toString(), QString("value1")); |
|
824 |
|
825 QVariant s2 = view2.page()->mainFrame()->evaluateJavaScript("localStorage.test"); |
|
826 QCOMPARE(s2.toString(), QString("value2")); |
|
827 |
|
828 QTest::qWait(1000); |
|
829 |
|
830 QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path1/http_www.myexample.com_0.localstorage")); |
|
831 QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path2/http_www.myexample.com_0.localstorage")); |
|
832 dir.rmdir(QDir::toNativeSeparators("./path1")); |
|
833 dir.rmdir(QDir::toNativeSeparators("./path2")); |
|
834 } |
|
835 |
|
836 class CursorTrackedPage : public QWebPage |
|
837 { |
|
838 public: |
|
839 |
|
840 CursorTrackedPage(QWidget *parent = 0): QWebPage(parent) { |
|
841 setViewportSize(QSize(1024, 768)); // big space |
|
842 } |
|
843 |
|
844 QString selectedText() { |
|
845 return mainFrame()->evaluateJavaScript("window.getSelection().toString()").toString(); |
|
846 } |
|
847 |
|
848 int selectionStartOffset() { |
|
849 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt(); |
|
850 } |
|
851 |
|
852 int selectionEndOffset() { |
|
853 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt(); |
|
854 } |
|
855 |
|
856 // true if start offset == end offset, i.e. no selected text |
|
857 int isSelectionCollapsed() { |
|
858 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool(); |
|
859 } |
|
860 }; |
|
861 |
|
862 void tst_QWebPage::cursorMovements() |
|
863 { |
|
864 CursorTrackedPage* page = new CursorTrackedPage; |
|
865 QString content("<html><body><p id=one>The quick brown fox</p><p id=two>jumps over the lazy dog</p><p>May the source<br/>be with you!</p></body></html>"); |
|
866 page->mainFrame()->setHtml(content); |
|
867 |
|
868 // this will select the first paragraph |
|
869 QString script = "var range = document.createRange(); " \ |
|
870 "var node = document.getElementById(\"one\"); " \ |
|
871 "range.selectNode(node); " \ |
|
872 "getSelection().addRange(range);"; |
|
873 page->mainFrame()->evaluateJavaScript(script); |
|
874 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); |
|
875 |
|
876 // these actions must exist |
|
877 QVERIFY(page->action(QWebPage::MoveToNextChar) != 0); |
|
878 QVERIFY(page->action(QWebPage::MoveToPreviousChar) != 0); |
|
879 QVERIFY(page->action(QWebPage::MoveToNextWord) != 0); |
|
880 QVERIFY(page->action(QWebPage::MoveToPreviousWord) != 0); |
|
881 QVERIFY(page->action(QWebPage::MoveToNextLine) != 0); |
|
882 QVERIFY(page->action(QWebPage::MoveToPreviousLine) != 0); |
|
883 QVERIFY(page->action(QWebPage::MoveToStartOfLine) != 0); |
|
884 QVERIFY(page->action(QWebPage::MoveToEndOfLine) != 0); |
|
885 QVERIFY(page->action(QWebPage::MoveToStartOfBlock) != 0); |
|
886 QVERIFY(page->action(QWebPage::MoveToEndOfBlock) != 0); |
|
887 QVERIFY(page->action(QWebPage::MoveToStartOfDocument) != 0); |
|
888 QVERIFY(page->action(QWebPage::MoveToEndOfDocument) != 0); |
|
889 |
|
890 // right now they are disabled because contentEditable is false |
|
891 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), false); |
|
892 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), false); |
|
893 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), false); |
|
894 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), false); |
|
895 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), false); |
|
896 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), false); |
|
897 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), false); |
|
898 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), false); |
|
899 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), false); |
|
900 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), false); |
|
901 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), false); |
|
902 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), false); |
|
903 |
|
904 // make it editable before navigating the cursor |
|
905 page->setContentEditable(true); |
|
906 |
|
907 // here the actions are enabled after contentEditable is true |
|
908 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), true); |
|
909 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), true); |
|
910 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), true); |
|
911 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), true); |
|
912 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), true); |
|
913 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), true); |
|
914 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), true); |
|
915 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), true); |
|
916 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), true); |
|
917 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), true); |
|
918 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), true); |
|
919 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), true); |
|
920 |
|
921 // cursor will be before the word "jump" |
|
922 page->triggerAction(QWebPage::MoveToNextChar); |
|
923 QVERIFY(page->isSelectionCollapsed()); |
|
924 QCOMPARE(page->selectionStartOffset(), 0); |
|
925 |
|
926 // cursor will be between 'j' and 'u' in the word "jump" |
|
927 page->triggerAction(QWebPage::MoveToNextChar); |
|
928 QVERIFY(page->isSelectionCollapsed()); |
|
929 QCOMPARE(page->selectionStartOffset(), 1); |
|
930 |
|
931 // cursor will be between 'u' and 'm' in the word "jump" |
|
932 page->triggerAction(QWebPage::MoveToNextChar); |
|
933 QVERIFY(page->isSelectionCollapsed()); |
|
934 QCOMPARE(page->selectionStartOffset(), 2); |
|
935 |
|
936 // cursor will be after the word "jump" |
|
937 page->triggerAction(QWebPage::MoveToNextWord); |
|
938 QVERIFY(page->isSelectionCollapsed()); |
|
939 QCOMPARE(page->selectionStartOffset(), 5); |
|
940 |
|
941 // cursor will be after the word "lazy" |
|
942 page->triggerAction(QWebPage::MoveToNextWord); |
|
943 page->triggerAction(QWebPage::MoveToNextWord); |
|
944 page->triggerAction(QWebPage::MoveToNextWord); |
|
945 QVERIFY(page->isSelectionCollapsed()); |
|
946 QCOMPARE(page->selectionStartOffset(), 19); |
|
947 |
|
948 // cursor will be between 'z' and 'y' in "lazy" |
|
949 page->triggerAction(QWebPage::MoveToPreviousChar); |
|
950 QVERIFY(page->isSelectionCollapsed()); |
|
951 QCOMPARE(page->selectionStartOffset(), 18); |
|
952 |
|
953 // cursor will be between 'a' and 'z' in "lazy" |
|
954 page->triggerAction(QWebPage::MoveToPreviousChar); |
|
955 QVERIFY(page->isSelectionCollapsed()); |
|
956 QCOMPARE(page->selectionStartOffset(), 17); |
|
957 |
|
958 // cursor will be before the word "lazy" |
|
959 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
960 QVERIFY(page->isSelectionCollapsed()); |
|
961 QCOMPARE(page->selectionStartOffset(), 15); |
|
962 |
|
963 // cursor will be before the word "quick" |
|
964 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
965 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
966 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
967 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
968 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
969 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
970 QVERIFY(page->isSelectionCollapsed()); |
|
971 QCOMPARE(page->selectionStartOffset(), 4); |
|
972 |
|
973 // cursor will be between 'p' and 's' in the word "jumps" |
|
974 page->triggerAction(QWebPage::MoveToNextWord); |
|
975 page->triggerAction(QWebPage::MoveToNextWord); |
|
976 page->triggerAction(QWebPage::MoveToNextWord); |
|
977 page->triggerAction(QWebPage::MoveToNextChar); |
|
978 page->triggerAction(QWebPage::MoveToNextChar); |
|
979 page->triggerAction(QWebPage::MoveToNextChar); |
|
980 page->triggerAction(QWebPage::MoveToNextChar); |
|
981 page->triggerAction(QWebPage::MoveToNextChar); |
|
982 QVERIFY(page->isSelectionCollapsed()); |
|
983 QCOMPARE(page->selectionStartOffset(), 4); |
|
984 |
|
985 // cursor will be before the word "jumps" |
|
986 page->triggerAction(QWebPage::MoveToStartOfLine); |
|
987 QVERIFY(page->isSelectionCollapsed()); |
|
988 QCOMPARE(page->selectionStartOffset(), 0); |
|
989 |
|
990 // cursor will be after the word "dog" |
|
991 page->triggerAction(QWebPage::MoveToEndOfLine); |
|
992 QVERIFY(page->isSelectionCollapsed()); |
|
993 QCOMPARE(page->selectionStartOffset(), 23); |
|
994 |
|
995 // cursor will be between 'w' and 'n' in "brown" |
|
996 page->triggerAction(QWebPage::MoveToStartOfLine); |
|
997 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
998 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
999 page->triggerAction(QWebPage::MoveToNextChar); |
|
1000 page->triggerAction(QWebPage::MoveToNextChar); |
|
1001 page->triggerAction(QWebPage::MoveToNextChar); |
|
1002 page->triggerAction(QWebPage::MoveToNextChar); |
|
1003 QVERIFY(page->isSelectionCollapsed()); |
|
1004 QCOMPARE(page->selectionStartOffset(), 14); |
|
1005 |
|
1006 // cursor will be after the word "fox" |
|
1007 page->triggerAction(QWebPage::MoveToEndOfLine); |
|
1008 QVERIFY(page->isSelectionCollapsed()); |
|
1009 QCOMPARE(page->selectionStartOffset(), 19); |
|
1010 |
|
1011 // cursor will be before the word "The" |
|
1012 page->triggerAction(QWebPage::MoveToStartOfDocument); |
|
1013 QVERIFY(page->isSelectionCollapsed()); |
|
1014 QCOMPARE(page->selectionStartOffset(), 0); |
|
1015 |
|
1016 // cursor will be after the word "you!" |
|
1017 page->triggerAction(QWebPage::MoveToEndOfDocument); |
|
1018 QVERIFY(page->isSelectionCollapsed()); |
|
1019 QCOMPARE(page->selectionStartOffset(), 12); |
|
1020 |
|
1021 // cursor will be before the word "be" |
|
1022 page->triggerAction(QWebPage::MoveToStartOfBlock); |
|
1023 QVERIFY(page->isSelectionCollapsed()); |
|
1024 QCOMPARE(page->selectionStartOffset(), 0); |
|
1025 |
|
1026 // cursor will be after the word "you!" |
|
1027 page->triggerAction(QWebPage::MoveToEndOfBlock); |
|
1028 QVERIFY(page->isSelectionCollapsed()); |
|
1029 QCOMPARE(page->selectionStartOffset(), 12); |
|
1030 |
|
1031 // try to move before the document start |
|
1032 page->triggerAction(QWebPage::MoveToStartOfDocument); |
|
1033 page->triggerAction(QWebPage::MoveToPreviousChar); |
|
1034 QVERIFY(page->isSelectionCollapsed()); |
|
1035 QCOMPARE(page->selectionStartOffset(), 0); |
|
1036 page->triggerAction(QWebPage::MoveToStartOfDocument); |
|
1037 page->triggerAction(QWebPage::MoveToPreviousWord); |
|
1038 QVERIFY(page->isSelectionCollapsed()); |
|
1039 QCOMPARE(page->selectionStartOffset(), 0); |
|
1040 |
|
1041 // try to move past the document end |
|
1042 page->triggerAction(QWebPage::MoveToEndOfDocument); |
|
1043 page->triggerAction(QWebPage::MoveToNextChar); |
|
1044 QVERIFY(page->isSelectionCollapsed()); |
|
1045 QCOMPARE(page->selectionStartOffset(), 12); |
|
1046 page->triggerAction(QWebPage::MoveToEndOfDocument); |
|
1047 page->triggerAction(QWebPage::MoveToNextWord); |
|
1048 QVERIFY(page->isSelectionCollapsed()); |
|
1049 QCOMPARE(page->selectionStartOffset(), 12); |
|
1050 |
|
1051 delete page; |
|
1052 } |
|
1053 |
|
1054 void tst_QWebPage::textSelection() |
|
1055 { |
|
1056 CursorTrackedPage* page = new CursorTrackedPage; |
|
1057 QString content("<html><body><p id=one>The quick brown fox</p>" \ |
|
1058 "<p id=two>jumps over the lazy dog</p>" \ |
|
1059 "<p>May the source<br/>be with you!</p></body></html>"); |
|
1060 page->mainFrame()->setHtml(content); |
|
1061 |
|
1062 // these actions must exist |
|
1063 QVERIFY(page->action(QWebPage::SelectAll) != 0); |
|
1064 QVERIFY(page->action(QWebPage::SelectNextChar) != 0); |
|
1065 QVERIFY(page->action(QWebPage::SelectPreviousChar) != 0); |
|
1066 QVERIFY(page->action(QWebPage::SelectNextWord) != 0); |
|
1067 QVERIFY(page->action(QWebPage::SelectPreviousWord) != 0); |
|
1068 QVERIFY(page->action(QWebPage::SelectNextLine) != 0); |
|
1069 QVERIFY(page->action(QWebPage::SelectPreviousLine) != 0); |
|
1070 QVERIFY(page->action(QWebPage::SelectStartOfLine) != 0); |
|
1071 QVERIFY(page->action(QWebPage::SelectEndOfLine) != 0); |
|
1072 QVERIFY(page->action(QWebPage::SelectStartOfBlock) != 0); |
|
1073 QVERIFY(page->action(QWebPage::SelectEndOfBlock) != 0); |
|
1074 QVERIFY(page->action(QWebPage::SelectStartOfDocument) != 0); |
|
1075 QVERIFY(page->action(QWebPage::SelectEndOfDocument) != 0); |
|
1076 |
|
1077 // right now they are disabled because contentEditable is false and |
|
1078 // there isn't an existing selection to modify |
|
1079 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), false); |
|
1080 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), false); |
|
1081 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), false); |
|
1082 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), false); |
|
1083 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), false); |
|
1084 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), false); |
|
1085 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), false); |
|
1086 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), false); |
|
1087 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), false); |
|
1088 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), false); |
|
1089 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), false); |
|
1090 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), false); |
|
1091 |
|
1092 // ..but SelectAll is awalys enabled |
|
1093 QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true); |
|
1094 |
|
1095 // this will select the first paragraph |
|
1096 QString selectScript = "var range = document.createRange(); " \ |
|
1097 "var node = document.getElementById(\"one\"); " \ |
|
1098 "range.selectNode(node); " \ |
|
1099 "getSelection().addRange(range);"; |
|
1100 page->mainFrame()->evaluateJavaScript(selectScript); |
|
1101 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); |
|
1102 |
|
1103 // here the actions are enabled after a selection has been created |
|
1104 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true); |
|
1105 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true); |
|
1106 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true); |
|
1107 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true); |
|
1108 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true); |
|
1109 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true); |
|
1110 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true); |
|
1111 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true); |
|
1112 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true); |
|
1113 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true); |
|
1114 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true); |
|
1115 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true); |
|
1116 |
|
1117 // make it editable before navigating the cursor |
|
1118 page->setContentEditable(true); |
|
1119 |
|
1120 // cursor will be before the word "The", this makes sure there is a charet |
|
1121 page->triggerAction(QWebPage::MoveToStartOfDocument); |
|
1122 QVERIFY(page->isSelectionCollapsed()); |
|
1123 QCOMPARE(page->selectionStartOffset(), 0); |
|
1124 |
|
1125 // here the actions are enabled after contentEditable is true |
|
1126 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true); |
|
1127 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true); |
|
1128 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true); |
|
1129 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true); |
|
1130 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true); |
|
1131 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true); |
|
1132 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true); |
|
1133 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true); |
|
1134 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true); |
|
1135 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true); |
|
1136 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true); |
|
1137 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true); |
|
1138 |
|
1139 delete page; |
|
1140 } |
|
1141 |
|
1142 void tst_QWebPage::textEditing() |
|
1143 { |
|
1144 CursorTrackedPage* page = new CursorTrackedPage; |
|
1145 QString content("<html><body><p id=one>The quick brown fox</p>" \ |
|
1146 "<p id=two>jumps over the lazy dog</p>" \ |
|
1147 "<p>May the source<br/>be with you!</p></body></html>"); |
|
1148 page->mainFrame()->setHtml(content); |
|
1149 |
|
1150 // these actions must exist |
|
1151 QVERIFY(page->action(QWebPage::Cut) != 0); |
|
1152 QVERIFY(page->action(QWebPage::Copy) != 0); |
|
1153 QVERIFY(page->action(QWebPage::Paste) != 0); |
|
1154 QVERIFY(page->action(QWebPage::DeleteStartOfWord) != 0); |
|
1155 QVERIFY(page->action(QWebPage::DeleteEndOfWord) != 0); |
|
1156 QVERIFY(page->action(QWebPage::SetTextDirectionDefault) != 0); |
|
1157 QVERIFY(page->action(QWebPage::SetTextDirectionLeftToRight) != 0); |
|
1158 QVERIFY(page->action(QWebPage::SetTextDirectionRightToLeft) != 0); |
|
1159 QVERIFY(page->action(QWebPage::ToggleBold) != 0); |
|
1160 QVERIFY(page->action(QWebPage::ToggleItalic) != 0); |
|
1161 QVERIFY(page->action(QWebPage::ToggleUnderline) != 0); |
|
1162 QVERIFY(page->action(QWebPage::InsertParagraphSeparator) != 0); |
|
1163 QVERIFY(page->action(QWebPage::InsertLineSeparator) != 0); |
|
1164 QVERIFY(page->action(QWebPage::PasteAndMatchStyle) != 0); |
|
1165 QVERIFY(page->action(QWebPage::RemoveFormat) != 0); |
|
1166 QVERIFY(page->action(QWebPage::ToggleStrikethrough) != 0); |
|
1167 QVERIFY(page->action(QWebPage::ToggleSubscript) != 0); |
|
1168 QVERIFY(page->action(QWebPage::ToggleSuperscript) != 0); |
|
1169 QVERIFY(page->action(QWebPage::InsertUnorderedList) != 0); |
|
1170 QVERIFY(page->action(QWebPage::InsertOrderedList) != 0); |
|
1171 QVERIFY(page->action(QWebPage::Indent) != 0); |
|
1172 QVERIFY(page->action(QWebPage::Outdent) != 0); |
|
1173 QVERIFY(page->action(QWebPage::AlignCenter) != 0); |
|
1174 QVERIFY(page->action(QWebPage::AlignJustified) != 0); |
|
1175 QVERIFY(page->action(QWebPage::AlignLeft) != 0); |
|
1176 QVERIFY(page->action(QWebPage::AlignRight) != 0); |
|
1177 |
|
1178 // right now they are disabled because contentEditable is false |
|
1179 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false); |
|
1180 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), false); |
|
1181 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), false); |
|
1182 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), false); |
|
1183 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), false); |
|
1184 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), false); |
|
1185 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), false); |
|
1186 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), false); |
|
1187 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), false); |
|
1188 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), false); |
|
1189 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), false); |
|
1190 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), false); |
|
1191 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), false); |
|
1192 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false); |
|
1193 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), false); |
|
1194 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), false); |
|
1195 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), false); |
|
1196 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), false); |
|
1197 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), false); |
|
1198 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), false); |
|
1199 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), false); |
|
1200 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), false); |
|
1201 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), false); |
|
1202 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), false); |
|
1203 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), false); |
|
1204 |
|
1205 // Select everything |
|
1206 page->triggerAction(QWebPage::SelectAll); |
|
1207 |
|
1208 // make sure it is enabled since there is a selection |
|
1209 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), true); |
|
1210 |
|
1211 // make it editable before navigating the cursor |
|
1212 page->setContentEditable(true); |
|
1213 |
|
1214 // clear the selection |
|
1215 page->triggerAction(QWebPage::MoveToStartOfDocument); |
|
1216 QVERIFY(page->isSelectionCollapsed()); |
|
1217 QCOMPARE(page->selectionStartOffset(), 0); |
|
1218 |
|
1219 // make sure it is disabled since there isn't a selection |
|
1220 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), false); |
|
1221 |
|
1222 // here the actions are enabled after contentEditable is true |
|
1223 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), true); |
|
1224 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), true); |
|
1225 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), true); |
|
1226 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), true); |
|
1227 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), true); |
|
1228 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), true); |
|
1229 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), true); |
|
1230 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), true); |
|
1231 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), true); |
|
1232 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), true); |
|
1233 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), true); |
|
1234 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), true); |
|
1235 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), true); |
|
1236 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), true); |
|
1237 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), true); |
|
1238 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), true); |
|
1239 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), true); |
|
1240 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), true); |
|
1241 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), true); |
|
1242 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), true); |
|
1243 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), true); |
|
1244 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), true); |
|
1245 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), true); |
|
1246 |
|
1247 // make sure these are disabled since there isn't a selection |
|
1248 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false); |
|
1249 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false); |
|
1250 |
|
1251 // make sure everything is selected |
|
1252 page->triggerAction(QWebPage::SelectAll); |
|
1253 |
|
1254 // this is only true if there is an editable selection |
|
1255 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), true); |
|
1256 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), true); |
|
1257 |
|
1258 delete page; |
|
1259 } |
|
1260 |
|
1261 void tst_QWebPage::requestCache() |
|
1262 { |
|
1263 TestPage page; |
|
1264 QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); |
|
1265 |
|
1266 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>")); |
|
1267 QTRY_COMPARE(loadSpy.count(), 1); |
|
1268 QTRY_COMPARE(page.navigations.count(), 1); |
|
1269 |
|
1270 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>")); |
|
1271 QTRY_COMPARE(loadSpy.count(), 2); |
|
1272 QTRY_COMPARE(page.navigations.count(), 2); |
|
1273 |
|
1274 page.triggerAction(QWebPage::Stop); |
|
1275 QVERIFY(page.history()->canGoBack()); |
|
1276 page.triggerAction(QWebPage::Back); |
|
1277 |
|
1278 QTRY_COMPARE(loadSpy.count(), 3); |
|
1279 QTRY_COMPARE(page.navigations.count(), 3); |
|
1280 QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), |
|
1281 (int)QNetworkRequest::PreferNetwork); |
|
1282 QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), |
|
1283 (int)QNetworkRequest::PreferNetwork); |
|
1284 QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), |
|
1285 (int)QNetworkRequest::PreferCache); |
|
1286 } |
|
1287 |
|
1288 void tst_QWebPage::backActionUpdate() |
|
1289 { |
|
1290 QWebView view; |
|
1291 QWebPage *page = view.page(); |
|
1292 QAction *action = page->action(QWebPage::Back); |
|
1293 QVERIFY(!action->isEnabled()); |
|
1294 QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); |
|
1295 QUrl url = QUrl("qrc:///resources/index.html"); |
|
1296 page->mainFrame()->load(url); |
|
1297 QTRY_COMPARE(loadSpy.count(), 1); |
|
1298 QVERIFY(!action->isEnabled()); |
|
1299 QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10)); |
|
1300 QTRY_COMPARE(loadSpy.count(), 2); |
|
1301 |
|
1302 QVERIFY(action->isEnabled()); |
|
1303 } |
|
1304 |
|
1305 void frameAtHelper(QWebPage* webPage, QWebFrame* webFrame, QPoint framePosition) |
|
1306 { |
|
1307 if (!webFrame) |
|
1308 return; |
|
1309 |
|
1310 framePosition += QPoint(webFrame->pos()); |
|
1311 QList<QWebFrame*> children = webFrame->childFrames(); |
|
1312 for (int i = 0; i < children.size(); ++i) { |
|
1313 if (children.at(i)->childFrames().size() > 0) |
|
1314 frameAtHelper(webPage, children.at(i), framePosition); |
|
1315 |
|
1316 QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size()); |
|
1317 QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft())); |
|
1318 } |
|
1319 } |
|
1320 |
|
1321 void tst_QWebPage::frameAt() |
|
1322 { |
|
1323 QWebView webView; |
|
1324 QWebPage* webPage = webView.page(); |
|
1325 QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool))); |
|
1326 QUrl url = QUrl("qrc:///resources/iframe.html"); |
|
1327 webPage->mainFrame()->load(url); |
|
1328 QTRY_COMPARE(loadSpy.count(), 1); |
|
1329 frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos()); |
|
1330 } |
|
1331 |
|
1332 void tst_QWebPage::inputMethods_data() |
|
1333 { |
|
1334 QTest::addColumn<QString>("viewType"); |
|
1335 QTest::newRow("QWebView") << "QWebView"; |
|
1336 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1337 QTest::newRow("QGraphicsWebView") << "QGraphicsWebView"; |
|
1338 #endif |
|
1339 } |
|
1340 |
|
1341 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1342 static Qt::InputMethodHints inputMethodHints(QObject* object) |
|
1343 { |
|
1344 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) |
|
1345 return o->inputMethodHints(); |
|
1346 if (QWidget* w = qobject_cast<QWidget*>(object)) |
|
1347 return w->inputMethodHints(); |
|
1348 return Qt::InputMethodHints(); |
|
1349 } |
|
1350 #endif |
|
1351 |
|
1352 static bool inputMethodEnabled(QObject* object) |
|
1353 { |
|
1354 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1355 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) |
|
1356 return o->flags() & QGraphicsItem::ItemAcceptsInputMethod; |
|
1357 #endif |
|
1358 if (QWidget* w = qobject_cast<QWidget*>(object)) |
|
1359 return w->testAttribute(Qt::WA_InputMethodEnabled); |
|
1360 return false; |
|
1361 } |
|
1362 |
|
1363 void tst_QWebPage::inputMethods() |
|
1364 { |
|
1365 QFETCH(QString, viewType); |
|
1366 QWebPage* page = new QWebPage; |
|
1367 QObject* view = 0; |
|
1368 QObject* container = 0; |
|
1369 if (viewType == "QWebView") { |
|
1370 QWebView* wv = new QWebView; |
|
1371 wv->setPage(page); |
|
1372 view = wv; |
|
1373 container = view; |
|
1374 } |
|
1375 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1376 else if (viewType == "QGraphicsWebView") { |
|
1377 QGraphicsWebView* wv = new QGraphicsWebView; |
|
1378 wv->setPage(page); |
|
1379 view = wv; |
|
1380 |
|
1381 QGraphicsView* gv = new QGraphicsView; |
|
1382 QGraphicsScene* scene = new QGraphicsScene(gv); |
|
1383 gv->setScene(scene); |
|
1384 scene->addItem(wv); |
|
1385 wv->setGeometry(QRect(0, 0, 500, 500)); |
|
1386 |
|
1387 container = gv; |
|
1388 } |
|
1389 #endif |
|
1390 else |
|
1391 QVERIFY2(false, "Unknown view type"); |
|
1392 |
|
1393 page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont"); |
|
1394 page->mainFrame()->setHtml("<html><body>" \ |
|
1395 "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \ |
|
1396 "<input type='password'/>" \ |
|
1397 "</body></html>"); |
|
1398 page->mainFrame()->setFocus(); |
|
1399 |
|
1400 EventSpy viewEventSpy(container); |
|
1401 |
|
1402 QWebElementCollection inputs = page->mainFrame()->documentElement().findAll("input"); |
|
1403 |
|
1404 QMouseEvent evpres(QEvent::MouseButtonPress, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1405 page->event(&evpres); |
|
1406 QMouseEvent evrel(QEvent::MouseButtonRelease, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1407 page->event(&evrel); |
|
1408 |
|
1409 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1410 // This part of the test checks if the SIP (Software Input Panel) is triggered, |
|
1411 // which normally happens on mobile platforms, when a user input form receives |
|
1412 // a mouse click. |
|
1413 int inputPanel = 0; |
|
1414 if (viewType == "QWebView") { |
|
1415 if (QWebView* wv = qobject_cast<QWebView*>(view)) |
|
1416 inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); |
|
1417 } else if (viewType == "QGraphicsWebView") { |
|
1418 if (QGraphicsWebView* wv = qobject_cast<QGraphicsWebView*>(view)) |
|
1419 inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); |
|
1420 } |
|
1421 |
|
1422 // For non-mobile platforms RequestSoftwareInputPanel event is not called |
|
1423 // because there is no SIP (Software Input Panel) triggered. In the case of a |
|
1424 // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked |
|
1425 // and the RequestSoftwareInputPanel event is called. For these two situations |
|
1426 // this part of the test can verified as the checks below. |
|
1427 if (inputPanel) |
|
1428 QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel)); |
|
1429 else |
|
1430 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel)); |
|
1431 #endif |
|
1432 viewEventSpy.clear(); |
|
1433 |
|
1434 page->event(&evpres); |
|
1435 page->event(&evrel); |
|
1436 |
|
1437 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1438 QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel)); |
|
1439 #endif |
|
1440 |
|
1441 //ImMicroFocus |
|
1442 QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus); |
|
1443 QRect focusRect = variant.toRect(); |
|
1444 QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); |
|
1445 |
|
1446 //ImFont |
|
1447 variant = page->inputMethodQuery(Qt::ImFont); |
|
1448 QFont font = variant.value<QFont>(); |
|
1449 QCOMPARE(page->settings()->fontFamily(QWebSettings::SerifFont), font.family()); |
|
1450 |
|
1451 QList<QInputMethodEvent::Attribute> inputAttributes; |
|
1452 |
|
1453 //Insert text. |
|
1454 { |
|
1455 QInputMethodEvent eventText("QtWebKit", inputAttributes); |
|
1456 QSignalSpy signalSpy(page, SIGNAL(microFocusChanged())); |
|
1457 page->event(&eventText); |
|
1458 QCOMPARE(signalSpy.count(), 0); |
|
1459 } |
|
1460 |
|
1461 { |
|
1462 QInputMethodEvent eventText("", inputAttributes); |
|
1463 eventText.setCommitString(QString("QtWebKit"), 0, 0); |
|
1464 page->event(&eventText); |
|
1465 } |
|
1466 |
|
1467 #if QT_VERSION >= 0x040600 |
|
1468 //ImMaximumTextLength |
|
1469 variant = page->inputMethodQuery(Qt::ImMaximumTextLength); |
|
1470 QCOMPARE(20, variant.toInt()); |
|
1471 |
|
1472 //Set selection |
|
1473 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); |
|
1474 QInputMethodEvent eventSelection("",inputAttributes); |
|
1475 page->event(&eventSelection); |
|
1476 |
|
1477 //ImAnchorPosition |
|
1478 variant = page->inputMethodQuery(Qt::ImAnchorPosition); |
|
1479 int anchorPosition = variant.toInt(); |
|
1480 QCOMPARE(anchorPosition, 3); |
|
1481 |
|
1482 //ImCursorPosition |
|
1483 variant = page->inputMethodQuery(Qt::ImCursorPosition); |
|
1484 int cursorPosition = variant.toInt(); |
|
1485 QCOMPARE(cursorPosition, 5); |
|
1486 |
|
1487 //ImCurrentSelection |
|
1488 variant = page->inputMethodQuery(Qt::ImCurrentSelection); |
|
1489 QString selectionValue = variant.value<QString>(); |
|
1490 QCOMPARE(selectionValue, QString("eb")); |
|
1491 |
|
1492 //Cancel current composition first |
|
1493 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); |
|
1494 QInputMethodEvent eventSelection2("",inputAttributes); |
|
1495 page->event(&eventSelection2); |
|
1496 |
|
1497 //Set selection with negative length |
|
1498 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); |
|
1499 QInputMethodEvent eventSelection3("",inputAttributes); |
|
1500 page->event(&eventSelection3); |
|
1501 |
|
1502 //ImAnchorPosition |
|
1503 variant = page->inputMethodQuery(Qt::ImAnchorPosition); |
|
1504 anchorPosition = variant.toInt(); |
|
1505 QCOMPARE(anchorPosition, 1); |
|
1506 |
|
1507 //ImCursorPosition |
|
1508 variant = page->inputMethodQuery(Qt::ImCursorPosition); |
|
1509 cursorPosition = variant.toInt(); |
|
1510 QCOMPARE(cursorPosition, 6); |
|
1511 |
|
1512 //ImCurrentSelection |
|
1513 variant = page->inputMethodQuery(Qt::ImCurrentSelection); |
|
1514 selectionValue = variant.value<QString>(); |
|
1515 QCOMPARE(selectionValue, QString("tWebK")); |
|
1516 #endif |
|
1517 |
|
1518 //ImSurroundingText |
|
1519 variant = page->inputMethodQuery(Qt::ImSurroundingText); |
|
1520 QString value = variant.value<QString>(); |
|
1521 QCOMPARE(value, QString("QtWebKit")); |
|
1522 |
|
1523 #if QT_VERSION >= 0x040600 |
|
1524 { |
|
1525 QList<QInputMethodEvent::Attribute> attributes; |
|
1526 // Clear the selection, so the next test does not clear any contents. |
|
1527 QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); |
|
1528 attributes.append(newSelection); |
|
1529 QInputMethodEvent event("composition", attributes); |
|
1530 page->event(&event); |
|
1531 } |
|
1532 |
|
1533 // A ongoing composition should not change the surrounding text before it is committed. |
|
1534 variant = page->inputMethodQuery(Qt::ImSurroundingText); |
|
1535 value = variant.value<QString>(); |
|
1536 QCOMPARE(value, QString("QtWebKit")); |
|
1537 #endif |
|
1538 |
|
1539 // Cancel current composition first |
|
1540 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); |
|
1541 QInputMethodEvent eventSelection4("", inputAttributes); |
|
1542 page->event(&eventSelection4); |
|
1543 |
|
1544 // START - Tests for Selection when the Editor is NOT in Composition mode |
|
1545 |
|
1546 // LEFT to RIGHT selection |
|
1547 // Deselect the selection by sending MouseButtonPress events |
|
1548 // This moves the current cursor to the end of the text |
|
1549 page->event(&evpres); |
|
1550 page->event(&evrel); |
|
1551 |
|
1552 //Move to the start of the line |
|
1553 page->triggerAction(QWebPage::MoveToStartOfLine); |
|
1554 |
|
1555 QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier); |
|
1556 QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier); |
|
1557 |
|
1558 //Move 2 characters RIGHT |
|
1559 for (int j = 0; j < 2; ++j) { |
|
1560 page->event(&keyRightEventPress); |
|
1561 page->event(&keyRightEventRelease); |
|
1562 } |
|
1563 |
|
1564 //Select to the end of the line |
|
1565 page->triggerAction(QWebPage::SelectEndOfLine); |
|
1566 |
|
1567 //ImAnchorPosition QtWebKit |
|
1568 variant = page->inputMethodQuery(Qt::ImAnchorPosition); |
|
1569 anchorPosition = variant.toInt(); |
|
1570 QCOMPARE(anchorPosition, 2); |
|
1571 |
|
1572 //ImCursorPosition |
|
1573 variant = page->inputMethodQuery(Qt::ImCursorPosition); |
|
1574 cursorPosition = variant.toInt(); |
|
1575 QCOMPARE(cursorPosition, 8); |
|
1576 |
|
1577 //ImCurrentSelection |
|
1578 variant = page->inputMethodQuery(Qt::ImCurrentSelection); |
|
1579 selectionValue = variant.value<QString>(); |
|
1580 QCOMPARE(selectionValue, QString("WebKit")); |
|
1581 |
|
1582 //RIGHT to LEFT selection |
|
1583 //Deselect the selection (this moves the current cursor to the end of the text) |
|
1584 page->event(&evpres); |
|
1585 page->event(&evrel); |
|
1586 |
|
1587 //ImAnchorPosition |
|
1588 variant = page->inputMethodQuery(Qt::ImAnchorPosition); |
|
1589 anchorPosition = variant.toInt(); |
|
1590 QCOMPARE(anchorPosition, 8); |
|
1591 |
|
1592 //ImCursorPosition |
|
1593 variant = page->inputMethodQuery(Qt::ImCursorPosition); |
|
1594 cursorPosition = variant.toInt(); |
|
1595 QCOMPARE(cursorPosition, 8); |
|
1596 |
|
1597 //ImCurrentSelection |
|
1598 variant = page->inputMethodQuery(Qt::ImCurrentSelection); |
|
1599 selectionValue = variant.value<QString>(); |
|
1600 QCOMPARE(selectionValue, QString("")); |
|
1601 |
|
1602 QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); |
|
1603 QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier); |
|
1604 |
|
1605 //Move 2 characters LEFT |
|
1606 for (int i = 0; i < 2; ++i) { |
|
1607 page->event(&keyLeftEventPress); |
|
1608 page->event(&keyLeftEventRelease); |
|
1609 } |
|
1610 |
|
1611 //Select to the start of the line |
|
1612 page->triggerAction(QWebPage::SelectStartOfLine); |
|
1613 |
|
1614 //ImAnchorPosition |
|
1615 variant = page->inputMethodQuery(Qt::ImAnchorPosition); |
|
1616 anchorPosition = variant.toInt(); |
|
1617 QCOMPARE(anchorPosition, 6); |
|
1618 |
|
1619 //ImCursorPosition |
|
1620 variant = page->inputMethodQuery(Qt::ImCursorPosition); |
|
1621 cursorPosition = variant.toInt(); |
|
1622 QCOMPARE(cursorPosition, 0); |
|
1623 |
|
1624 //ImCurrentSelection |
|
1625 variant = page->inputMethodQuery(Qt::ImCurrentSelection); |
|
1626 selectionValue = variant.value<QString>(); |
|
1627 QCOMPARE(selectionValue, QString("QtWebK")); |
|
1628 |
|
1629 //END - Tests for Selection when the Editor is not in Composition mode |
|
1630 |
|
1631 //ImhHiddenText |
|
1632 QMouseEvent evpresPassword(QEvent::MouseButtonPress, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1633 page->event(&evpresPassword); |
|
1634 QMouseEvent evrelPassword(QEvent::MouseButtonRelease, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1635 page->event(&evrelPassword); |
|
1636 |
|
1637 QVERIFY(inputMethodEnabled(view)); |
|
1638 #if QT_VERSION >= 0x040600 |
|
1639 QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText); |
|
1640 |
|
1641 page->event(&evpres); |
|
1642 page->event(&evrel); |
|
1643 QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText)); |
|
1644 #endif |
|
1645 |
|
1646 page->mainFrame()->setHtml("<html><body><p>nothing to input here"); |
|
1647 viewEventSpy.clear(); |
|
1648 |
|
1649 QWebElement para = page->mainFrame()->findFirstElement("p"); |
|
1650 { |
|
1651 QMouseEvent evpres(QEvent::MouseButtonPress, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1652 page->event(&evpres); |
|
1653 QMouseEvent evrel(QEvent::MouseButtonRelease, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier); |
|
1654 page->event(&evrel); |
|
1655 } |
|
1656 |
|
1657 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
1658 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel)); |
|
1659 #endif |
|
1660 |
|
1661 delete container; |
|
1662 } |
|
1663 |
|
1664 void tst_QWebPage::inputMethodsTextFormat_data() |
|
1665 { |
|
1666 QTest::addColumn<QString>("string"); |
|
1667 QTest::addColumn<int>("start"); |
|
1668 QTest::addColumn<int>("length"); |
|
1669 |
|
1670 QTest::newRow("") << QString("") << 0 << 0; |
|
1671 QTest::newRow("Q") << QString("Q") << 0 << 1; |
|
1672 QTest::newRow("Qt") << QString("Qt") << 0 << 1; |
|
1673 QTest::newRow("Qt") << QString("Qt") << 0 << 2; |
|
1674 QTest::newRow("Qt") << QString("Qt") << 1 << 1; |
|
1675 QTest::newRow("Qt ") << QString("Qt ") << 0 << 1; |
|
1676 QTest::newRow("Qt ") << QString("Qt ") << 1 << 1; |
|
1677 QTest::newRow("Qt ") << QString("Qt ") << 2 << 1; |
|
1678 QTest::newRow("Qt ") << QString("Qt ") << 2 << -1; |
|
1679 QTest::newRow("Qt ") << QString("Qt ") << -2 << 3; |
|
1680 QTest::newRow("Qt ") << QString("Qt ") << 0 << 3; |
|
1681 QTest::newRow("Qt by") << QString("Qt by") << 0 << 1; |
|
1682 QTest::newRow("Qt by Nokia") << QString("Qt by Nokia") << 0 << 1; |
|
1683 } |
|
1684 |
|
1685 |
|
1686 void tst_QWebPage::inputMethodsTextFormat() |
|
1687 { |
|
1688 QWebPage* page = new QWebPage; |
|
1689 QWebView* view = new QWebView; |
|
1690 view->setPage(page); |
|
1691 page->settings()->setFontFamily(QWebSettings::SerifFont, "FooSerifFont"); |
|
1692 page->mainFrame()->setHtml("<html><body>" \ |
|
1693 "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/>"); |
|
1694 page->mainFrame()->evaluateJavaScript("document.getElementById('input1').focus()"); |
|
1695 page->mainFrame()->setFocus(); |
|
1696 view->show(); |
|
1697 |
|
1698 QFETCH(QString, string); |
|
1699 QFETCH(int, start); |
|
1700 QFETCH(int, length); |
|
1701 |
|
1702 QList<QInputMethodEvent::Attribute> attrs; |
|
1703 QTextCharFormat format; |
|
1704 format.setUnderlineStyle(QTextCharFormat::SingleUnderline); |
|
1705 format.setUnderlineColor(Qt::red); |
|
1706 attrs.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, start, length, format)); |
|
1707 QInputMethodEvent im(string, attrs); |
|
1708 page->event(&im); |
|
1709 |
|
1710 QTest::qWait(1000); |
|
1711 |
|
1712 delete view; |
|
1713 } |
|
1714 |
|
1715 void tst_QWebPage::protectBindingsRuntimeObjectsFromCollector() |
|
1716 { |
|
1717 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); |
|
1718 |
|
1719 PluginPage* newPage = new PluginPage(m_view); |
|
1720 m_view->setPage(newPage); |
|
1721 |
|
1722 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true); |
|
1723 |
|
1724 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='lineedit' id='mylineedit'/></body></html>")); |
|
1725 QTRY_COMPARE(loadSpy.count(), 1); |
|
1726 |
|
1727 newPage->mainFrame()->evaluateJavaScript("function testme(text) { var lineedit = document.getElementById('mylineedit'); lineedit.setText(text); lineedit.selectAll(); }"); |
|
1728 |
|
1729 newPage->mainFrame()->evaluateJavaScript("testme('foo')"); |
|
1730 |
|
1731 DumpRenderTreeSupportQt::garbageCollectorCollect(); |
|
1732 |
|
1733 // don't crash! |
|
1734 newPage->mainFrame()->evaluateJavaScript("testme('bar')"); |
|
1735 } |
|
1736 |
|
1737 void tst_QWebPage::localURLSchemes() |
|
1738 { |
|
1739 int i = QWebSecurityOrigin::localSchemes().size(); |
|
1740 |
|
1741 QWebSecurityOrigin::removeLocalScheme("file"); |
|
1742 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i); |
|
1743 QWebSecurityOrigin::addLocalScheme("file"); |
|
1744 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i); |
|
1745 |
|
1746 QWebSecurityOrigin::removeLocalScheme("qrc"); |
|
1747 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i - 1); |
|
1748 QWebSecurityOrigin::addLocalScheme("qrc"); |
|
1749 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i); |
|
1750 |
|
1751 QString myscheme = "myscheme"; |
|
1752 QWebSecurityOrigin::addLocalScheme(myscheme); |
|
1753 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i + 1); |
|
1754 QVERIFY(QWebSecurityOrigin::localSchemes().contains(myscheme)); |
|
1755 QWebSecurityOrigin::removeLocalScheme(myscheme); |
|
1756 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i); |
|
1757 QWebSecurityOrigin::removeLocalScheme(myscheme); |
|
1758 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i); |
|
1759 } |
|
1760 |
|
1761 static inline bool testFlag(QWebPage& webPage, QWebSettings::WebAttribute settingAttribute, const QString& jsObjectName, bool settingValue) |
|
1762 { |
|
1763 webPage.settings()->setAttribute(settingAttribute, settingValue); |
|
1764 return webPage.mainFrame()->evaluateJavaScript(QString("(window.%1 != undefined)").arg(jsObjectName)).toBool(); |
|
1765 } |
|
1766 |
|
1767 void tst_QWebPage::testOptionalJSObjects() |
|
1768 { |
|
1769 // Once a feature is enabled and the JS object is accessed turning off the setting will not turn off |
|
1770 // the visibility of the JS object any more. For this reason this test uses two QWebPage instances. |
|
1771 // Part of the test is to make sure that the QWebPage instances do not interfere with each other so turning on |
|
1772 // a feature for one instance will not turn it on for another. |
|
1773 |
|
1774 QWebPage webPage1; |
|
1775 QWebPage webPage2; |
|
1776 |
|
1777 webPage1.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl()); |
|
1778 webPage2.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl()); |
|
1779 |
|
1780 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue); |
|
1781 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false); |
|
1782 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", true), true); |
|
1783 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue); |
|
1784 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false); |
|
1785 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), true); |
|
1786 |
|
1787 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false); |
|
1788 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", true), true); |
|
1789 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false); |
|
1790 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", false), true); |
|
1791 } |
|
1792 |
|
1793 void tst_QWebPage::testEnablePersistentStorage() |
|
1794 { |
|
1795 QWebPage webPage; |
|
1796 |
|
1797 // By default all persistent options should be disabled |
|
1798 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), false); |
|
1799 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), false); |
|
1800 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), false); |
|
1801 QVERIFY(webPage.settings()->iconDatabasePath().isEmpty()); |
|
1802 |
|
1803 QWebSettings::enablePersistentStorage(); |
|
1804 |
|
1805 |
|
1806 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), true); |
|
1807 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), true); |
|
1808 QTRY_COMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), true); |
|
1809 |
|
1810 QTRY_VERIFY(!webPage.settings()->offlineStoragePath().isEmpty()); |
|
1811 QTRY_VERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty()); |
|
1812 QTRY_VERIFY(!webPage.settings()->iconDatabasePath().isEmpty()); |
|
1813 } |
|
1814 |
|
1815 void tst_QWebPage::defaultTextEncoding() |
|
1816 { |
|
1817 QWebFrame* mainFrame = m_page->mainFrame(); |
|
1818 |
|
1819 QString defaultCharset = mainFrame->evaluateJavaScript("document.defaultCharset").toString(); |
|
1820 QVERIFY(!defaultCharset.isEmpty()); |
|
1821 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), defaultCharset); |
|
1822 |
|
1823 m_page->settings()->setDefaultTextEncoding(QString("utf-8")); |
|
1824 QString charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString(); |
|
1825 QCOMPARE(charset, QString("utf-8")); |
|
1826 QCOMPARE(m_page->settings()->defaultTextEncoding(), charset); |
|
1827 |
|
1828 m_page->settings()->setDefaultTextEncoding(QString()); |
|
1829 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString(); |
|
1830 QVERIFY(!charset.isEmpty()); |
|
1831 QCOMPARE(charset, defaultCharset); |
|
1832 |
|
1833 QWebSettings::globalSettings()->setDefaultTextEncoding(QString("utf-8")); |
|
1834 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString(); |
|
1835 QCOMPARE(charset, QString("utf-8")); |
|
1836 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), charset); |
|
1837 } |
|
1838 |
|
1839 class ErrorPage : public QWebPage |
|
1840 { |
|
1841 public: |
|
1842 |
|
1843 ErrorPage(QWidget* parent = 0): QWebPage(parent) |
|
1844 { |
|
1845 } |
|
1846 |
|
1847 virtual bool supportsExtension(Extension extension) const |
|
1848 { |
|
1849 return extension == ErrorPageExtension; |
|
1850 } |
|
1851 |
|
1852 virtual bool extension(Extension, const ExtensionOption* option, ExtensionReturn* output) |
|
1853 { |
|
1854 ErrorPageExtensionReturn* errorPage = static_cast<ErrorPageExtensionReturn*>(output); |
|
1855 |
|
1856 errorPage->content = "data:text/html,error"; |
|
1857 return true; |
|
1858 } |
|
1859 }; |
|
1860 |
|
1861 void tst_QWebPage::errorPageExtension() |
|
1862 { |
|
1863 ErrorPage* page = new ErrorPage; |
|
1864 m_view->setPage(page); |
|
1865 |
|
1866 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); |
|
1867 |
|
1868 m_view->setUrl(QUrl("data:text/html,foo")); |
|
1869 QTRY_COMPARE(spyLoadFinished.count(), 1); |
|
1870 |
|
1871 page->mainFrame()->setUrl(QUrl("http://non.existent/url")); |
|
1872 QTRY_COMPARE(spyLoadFinished.count(), 2); |
|
1873 QCOMPARE(page->mainFrame()->toPlainText(), QString("data:text/html,error")); |
|
1874 QCOMPARE(page->history()->count(), 2); |
|
1875 QCOMPARE(page->history()->currentItem().url(), QUrl("http://non.existent/url")); |
|
1876 QCOMPARE(page->history()->canGoBack(), true); |
|
1877 QCOMPARE(page->history()->canGoForward(), false); |
|
1878 |
|
1879 page->triggerAction(QWebPage::Back); |
|
1880 QTRY_COMPARE(page->history()->canGoBack(), false); |
|
1881 QTRY_COMPARE(page->history()->canGoForward(), true); |
|
1882 |
|
1883 page->triggerAction(QWebPage::Forward); |
|
1884 QTRY_COMPARE(page->history()->canGoBack(), true); |
|
1885 QTRY_COMPARE(page->history()->canGoForward(), false); |
|
1886 |
|
1887 page->triggerAction(QWebPage::Back); |
|
1888 QTRY_COMPARE(page->history()->canGoBack(), false); |
|
1889 QTRY_COMPARE(page->history()->canGoForward(), true); |
|
1890 QTRY_COMPARE(page->history()->currentItem().url(), QUrl("data:text/html,foo")); |
|
1891 |
|
1892 m_view->setPage(0); |
|
1893 } |
|
1894 |
|
1895 void tst_QWebPage::errorPageExtensionInIFrames() |
|
1896 { |
|
1897 ErrorPage* page = new ErrorPage; |
|
1898 m_view->setPage(page); |
|
1899 |
|
1900 m_view->setHtml(QString("data:text/html," |
|
1901 "<h1>h1</h1>" |
|
1902 "<iframe src='data:text/html,<p/>p'></iframe>" |
|
1903 "<iframe src='non-existent.html'></iframe>")); |
|
1904 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); |
|
1905 QTRY_COMPARE(spyLoadFinished.count(), 1); |
|
1906 |
|
1907 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("data:text/html,error")); |
|
1908 |
|
1909 m_view->setPage(0); |
|
1910 } |
|
1911 |
|
1912 void tst_QWebPage::errorPageExtensionInFrameset() |
|
1913 { |
|
1914 ErrorPage* page = new ErrorPage; |
|
1915 m_view->setPage(page); |
|
1916 |
|
1917 m_view->load(QUrl("qrc:///resources/index.html")); |
|
1918 |
|
1919 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); |
|
1920 QTRY_COMPARE(spyLoadFinished.count(), 1); |
|
1921 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("data:text/html,error")); |
|
1922 |
|
1923 m_view->setPage(0); |
|
1924 } |
|
1925 |
|
1926 class FriendlyWebPage : public QWebPage |
|
1927 { |
|
1928 public: |
|
1929 friend class tst_QWebPage; |
|
1930 }; |
|
1931 |
|
1932 void tst_QWebPage::userAgentApplicationName() |
|
1933 { |
|
1934 const QString oldApplicationName = QCoreApplication::applicationName(); |
|
1935 FriendlyWebPage page; |
|
1936 |
|
1937 const QString applicationNameMarker = QString::fromUtf8("StrangeName\342\210\236"); |
|
1938 QCoreApplication::setApplicationName(applicationNameMarker); |
|
1939 QVERIFY(page.userAgentForUrl(QUrl()).contains(applicationNameMarker)); |
|
1940 |
|
1941 QCoreApplication::setApplicationName(oldApplicationName); |
|
1942 } |
|
1943 |
|
1944 void tst_QWebPage::userAgentLocaleChange() |
|
1945 { |
|
1946 FriendlyWebPage page; |
|
1947 m_view->setPage(&page); |
|
1948 |
|
1949 const QString markerString = QString::fromLatin1(" nn-NO)"); |
|
1950 |
|
1951 if (page.userAgentForUrl(QUrl()).contains(markerString)) |
|
1952 QSKIP("marker string already present", SkipSingle); |
|
1953 |
|
1954 m_view->setLocale(QLocale(QString::fromLatin1("nn_NO"))); |
|
1955 QVERIFY(page.userAgentForUrl(QUrl()).contains(markerString)); |
|
1956 } |
|
1957 |
|
1958 void tst_QWebPage::crashTests_LazyInitializationOfMainFrame() |
|
1959 { |
|
1960 { |
|
1961 QWebPage webPage; |
|
1962 } |
|
1963 { |
|
1964 QWebPage webPage; |
|
1965 webPage.selectedText(); |
|
1966 } |
|
1967 { |
|
1968 QWebPage webPage; |
|
1969 webPage.triggerAction(QWebPage::Back, true); |
|
1970 } |
|
1971 { |
|
1972 QWebPage webPage; |
|
1973 QPoint pos(10,10); |
|
1974 webPage.updatePositionDependentActions(pos); |
|
1975 } |
|
1976 } |
|
1977 |
|
1978 static void takeScreenshot(QWebPage* page) |
|
1979 { |
|
1980 QWebFrame* mainFrame = page->mainFrame(); |
|
1981 page->setViewportSize(mainFrame->contentsSize()); |
|
1982 QImage image(page->viewportSize(), QImage::Format_ARGB32); |
|
1983 QPainter painter(&image); |
|
1984 mainFrame->render(&painter); |
|
1985 painter.end(); |
|
1986 } |
|
1987 |
|
1988 void tst_QWebPage::screenshot_data() |
|
1989 { |
|
1990 QTest::addColumn<QString>("html"); |
|
1991 QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>"; |
|
1992 QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>"); |
|
1993 QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode='transparent'></embed></body></html>"); |
|
1994 } |
|
1995 |
|
1996 void tst_QWebPage::screenshot() |
|
1997 { |
|
1998 if (!QDir(TESTS_SOURCE_DIR).exists()) |
|
1999 QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); |
|
2000 |
|
2001 QDir::setCurrent(TESTS_SOURCE_DIR); |
|
2002 |
|
2003 QFETCH(QString, html); |
|
2004 QWebPage* page = new QWebPage; |
|
2005 page->settings()->setAttribute(QWebSettings::PluginsEnabled, true); |
|
2006 QWebFrame* mainFrame = page->mainFrame(); |
|
2007 mainFrame->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); |
|
2008 ::waitForSignal(mainFrame, SIGNAL(loadFinished(bool)), 2000); |
|
2009 |
|
2010 // take screenshot without a view |
|
2011 takeScreenshot(page); |
|
2012 |
|
2013 QWebView* view = new QWebView; |
|
2014 view->setPage(page); |
|
2015 |
|
2016 // take screenshot when attached to a view |
|
2017 takeScreenshot(page); |
|
2018 |
|
2019 delete page; |
|
2020 delete view; |
|
2021 |
|
2022 QDir::setCurrent(QApplication::applicationDirPath()); |
|
2023 } |
|
2024 |
|
2025 void tst_QWebPage::originatingObjectInNetworkRequests() |
|
2026 { |
|
2027 TestNetworkManager* networkManager = new TestNetworkManager(m_page); |
|
2028 m_page->setNetworkAccessManager(networkManager); |
|
2029 networkManager->requests.clear(); |
|
2030 |
|
2031 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," |
|
2032 "<head><meta http-equiv='refresh' content='1'></head>foo \">" |
|
2033 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl()); |
|
2034 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); |
|
2035 |
|
2036 QCOMPARE(networkManager->requests.count(), 2); |
|
2037 |
|
2038 QList<QWebFrame*> childFrames = m_page->mainFrame()->childFrames(); |
|
2039 QCOMPARE(childFrames.count(), 2); |
|
2040 |
|
2041 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0) |
|
2042 for (int i = 0; i < 2; ++i) |
|
2043 QVERIFY(qobject_cast<QWebFrame*>(networkManager->requests.at(i).originatingObject()) == childFrames.at(i)); |
|
2044 #endif |
|
2045 } |
|
2046 |
|
2047 /** |
|
2048 * Test fixups for https://bugs.webkit.org/show_bug.cgi?id=30914 |
|
2049 * |
|
2050 * From JS we test the following conditions. |
|
2051 * |
|
2052 * OK + QString() => SUCCESS, empty string (but not null) |
|
2053 * OK + "text" => SUCCESS, "text" |
|
2054 * CANCEL + QString() => CANCEL, null string |
|
2055 * CANCEL + "text" => CANCEL, null string |
|
2056 */ |
|
2057 class JSPromptPage : public QWebPage { |
|
2058 Q_OBJECT |
|
2059 public: |
|
2060 JSPromptPage() |
|
2061 {} |
|
2062 |
|
2063 bool javaScriptPrompt(QWebFrame* frame, const QString& msg, const QString& defaultValue, QString* result) |
|
2064 { |
|
2065 if (msg == QLatin1String("test1")) { |
|
2066 *result = QString(); |
|
2067 return true; |
|
2068 } else if (msg == QLatin1String("test2")) { |
|
2069 *result = QLatin1String("text"); |
|
2070 return true; |
|
2071 } else if (msg == QLatin1String("test3")) { |
|
2072 *result = QString(); |
|
2073 return false; |
|
2074 } else if (msg == QLatin1String("test4")) { |
|
2075 *result = QLatin1String("text"); |
|
2076 return false; |
|
2077 } |
|
2078 |
|
2079 qFatal("Unknown msg."); |
|
2080 return QWebPage::javaScriptPrompt(frame, msg, defaultValue, result); |
|
2081 } |
|
2082 }; |
|
2083 |
|
2084 void tst_QWebPage::testJSPrompt() |
|
2085 { |
|
2086 JSPromptPage page; |
|
2087 bool res; |
|
2088 |
|
2089 // OK + QString() |
|
2090 res = page.mainFrame()->evaluateJavaScript( |
|
2091 "var retval = prompt('test1');" |
|
2092 "retval=='' && retval.length == 0;").toBool(); |
|
2093 QVERIFY(res); |
|
2094 |
|
2095 // OK + "text" |
|
2096 res = page.mainFrame()->evaluateJavaScript( |
|
2097 "var retval = prompt('test2');" |
|
2098 "retval=='text' && retval.length == 4;").toBool(); |
|
2099 QVERIFY(res); |
|
2100 |
|
2101 // Cancel + QString() |
|
2102 res = page.mainFrame()->evaluateJavaScript( |
|
2103 "var retval = prompt('test3');" |
|
2104 "retval===null;").toBool(); |
|
2105 QVERIFY(res); |
|
2106 |
|
2107 // Cancel + "text" |
|
2108 res = page.mainFrame()->evaluateJavaScript( |
|
2109 "var retval = prompt('test4');" |
|
2110 "retval===null;").toBool(); |
|
2111 QVERIFY(res); |
|
2112 } |
|
2113 |
|
2114 class TestModalPage : public QWebPage |
|
2115 { |
|
2116 Q_OBJECT |
|
2117 public: |
|
2118 TestModalPage(QObject* parent = 0) : QWebPage(parent) { |
|
2119 } |
|
2120 virtual QWebPage* createWindow(WebWindowType) { |
|
2121 QWebPage* page = new TestModalPage(); |
|
2122 connect(page, SIGNAL(windowCloseRequested()), page, SLOT(deleteLater())); |
|
2123 return page; |
|
2124 } |
|
2125 }; |
|
2126 |
|
2127 void tst_QWebPage::showModalDialog() |
|
2128 { |
|
2129 TestModalPage page; |
|
2130 page.mainFrame()->setHtml(QString("<html></html>")); |
|
2131 QString res = page.mainFrame()->evaluateJavaScript("window.showModalDialog('javascript:window.returnValue=dialogArguments; window.close();', 'This is a test');").toString(); |
|
2132 QCOMPARE(res, QString("This is a test")); |
|
2133 } |
|
2134 |
|
2135 void tst_QWebPage::testStopScheduledPageRefresh() |
|
2136 { |
|
2137 // Without QWebPage::StopScheduledPageRefresh |
|
2138 QWebPage page1; |
|
2139 page1.setNetworkAccessManager(new TestNetworkManager(&page1)); |
|
2140 page1.mainFrame()->setHtml("<html><head>" |
|
2141 "<meta http-equiv=\"refresh\"content=\"0;URL=http://qt.nokia.com/favicon.ico\">" |
|
2142 "</head><body><h1>Page redirects immediately...</h1>" |
|
2143 "</body></html>"); |
|
2144 QVERIFY(::waitForSignal(&page1, SIGNAL(loadFinished(bool)))); |
|
2145 QTest::qWait(500); |
|
2146 QCOMPARE(page1.mainFrame()->url().toString(), QString("http://qt.nokia.com/favicon.ico")); |
|
2147 |
|
2148 // With QWebPage::StopScheduledPageRefresh |
|
2149 QWebPage page2; |
|
2150 page2.setNetworkAccessManager(new TestNetworkManager(&page2)); |
|
2151 page2.mainFrame()->setHtml("<html><head>" |
|
2152 "<meta http-equiv=\"refresh\"content=\"1;URL=http://qt.nokia.com/favicon.ico\">" |
|
2153 "</head><body><h1>Page redirect test with 1 sec timeout...</h1>" |
|
2154 "</body></html>"); |
|
2155 page2.triggerAction(QWebPage::StopScheduledPageRefresh); |
|
2156 QTest::qWait(1500); |
|
2157 QCOMPARE(page2.mainFrame()->url().toString(), QString("about:blank")); |
|
2158 } |
|
2159 |
|
2160 void tst_QWebPage::findText() |
|
2161 { |
|
2162 m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); |
|
2163 m_page->triggerAction(QWebPage::SelectAll); |
|
2164 QVERIFY(!m_page->selectedText().isEmpty()); |
|
2165 m_page->findText(""); |
|
2166 QVERIFY(m_page->selectedText().isEmpty()); |
|
2167 QStringList words = (QStringList() << "foo" << "bar"); |
|
2168 foreach (QString subString, words) { |
|
2169 m_page->findText(subString, QWebPage::FindWrapsAroundDocument); |
|
2170 QCOMPARE(m_page->selectedText(), subString); |
|
2171 m_page->findText(""); |
|
2172 QVERIFY(m_page->selectedText().isEmpty()); |
|
2173 } |
|
2174 } |
|
2175 |
|
2176 QTEST_MAIN(tst_QWebPage) |
|
2177 #include "tst_qwebpage.moc" |
|