2 Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
3 Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
22 #include <QtTest/QtTest>
24 #include <qgraphicsscene.h>
25 #include <qgraphicsview.h>
26 #include <qgraphicswebview.h>
27 #include <qwebelement.h>
30 #include <QGraphicsWidget>
32 #include <qwebframe.h>
33 #include <qwebhistory.h>
34 #include <qnetworkrequest.h>
38 #include <qwebsecurityorigin.h>
39 #include <qwebdatabase.h>
40 #include <QPushButton>
43 #if defined(Q_OS_SYMBIAN)
47 // Will try to wait for the condition while allowing event processing
48 #define QTRY_COMPARE(__expr, __expected) \
50 const int __step = 50; \
51 const int __timeout = 5000; \
52 if ((__expr) != (__expected)) { \
55 for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
56 QTest::qWait(__step); \
58 QCOMPARE(__expr, __expected); \
66 * Starts an event loop that runs until the given signal is received.
67 Optionally the event loop
68 * can return earlier on a timeout.
70 * \return \p true if the requested signal was received
73 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000)
76 QObject::connect(obj, signal, &loop, SLOT(quit()));
78 QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
80 QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
81 timer.setSingleShot(true);
85 return timeoutSpy.isEmpty();
88 class EventSpy : public QObject, public QList<QEvent::Type>
92 EventSpy(QObject* objectToSpy)
94 objectToSpy->installEventFilter(this);
97 virtual bool eventFilter(QObject* receiver, QEvent* event)
99 append(event->type());
104 class tst_QWebPage : public QObject
110 virtual ~tst_QWebPage();
119 void cleanupTestCase();
121 void acceptNavigationRequest();
122 void infiniteLoopJS();
124 void acceptNavigationRequestWithNewWindow();
125 void userStyleSheet();
127 void contextMenuCrash();
130 void destroyPlugin_data();
131 void destroyPlugin();
132 void createViewlessPlugin_data();
133 void createViewlessPlugin();
134 void multiplePageGroupsAndLocalStorage();
135 void cursorMovements();
136 void textSelection();
138 void backActionUpdate();
141 void protectBindingsRuntimeObjectsFromCollector();
142 void localURLSchemes();
143 void testOptionalJSObjects();
144 void testEnablePersistentStorage();
145 void consoleOutput();
146 void inputMethods_data();
148 void defaultTextEncoding();
149 void errorPageExtension();
150 void errorPageExtensionInIFrames();
151 void errorPageExtensionInFrameset();
153 void crashTests_LazyInitializationOfMainFrame();
155 void screenshot_data();
158 void originatingObjectInNetworkRequests();
165 tst_QWebPage::tst_QWebPage()
169 tst_QWebPage::~tst_QWebPage()
173 void tst_QWebPage::init()
175 m_view = new QWebView();
176 m_page = m_view->page();
179 void tst_QWebPage::cleanup()
184 void tst_QWebPage::cleanupFiles()
186 QFile::remove("Databases.db");
187 QDir::current().rmdir("http_www.myexample.com_0");
188 QFile::remove("http_www.myexample.com_0.localstorage");
191 void tst_QWebPage::initTestCase()
193 cleanupFiles(); // In case there are old files from previous runs
196 void tst_QWebPage::cleanupTestCase()
198 cleanupFiles(); // Be nice
201 class NavigationRequestOverride : public QWebPage
204 NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
206 bool m_acceptNavigationRequest;
208 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
213 return m_acceptNavigationRequest;
217 void tst_QWebPage::acceptNavigationRequest()
219 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
221 NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
222 m_view->setPage(newPage);
224 m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
225 "<input type='text'><input type='submit'></form></body></html>"), QUrl());
226 QTRY_COMPARE(loadSpy.count(), 1);
228 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
230 newPage->m_acceptNavigationRequest = true;
231 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
232 QTRY_COMPARE(loadSpy.count(), 2);
234 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
236 // Restore default page
240 class JSTestPage : public QWebPage
244 JSTestPage(QObject* parent = 0)
245 : QWebPage(parent) {}
248 bool shouldInterruptJavaScript() {
253 void tst_QWebPage::infiniteLoopJS()
255 JSTestPage* newPage = new JSTestPage(m_view);
256 m_view->setPage(newPage);
257 m_view->setHtml(QString("<html><bodytest</body></html>"), QUrl());
258 m_view->page()->mainFrame()->evaluateJavaScript("var run = true;var a = 1;while(run){a++;}");
261 void tst_QWebPage::loadFinished()
263 qRegisterMetaType<QWebFrame*>("QWebFrame*");
264 qRegisterMetaType<QNetworkRequest*>("QNetworkRequest*");
265 QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
266 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
268 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
269 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
270 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
271 QTRY_COMPARE(spyLoadFinished.count(), 1);
275 QVERIFY(spyLoadStarted.count() > 1);
276 QVERIFY(spyLoadFinished.count() > 1);
278 spyLoadFinished.clear();
280 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
281 "foo \"><frame src=\"data:text/html,bar\"></frameset>"), QUrl());
282 QTRY_COMPARE(spyLoadFinished.count(), 1);
283 QCOMPARE(spyLoadFinished.count(), 1);
286 class ConsolePage : public QWebPage
289 ConsolePage(QObject* parent = 0) : QWebPage(parent) {}
291 virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID)
293 messages.append(message);
294 lineNumbers.append(lineNumber);
295 sourceIDs.append(sourceID);
298 QStringList messages;
299 QList<int> lineNumbers;
300 QStringList sourceIDs;
303 void tst_QWebPage::consoleOutput()
306 page.mainFrame()->evaluateJavaScript("this is not valid JavaScript");
307 QCOMPARE(page.messages.count(), 1);
308 QCOMPARE(page.lineNumbers.at(0), 1);
311 class TestPage : public QWebPage
314 TestPage(QObject* parent = 0) : QWebPage(parent) {}
317 QPointer<QWebFrame> frame;
318 QNetworkRequest request;
322 QList<Navigation> navigations;
323 QList<QWebPage*> createdWindows;
325 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
330 navigations.append(n);
334 virtual QWebPage* createWindow(WebWindowType) {
335 QWebPage* page = new TestPage(this);
336 createdWindows.append(page);
341 void tst_QWebPage::acceptNavigationRequestWithNewWindow()
343 TestPage* page = new TestPage(m_view);
344 page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
346 m_view->setPage(m_page);
348 m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
349 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
351 QFocusEvent fe(QEvent::FocusIn);
354 QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
356 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
357 m_page->event(&keyEnter);
359 QCOMPARE(page->navigations.count(), 2);
361 TestPage::Navigation n = page->navigations.at(1);
362 QVERIFY(n.frame.isNull());
363 QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached"));
364 QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked);
366 QCOMPARE(page->createdWindows.count(), 1);
369 class TestNetworkManager : public QNetworkAccessManager
372 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
374 QList<QUrl> requestedUrls;
375 QList<QNetworkRequest> requests;
378 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
379 requests.append(request);
380 requestedUrls.append(request.url());
381 return QNetworkAccessManager::createRequest(op, request, outgoingData);
385 void tst_QWebPage::userStyleSheet()
387 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
388 m_page->setNetworkAccessManager(networkManager);
389 networkManager->requestedUrls.clear();
391 m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64,"
392 + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64()));
393 m_view->setHtml("<p>hello world</p>");
394 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
396 QVERIFY(networkManager->requestedUrls.count() >= 1);
397 QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png"));
400 void tst_QWebPage::modified()
402 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
403 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
405 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
406 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
408 QVERIFY(!m_page->isModified());
410 // m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))");
411 m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()");
412 m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');");
414 QVERIFY(m_page->isModified());
416 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
418 QVERIFY(!m_page->isModified());
420 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
422 QVERIFY(m_page->isModified());
424 QVERIFY(m_page->history()->canGoBack());
425 QVERIFY(!m_page->history()->canGoForward());
426 QCOMPARE(m_page->history()->count(), 2);
427 QVERIFY(m_page->history()->backItem().isValid());
428 QVERIFY(!m_page->history()->forwardItem().isValid());
430 m_page->history()->back();
431 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
433 QVERIFY(!m_page->history()->canGoBack());
434 QVERIFY(m_page->history()->canGoForward());
436 QVERIFY(!m_page->isModified());
438 QVERIFY(m_page->history()->currentItemIndex() == 0);
440 m_page->history()->setMaximumItemCount(3);
441 QVERIFY(m_page->history()->maximumItemCount() == 3);
443 QVariant variant("string test");
444 m_page->history()->currentItem().setUserData(variant);
445 QVERIFY(m_page->history()->currentItem().userData().toString() == "string test");
447 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is second page"));
448 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is third page"));
449 QVERIFY(m_page->history()->count() == 2);
450 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fourth page"));
451 QVERIFY(m_page->history()->count() == 2);
452 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>This is fifth page"));
453 QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebFrame*,QWebHistoryItem*))));
456 void tst_QWebPage::contextMenuCrash()
459 view.setHtml("<p>test");
460 view.page()->updatePositionDependentActions(QPoint(0, 0));
461 QMenu* contextMenu = 0;
462 foreach (QObject* child, view.children()) {
463 contextMenu = qobject_cast<QMenu*>(child);
467 QVERIFY(contextMenu);
471 void tst_QWebPage::database()
473 QString path = QDir::currentPath();
474 m_page->settings()->setOfflineStoragePath(path);
475 QVERIFY(m_page->settings()->offlineStoragePath() == path);
477 QWebSettings::setOfflineStorageDefaultQuota(1024 * 1024);
478 QVERIFY(QWebSettings::offlineStorageDefaultQuota() == 1024 * 1024);
480 m_page->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
481 m_page->settings()->setAttribute(QWebSettings::OfflineStorageDatabaseEnabled, true);
483 QString dbFileName = path + "Databases.db";
485 if (QFile::exists(dbFileName))
486 QFile::remove(dbFileName);
488 qRegisterMetaType<QWebFrame*>("QWebFrame*");
489 QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebFrame*,QString)));
490 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"));
491 QTRY_COMPARE(spy.count(), 1);
492 m_page->mainFrame()->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);");
493 QTRY_COMPARE(spy.count(),1);
495 m_page->mainFrame()->evaluateJavaScript("localStorage.test='This is a test for local storage';");
496 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
498 QVariant s1 = m_page->mainFrame()->evaluateJavaScript("localStorage.test");
499 QCOMPARE(s1.toString(), QString("This is a test for local storage"));
501 m_page->mainFrame()->evaluateJavaScript("sessionStorage.test='This is a test for session storage';");
502 m_view->setHtml(QString("<html><body id='b'>text</body></html>"), QUrl("http://www.myexample.com"));
503 QVariant s2 = m_page->mainFrame()->evaluateJavaScript("sessionStorage.test");
504 QCOMPARE(s2.toString(), QString("This is a test for session storage"));
506 m_view->setHtml(QString("<html><head></head><body><div></div></body></html>"), QUrl("http://www.myexample.com"));
507 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) { });");
510 // Remove all databases.
511 QWebSecurityOrigin origin = m_page->mainFrame()->securityOrigin();
512 QList<QWebDatabase> dbs = origin.databases();
513 for (int i = 0; i < dbs.count(); i++) {
514 QString fileName = dbs[i].fileName();
515 QVERIFY(QFile::exists(fileName));
516 QWebDatabase::removeDatabase(dbs[i]);
517 QVERIFY(!QFile::exists(fileName));
519 QVERIFY(!origin.databases().size());
520 // Remove removed test :-)
521 QWebDatabase::removeAllDatabases();
522 QVERIFY(!origin.databases().size());
526 class PluginPage : public QWebPage
529 PluginPage(QObject *parent = 0)
530 : QWebPage(parent) {}
534 CallInfo(const QString &c, const QUrl &u,
535 const QStringList &pn, const QStringList &pv,
537 : classid(c), url(u), paramNames(pn),
538 paramValues(pv), returnValue(r)
542 QStringList paramNames;
543 QStringList paramValues;
544 QObject *returnValue;
547 QList<CallInfo> calls;
550 virtual QObject *createPlugin(const QString &classid, const QUrl &url,
551 const QStringList ¶mNames,
552 const QStringList ¶mValues)
555 if (classid == "pushbutton")
556 result = new QPushButton();
557 else if (classid == "lineedit")
558 result = new QLineEdit();
560 result->setObjectName(classid);
561 calls.append(CallInfo(classid, url, paramNames, paramValues, result));
566 void tst_QWebPage::createPlugin()
568 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
570 PluginPage* newPage = new PluginPage(m_view);
571 m_view->setPage(newPage);
573 // plugins not enabled by default, so the plugin shouldn't be loaded
574 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
575 QTRY_COMPARE(loadSpy.count(), 1);
576 QCOMPARE(newPage->calls.count(), 0);
578 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
580 // type has to be application/x-qt-plugin
581 m_view->setHtml(QString("<html><body><object type='application/x-foobarbaz' classid='pushbutton' id='mybutton'/></body></html>"));
582 QTRY_COMPARE(loadSpy.count(), 2);
583 QCOMPARE(newPage->calls.count(), 0);
585 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
586 QTRY_COMPARE(loadSpy.count(), 3);
587 QCOMPARE(newPage->calls.count(), 1);
589 PluginPage::CallInfo ci = newPage->calls.takeFirst();
590 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
591 QCOMPARE(ci.url, QUrl());
592 QCOMPARE(ci.paramNames.count(), 3);
593 QCOMPARE(ci.paramValues.count(), 3);
594 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
595 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
596 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
597 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
598 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
599 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
600 QVERIFY(ci.returnValue != 0);
601 QVERIFY(ci.returnValue->inherits("QPushButton"));
604 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(),
605 QString::fromLatin1("[object HTMLObjectElement]"));
606 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.toString()").toString(),
607 QString::fromLatin1("[object HTMLObjectElement]"));
608 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.objectName").toString(),
609 QString::fromLatin1("string"));
610 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.objectName").toString(),
611 QString::fromLatin1("pushbutton"));
612 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("typeof mybutton.clicked").toString(),
613 QString::fromLatin1("function"));
614 QCOMPARE(newPage->mainFrame()->evaluateJavaScript("mybutton.clicked.toString()").toString(),
615 QString::fromLatin1("function clicked() {\n [native code]\n}"));
617 m_view->setHtml(QString("<html><body><table>"
618 "<tr><object type='application/x-qt-plugin' classid='lineedit' id='myedit'/></tr>"
619 "<tr><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></tr>"
620 "</table></body></html>"), QUrl("http://foo.bar.baz"));
621 QTRY_COMPARE(loadSpy.count(), 4);
622 QCOMPARE(newPage->calls.count(), 2);
624 PluginPage::CallInfo ci = newPage->calls.takeFirst();
625 QCOMPARE(ci.classid, QString::fromLatin1("lineedit"));
626 QCOMPARE(ci.url, QUrl());
627 QCOMPARE(ci.paramNames.count(), 3);
628 QCOMPARE(ci.paramValues.count(), 3);
629 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
630 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
631 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
632 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit"));
633 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
634 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit"));
635 QVERIFY(ci.returnValue != 0);
636 QVERIFY(ci.returnValue->inherits("QLineEdit"));
639 PluginPage::CallInfo ci = newPage->calls.takeFirst();
640 QCOMPARE(ci.classid, QString::fromLatin1("pushbutton"));
641 QCOMPARE(ci.url, QUrl());
642 QCOMPARE(ci.paramNames.count(), 3);
643 QCOMPARE(ci.paramValues.count(), 3);
644 QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type"));
645 QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin"));
646 QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid"));
647 QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton"));
648 QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id"));
649 QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton"));
650 QVERIFY(ci.returnValue != 0);
651 QVERIFY(ci.returnValue->inherits("QPushButton"));
654 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, false);
656 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='pushbutton' id='mybutton'/></body></html>"));
657 QTRY_COMPARE(loadSpy.count(), 5);
658 QCOMPARE(newPage->calls.count(), 0);
662 // Standard base class for template PluginTracerPage. In tests it is used as interface.
663 class PluginCounterPage : public QWebPage {
666 QPointer<QObject> m_widget;
667 QObject* m_pluginParent;
668 PluginCounterPage(QObject* parent = 0)
674 settings()->setAttribute(QWebSettings::PluginsEnabled, true);
679 m_pluginParent->deleteLater();
684 class PluginTracerPage : public PluginCounterPage {
686 PluginTracerPage(QObject* parent = 0)
687 : PluginCounterPage(parent)
689 // this is a dummy parent object for the created plugin
690 m_pluginParent = new T;
692 virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&)
696 // need a cast to the specific type, as QObject::setParent cannot be called,
697 // because it is not virtual. Instead it is necesary to call QWidget::setParent,
698 // which also takes a QWidget* instead of a QObject*. Therefore we need to
699 // upcast to T*, which is a QWidget.
700 static_cast<T*>(m_widget.data())->setParent(static_cast<T*>(m_pluginParent));
705 class PluginFactory {
707 enum FactoredType {QWidgetType, QGraphicsWidgetType};
708 static PluginCounterPage* create(FactoredType type, QObject* parent = 0)
710 PluginCounterPage* result = 0;
713 result = new PluginTracerPage<QWidget>(parent);
715 case QGraphicsWidgetType:
716 result = new PluginTracerPage<QGraphicsWidget>(parent);
723 static void prepareTestData()
725 QTest::addColumn<int>("type");
726 QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType;
727 QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType;
731 void tst_QWebPage::destroyPlugin_data()
733 PluginFactory::prepareTestData();
736 void tst_QWebPage::destroyPlugin()
739 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view);
740 m_view->setPage(page);
742 // we create the plugin, so the widget should be constructed
743 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
744 m_view->setHtml(content);
745 QVERIFY(page->m_widget);
746 QCOMPARE(page->m_count, 1);
748 // navigate away, the plugin widget should be destructed
749 m_view->setHtml("<html><body>Hi</body></html>");
750 QTestEventLoop::instance().enterLoop(1);
751 QVERIFY(!page->m_widget);
754 void tst_QWebPage::createViewlessPlugin_data()
756 PluginFactory::prepareTestData();
759 void tst_QWebPage::createViewlessPlugin()
762 PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type);
763 QString content("<html><body><object type=\"application/x-qt-plugin\" classid=\"QProgressBar\"></object></body></html>");
764 page->mainFrame()->setHtml(content);
765 QCOMPARE(page->m_count, 1);
766 QVERIFY(page->m_widget);
767 QVERIFY(page->m_pluginParent);
768 QVERIFY(page->m_widget->parent() == page->m_pluginParent);
773 // import private API
774 void QWEBKIT_EXPORT qt_webpage_setGroupName(QWebPage* page, const QString& groupName);
775 QString QWEBKIT_EXPORT qt_webpage_groupName(QWebPage* page);
777 void tst_QWebPage::multiplePageGroupsAndLocalStorage()
779 QDir dir(QDir::currentPath());
786 view1.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
787 view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path1"));
788 qt_webpage_setGroupName(view1.page(), "group1");
789 view2.page()->settings()->setAttribute(QWebSettings::LocalStorageEnabled, true);
790 view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(QDir::currentPath() + "/path2"));
791 qt_webpage_setGroupName(view2.page(), "group2");
792 QCOMPARE(qt_webpage_groupName(view1.page()), QString("group1"));
793 QCOMPARE(qt_webpage_groupName(view2.page()), QString("group2"));
796 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
797 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
799 view1.page()->mainFrame()->evaluateJavaScript("localStorage.test='value1';");
800 view2.page()->mainFrame()->evaluateJavaScript("localStorage.test='value2';");
802 view1.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
803 view2.setHtml(QString("<html><body> </body></html>"), QUrl("http://www.myexample.com"));
805 QVariant s1 = view1.page()->mainFrame()->evaluateJavaScript("localStorage.test");
806 QCOMPARE(s1.toString(), QString("value1"));
808 QVariant s2 = view2.page()->mainFrame()->evaluateJavaScript("localStorage.test");
809 QCOMPARE(s2.toString(), QString("value2"));
813 QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path1/http_www.myexample.com_0.localstorage"));
814 QFile::remove(QDir::toNativeSeparators(QDir::currentPath() + "/path2/http_www.myexample.com_0.localstorage"));
815 dir.rmdir(QDir::toNativeSeparators("./path1"));
816 dir.rmdir(QDir::toNativeSeparators("./path2"));
819 class CursorTrackedPage : public QWebPage
823 CursorTrackedPage(QWidget *parent = 0): QWebPage(parent) {
824 setViewportSize(QSize(1024, 768)); // big space
827 QString selectedText() {
828 return mainFrame()->evaluateJavaScript("window.getSelection().toString()").toString();
831 int selectionStartOffset() {
832 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt();
835 int selectionEndOffset() {
836 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt();
839 // true if start offset == end offset, i.e. no selected text
840 int isSelectionCollapsed() {
841 return mainFrame()->evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool();
845 void tst_QWebPage::cursorMovements()
847 CursorTrackedPage* page = new CursorTrackedPage;
848 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>");
849 page->mainFrame()->setHtml(content);
851 // this will select the first paragraph
852 QString script = "var range = document.createRange(); " \
853 "var node = document.getElementById(\"one\"); " \
854 "range.selectNode(node); " \
855 "getSelection().addRange(range);";
856 page->mainFrame()->evaluateJavaScript(script);
857 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
859 // these actions must exist
860 QVERIFY(page->action(QWebPage::MoveToNextChar) != 0);
861 QVERIFY(page->action(QWebPage::MoveToPreviousChar) != 0);
862 QVERIFY(page->action(QWebPage::MoveToNextWord) != 0);
863 QVERIFY(page->action(QWebPage::MoveToPreviousWord) != 0);
864 QVERIFY(page->action(QWebPage::MoveToNextLine) != 0);
865 QVERIFY(page->action(QWebPage::MoveToPreviousLine) != 0);
866 QVERIFY(page->action(QWebPage::MoveToStartOfLine) != 0);
867 QVERIFY(page->action(QWebPage::MoveToEndOfLine) != 0);
868 QVERIFY(page->action(QWebPage::MoveToStartOfBlock) != 0);
869 QVERIFY(page->action(QWebPage::MoveToEndOfBlock) != 0);
870 QVERIFY(page->action(QWebPage::MoveToStartOfDocument) != 0);
871 QVERIFY(page->action(QWebPage::MoveToEndOfDocument) != 0);
873 // right now they are disabled because contentEditable is false
874 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), false);
875 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), false);
876 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), false);
877 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), false);
878 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), false);
879 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), false);
880 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), false);
881 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), false);
882 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), false);
883 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), false);
884 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), false);
885 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), false);
887 // make it editable before navigating the cursor
888 page->setContentEditable(true);
890 // here the actions are enabled after contentEditable is true
891 QCOMPARE(page->action(QWebPage::MoveToNextChar)->isEnabled(), true);
892 QCOMPARE(page->action(QWebPage::MoveToPreviousChar)->isEnabled(), true);
893 QCOMPARE(page->action(QWebPage::MoveToNextWord)->isEnabled(), true);
894 QCOMPARE(page->action(QWebPage::MoveToPreviousWord)->isEnabled(), true);
895 QCOMPARE(page->action(QWebPage::MoveToNextLine)->isEnabled(), true);
896 QCOMPARE(page->action(QWebPage::MoveToPreviousLine)->isEnabled(), true);
897 QCOMPARE(page->action(QWebPage::MoveToStartOfLine)->isEnabled(), true);
898 QCOMPARE(page->action(QWebPage::MoveToEndOfLine)->isEnabled(), true);
899 QCOMPARE(page->action(QWebPage::MoveToStartOfBlock)->isEnabled(), true);
900 QCOMPARE(page->action(QWebPage::MoveToEndOfBlock)->isEnabled(), true);
901 QCOMPARE(page->action(QWebPage::MoveToStartOfDocument)->isEnabled(), true);
902 QCOMPARE(page->action(QWebPage::MoveToEndOfDocument)->isEnabled(), true);
904 // cursor will be before the word "jump"
905 page->triggerAction(QWebPage::MoveToNextChar);
906 QVERIFY(page->isSelectionCollapsed());
907 QCOMPARE(page->selectionStartOffset(), 0);
909 // cursor will be between 'j' and 'u' in the word "jump"
910 page->triggerAction(QWebPage::MoveToNextChar);
911 QVERIFY(page->isSelectionCollapsed());
912 QCOMPARE(page->selectionStartOffset(), 1);
914 // cursor will be between 'u' and 'm' in the word "jump"
915 page->triggerAction(QWebPage::MoveToNextChar);
916 QVERIFY(page->isSelectionCollapsed());
917 QCOMPARE(page->selectionStartOffset(), 2);
919 // cursor will be after the word "jump"
920 page->triggerAction(QWebPage::MoveToNextWord);
921 QVERIFY(page->isSelectionCollapsed());
922 QCOMPARE(page->selectionStartOffset(), 5);
924 // cursor will be after the word "lazy"
925 page->triggerAction(QWebPage::MoveToNextWord);
926 page->triggerAction(QWebPage::MoveToNextWord);
927 page->triggerAction(QWebPage::MoveToNextWord);
928 QVERIFY(page->isSelectionCollapsed());
929 QCOMPARE(page->selectionStartOffset(), 19);
931 // cursor will be between 'z' and 'y' in "lazy"
932 page->triggerAction(QWebPage::MoveToPreviousChar);
933 QVERIFY(page->isSelectionCollapsed());
934 QCOMPARE(page->selectionStartOffset(), 18);
936 // cursor will be between 'a' and 'z' in "lazy"
937 page->triggerAction(QWebPage::MoveToPreviousChar);
938 QVERIFY(page->isSelectionCollapsed());
939 QCOMPARE(page->selectionStartOffset(), 17);
941 // cursor will be before the word "lazy"
942 page->triggerAction(QWebPage::MoveToPreviousWord);
943 QVERIFY(page->isSelectionCollapsed());
944 QCOMPARE(page->selectionStartOffset(), 15);
946 // cursor will be before the word "quick"
947 page->triggerAction(QWebPage::MoveToPreviousWord);
948 page->triggerAction(QWebPage::MoveToPreviousWord);
949 page->triggerAction(QWebPage::MoveToPreviousWord);
950 page->triggerAction(QWebPage::MoveToPreviousWord);
951 page->triggerAction(QWebPage::MoveToPreviousWord);
952 page->triggerAction(QWebPage::MoveToPreviousWord);
953 QVERIFY(page->isSelectionCollapsed());
954 QCOMPARE(page->selectionStartOffset(), 4);
956 // cursor will be between 'p' and 's' in the word "jumps"
957 page->triggerAction(QWebPage::MoveToNextWord);
958 page->triggerAction(QWebPage::MoveToNextWord);
959 page->triggerAction(QWebPage::MoveToNextWord);
960 page->triggerAction(QWebPage::MoveToNextChar);
961 page->triggerAction(QWebPage::MoveToNextChar);
962 page->triggerAction(QWebPage::MoveToNextChar);
963 page->triggerAction(QWebPage::MoveToNextChar);
964 page->triggerAction(QWebPage::MoveToNextChar);
965 QVERIFY(page->isSelectionCollapsed());
966 QCOMPARE(page->selectionStartOffset(), 4);
968 // cursor will be before the word "jumps"
969 page->triggerAction(QWebPage::MoveToStartOfLine);
970 QVERIFY(page->isSelectionCollapsed());
971 QCOMPARE(page->selectionStartOffset(), 0);
973 // cursor will be after the word "dog"
974 page->triggerAction(QWebPage::MoveToEndOfLine);
975 QVERIFY(page->isSelectionCollapsed());
976 QCOMPARE(page->selectionStartOffset(), 23);
978 // cursor will be between 'w' and 'n' in "brown"
979 page->triggerAction(QWebPage::MoveToStartOfLine);
980 page->triggerAction(QWebPage::MoveToPreviousWord);
981 page->triggerAction(QWebPage::MoveToPreviousWord);
982 page->triggerAction(QWebPage::MoveToNextChar);
983 page->triggerAction(QWebPage::MoveToNextChar);
984 page->triggerAction(QWebPage::MoveToNextChar);
985 page->triggerAction(QWebPage::MoveToNextChar);
986 QVERIFY(page->isSelectionCollapsed());
987 QCOMPARE(page->selectionStartOffset(), 14);
989 // cursor will be after the word "fox"
990 page->triggerAction(QWebPage::MoveToEndOfLine);
991 QVERIFY(page->isSelectionCollapsed());
992 QCOMPARE(page->selectionStartOffset(), 19);
994 // cursor will be before the word "The"
995 page->triggerAction(QWebPage::MoveToStartOfDocument);
996 QVERIFY(page->isSelectionCollapsed());
997 QCOMPARE(page->selectionStartOffset(), 0);
999 // cursor will be after the word "you!"
1000 page->triggerAction(QWebPage::MoveToEndOfDocument);
1001 QVERIFY(page->isSelectionCollapsed());
1002 QCOMPARE(page->selectionStartOffset(), 12);
1004 // cursor will be before the word "be"
1005 page->triggerAction(QWebPage::MoveToStartOfBlock);
1006 QVERIFY(page->isSelectionCollapsed());
1007 QCOMPARE(page->selectionStartOffset(), 0);
1009 // cursor will be after the word "you!"
1010 page->triggerAction(QWebPage::MoveToEndOfBlock);
1011 QVERIFY(page->isSelectionCollapsed());
1012 QCOMPARE(page->selectionStartOffset(), 12);
1014 // try to move before the document start
1015 page->triggerAction(QWebPage::MoveToStartOfDocument);
1016 page->triggerAction(QWebPage::MoveToPreviousChar);
1017 QVERIFY(page->isSelectionCollapsed());
1018 QCOMPARE(page->selectionStartOffset(), 0);
1019 page->triggerAction(QWebPage::MoveToStartOfDocument);
1020 page->triggerAction(QWebPage::MoveToPreviousWord);
1021 QVERIFY(page->isSelectionCollapsed());
1022 QCOMPARE(page->selectionStartOffset(), 0);
1024 // try to move past the document end
1025 page->triggerAction(QWebPage::MoveToEndOfDocument);
1026 page->triggerAction(QWebPage::MoveToNextChar);
1027 QVERIFY(page->isSelectionCollapsed());
1028 QCOMPARE(page->selectionStartOffset(), 12);
1029 page->triggerAction(QWebPage::MoveToEndOfDocument);
1030 page->triggerAction(QWebPage::MoveToNextWord);
1031 QVERIFY(page->isSelectionCollapsed());
1032 QCOMPARE(page->selectionStartOffset(), 12);
1037 void tst_QWebPage::textSelection()
1039 CursorTrackedPage* page = new CursorTrackedPage;
1040 QString content("<html><body<p id=one>The quick brown fox</p>" \
1041 "<p id=two>jumps over the lazy dog</p>" \
1042 "<p>May the source<br/>be with you!</p></body></html>");
1043 page->mainFrame()->setHtml(content);
1045 // these actions must exist
1046 QVERIFY(page->action(QWebPage::SelectAll) != 0);
1047 QVERIFY(page->action(QWebPage::SelectNextChar) != 0);
1048 QVERIFY(page->action(QWebPage::SelectPreviousChar) != 0);
1049 QVERIFY(page->action(QWebPage::SelectNextWord) != 0);
1050 QVERIFY(page->action(QWebPage::SelectPreviousWord) != 0);
1051 QVERIFY(page->action(QWebPage::SelectNextLine) != 0);
1052 QVERIFY(page->action(QWebPage::SelectPreviousLine) != 0);
1053 QVERIFY(page->action(QWebPage::SelectStartOfLine) != 0);
1054 QVERIFY(page->action(QWebPage::SelectEndOfLine) != 0);
1055 QVERIFY(page->action(QWebPage::SelectStartOfBlock) != 0);
1056 QVERIFY(page->action(QWebPage::SelectEndOfBlock) != 0);
1057 QVERIFY(page->action(QWebPage::SelectStartOfDocument) != 0);
1058 QVERIFY(page->action(QWebPage::SelectEndOfDocument) != 0);
1060 // right now they are disabled because contentEditable is false and
1061 // there isn't an existing selection to modify
1062 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), false);
1063 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), false);
1064 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), false);
1065 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), false);
1066 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), false);
1067 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), false);
1068 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), false);
1069 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), false);
1070 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), false);
1071 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), false);
1072 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), false);
1073 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), false);
1075 // ..but SelectAll is awalys enabled
1076 QCOMPARE(page->action(QWebPage::SelectAll)->isEnabled(), true);
1078 // this will select the first paragraph
1079 QString selectScript = "var range = document.createRange(); " \
1080 "var node = document.getElementById(\"one\"); " \
1081 "range.selectNode(node); " \
1082 "getSelection().addRange(range);";
1083 page->mainFrame()->evaluateJavaScript(selectScript);
1084 QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox"));
1086 // here the actions are enabled after a selection has been created
1087 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
1088 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
1089 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
1090 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
1091 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
1092 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
1093 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
1094 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
1095 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
1096 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
1097 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
1098 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
1100 // make it editable before navigating the cursor
1101 page->setContentEditable(true);
1103 // cursor will be before the word "The", this makes sure there is a charet
1104 page->triggerAction(QWebPage::MoveToStartOfDocument);
1105 QVERIFY(page->isSelectionCollapsed());
1106 QCOMPARE(page->selectionStartOffset(), 0);
1108 // here the actions are enabled after contentEditable is true
1109 QCOMPARE(page->action(QWebPage::SelectNextChar)->isEnabled(), true);
1110 QCOMPARE(page->action(QWebPage::SelectPreviousChar)->isEnabled(), true);
1111 QCOMPARE(page->action(QWebPage::SelectNextWord)->isEnabled(), true);
1112 QCOMPARE(page->action(QWebPage::SelectPreviousWord)->isEnabled(), true);
1113 QCOMPARE(page->action(QWebPage::SelectNextLine)->isEnabled(), true);
1114 QCOMPARE(page->action(QWebPage::SelectPreviousLine)->isEnabled(), true);
1115 QCOMPARE(page->action(QWebPage::SelectStartOfLine)->isEnabled(), true);
1116 QCOMPARE(page->action(QWebPage::SelectEndOfLine)->isEnabled(), true);
1117 QCOMPARE(page->action(QWebPage::SelectStartOfBlock)->isEnabled(), true);
1118 QCOMPARE(page->action(QWebPage::SelectEndOfBlock)->isEnabled(), true);
1119 QCOMPARE(page->action(QWebPage::SelectStartOfDocument)->isEnabled(), true);
1120 QCOMPARE(page->action(QWebPage::SelectEndOfDocument)->isEnabled(), true);
1125 void tst_QWebPage::textEditing()
1127 CursorTrackedPage* page = new CursorTrackedPage;
1128 QString content("<html><body<p id=one>The quick brown fox</p>" \
1129 "<p id=two>jumps over the lazy dog</p>" \
1130 "<p>May the source<br/>be with you!</p></body></html>");
1131 page->mainFrame()->setHtml(content);
1133 // these actions must exist
1134 QVERIFY(page->action(QWebPage::Cut) != 0);
1135 QVERIFY(page->action(QWebPage::Copy) != 0);
1136 QVERIFY(page->action(QWebPage::Paste) != 0);
1137 QVERIFY(page->action(QWebPage::DeleteStartOfWord) != 0);
1138 QVERIFY(page->action(QWebPage::DeleteEndOfWord) != 0);
1139 QVERIFY(page->action(QWebPage::SetTextDirectionDefault) != 0);
1140 QVERIFY(page->action(QWebPage::SetTextDirectionLeftToRight) != 0);
1141 QVERIFY(page->action(QWebPage::SetTextDirectionRightToLeft) != 0);
1142 QVERIFY(page->action(QWebPage::ToggleBold) != 0);
1143 QVERIFY(page->action(QWebPage::ToggleItalic) != 0);
1144 QVERIFY(page->action(QWebPage::ToggleUnderline) != 0);
1145 QVERIFY(page->action(QWebPage::InsertParagraphSeparator) != 0);
1146 QVERIFY(page->action(QWebPage::InsertLineSeparator) != 0);
1147 QVERIFY(page->action(QWebPage::PasteAndMatchStyle) != 0);
1148 QVERIFY(page->action(QWebPage::RemoveFormat) != 0);
1149 QVERIFY(page->action(QWebPage::ToggleStrikethrough) != 0);
1150 QVERIFY(page->action(QWebPage::ToggleSubscript) != 0);
1151 QVERIFY(page->action(QWebPage::ToggleSuperscript) != 0);
1152 QVERIFY(page->action(QWebPage::InsertUnorderedList) != 0);
1153 QVERIFY(page->action(QWebPage::InsertOrderedList) != 0);
1154 QVERIFY(page->action(QWebPage::Indent) != 0);
1155 QVERIFY(page->action(QWebPage::Outdent) != 0);
1156 QVERIFY(page->action(QWebPage::AlignCenter) != 0);
1157 QVERIFY(page->action(QWebPage::AlignJustified) != 0);
1158 QVERIFY(page->action(QWebPage::AlignLeft) != 0);
1159 QVERIFY(page->action(QWebPage::AlignRight) != 0);
1161 // right now they are disabled because contentEditable is false
1162 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
1163 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), false);
1164 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), false);
1165 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), false);
1166 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), false);
1167 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), false);
1168 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), false);
1169 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), false);
1170 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), false);
1171 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), false);
1172 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), false);
1173 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), false);
1174 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), false);
1175 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
1176 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), false);
1177 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), false);
1178 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), false);
1179 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), false);
1180 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), false);
1181 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), false);
1182 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), false);
1183 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), false);
1184 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), false);
1185 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), false);
1186 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), false);
1188 // Select everything
1189 page->triggerAction(QWebPage::SelectAll);
1191 // make sure it is enabled since there is a selection
1192 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), true);
1194 // make it editable before navigating the cursor
1195 page->setContentEditable(true);
1197 // clear the selection
1198 page->triggerAction(QWebPage::MoveToStartOfDocument);
1199 QVERIFY(page->isSelectionCollapsed());
1200 QCOMPARE(page->selectionStartOffset(), 0);
1202 // make sure it is disabled since there isn't a selection
1203 QCOMPARE(page->action(QWebPage::Copy)->isEnabled(), false);
1205 // here the actions are enabled after contentEditable is true
1206 QCOMPARE(page->action(QWebPage::Paste)->isEnabled(), true);
1207 QCOMPARE(page->action(QWebPage::DeleteStartOfWord)->isEnabled(), true);
1208 QCOMPARE(page->action(QWebPage::DeleteEndOfWord)->isEnabled(), true);
1209 QCOMPARE(page->action(QWebPage::SetTextDirectionDefault)->isEnabled(), true);
1210 QCOMPARE(page->action(QWebPage::SetTextDirectionLeftToRight)->isEnabled(), true);
1211 QCOMPARE(page->action(QWebPage::SetTextDirectionRightToLeft)->isEnabled(), true);
1212 QCOMPARE(page->action(QWebPage::ToggleBold)->isEnabled(), true);
1213 QCOMPARE(page->action(QWebPage::ToggleItalic)->isEnabled(), true);
1214 QCOMPARE(page->action(QWebPage::ToggleUnderline)->isEnabled(), true);
1215 QCOMPARE(page->action(QWebPage::InsertParagraphSeparator)->isEnabled(), true);
1216 QCOMPARE(page->action(QWebPage::InsertLineSeparator)->isEnabled(), true);
1217 QCOMPARE(page->action(QWebPage::PasteAndMatchStyle)->isEnabled(), true);
1218 QCOMPARE(page->action(QWebPage::ToggleStrikethrough)->isEnabled(), true);
1219 QCOMPARE(page->action(QWebPage::ToggleSubscript)->isEnabled(), true);
1220 QCOMPARE(page->action(QWebPage::ToggleSuperscript)->isEnabled(), true);
1221 QCOMPARE(page->action(QWebPage::InsertUnorderedList)->isEnabled(), true);
1222 QCOMPARE(page->action(QWebPage::InsertOrderedList)->isEnabled(), true);
1223 QCOMPARE(page->action(QWebPage::Indent)->isEnabled(), true);
1224 QCOMPARE(page->action(QWebPage::Outdent)->isEnabled(), true);
1225 QCOMPARE(page->action(QWebPage::AlignCenter)->isEnabled(), true);
1226 QCOMPARE(page->action(QWebPage::AlignJustified)->isEnabled(), true);
1227 QCOMPARE(page->action(QWebPage::AlignLeft)->isEnabled(), true);
1228 QCOMPARE(page->action(QWebPage::AlignRight)->isEnabled(), true);
1230 // make sure these are disabled since there isn't a selection
1231 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), false);
1232 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), false);
1234 // make sure everything is selected
1235 page->triggerAction(QWebPage::SelectAll);
1237 // this is only true if there is an editable selection
1238 QCOMPARE(page->action(QWebPage::Cut)->isEnabled(), true);
1239 QCOMPARE(page->action(QWebPage::RemoveFormat)->isEnabled(), true);
1244 void tst_QWebPage::requestCache()
1247 QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool)));
1249 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
1250 QTRY_COMPARE(loadSpy.count(), 1);
1251 QTRY_COMPARE(page.navigations.count(), 1);
1253 page.mainFrame()->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me2</a>"));
1254 QTRY_COMPARE(loadSpy.count(), 2);
1255 QTRY_COMPARE(page.navigations.count(), 2);
1257 page.triggerAction(QWebPage::Stop);
1258 QVERIFY(page.history()->canGoBack());
1259 page.triggerAction(QWebPage::Back);
1261 QTRY_COMPARE(loadSpy.count(), 3);
1262 QTRY_COMPARE(page.navigations.count(), 3);
1263 QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1264 (int)QNetworkRequest::PreferNetwork);
1265 QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1266 (int)QNetworkRequest::PreferNetwork);
1267 QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(),
1268 (int)QNetworkRequest::PreferCache);
1271 void tst_QWebPage::backActionUpdate()
1274 QWebPage *page = view.page();
1275 QAction *action = page->action(QWebPage::Back);
1276 QVERIFY(!action->isEnabled());
1277 QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool)));
1278 QUrl url = QUrl("qrc:///frametest/index.html");
1279 page->mainFrame()->load(url);
1280 QTRY_COMPARE(loadSpy.count(), 1);
1281 QVERIFY(!action->isEnabled());
1282 QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10));
1283 QTRY_COMPARE(loadSpy.count(), 2);
1285 QVERIFY(action->isEnabled());
1288 void frameAtHelper(QWebPage* webPage, QWebFrame* webFrame, QPoint framePosition)
1293 framePosition += QPoint(webFrame->pos());
1294 QList<QWebFrame*> children = webFrame->childFrames();
1295 for (int i = 0; i < children.size(); ++i) {
1296 if (children.at(i)->childFrames().size() > 0)
1297 frameAtHelper(webPage, children.at(i), framePosition);
1299 QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size());
1300 QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft()));
1304 void tst_QWebPage::frameAt()
1307 QWebPage* webPage = webView.page();
1308 QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool)));
1309 QUrl url = QUrl("qrc:///frametest/iframe.html");
1310 webPage->mainFrame()->load(url);
1311 QTRY_COMPARE(loadSpy.count(), 1);
1312 frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos());
1315 void tst_QWebPage::inputMethods_data()
1317 QTest::addColumn<QString>("viewType");
1318 QTest::newRow("QWebView") << "QWebView";
1319 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1320 QTest::newRow("QGraphicsWebView") << "QGraphicsWebView";
1324 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1325 static Qt::InputMethodHints inputMethodHints(QObject* object)
1327 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
1328 return o->inputMethodHints();
1329 if (QWidget* w = qobject_cast<QWidget*>(object))
1330 return w->inputMethodHints();
1331 return Qt::InputMethodHints();
1335 static bool inputMethodEnabled(QObject* object)
1337 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1338 if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object))
1339 return o->flags() & QGraphicsItem::ItemAcceptsInputMethod;
1341 if (QWidget* w = qobject_cast<QWidget*>(object))
1342 return w->testAttribute(Qt::WA_InputMethodEnabled);
1346 void tst_QWebPage::inputMethods()
1348 QFETCH(QString, viewType);
1349 QWebPage* page = new QWebPage;
1351 QObject* container = 0;
1352 if (viewType == "QWebView") {
1353 QWebView* wv = new QWebView;
1358 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1359 else if (viewType == "QGraphicsWebView") {
1360 QGraphicsWebView* wv = new QGraphicsWebView;
1364 QGraphicsView* gv = new QGraphicsView;
1365 QGraphicsScene* scene = new QGraphicsScene(gv);
1366 gv->setScene(scene);
1368 wv->setGeometry(QRect(0, 0, 500, 500));
1374 QVERIFY2(false, "Unknown view type");
1376 page->mainFrame()->setHtml("<html><body>" \
1377 "<input type='text' id='input1' style='font-family: serif' value='' maxlength='20'/><br>" \
1378 "<input type='password'/>" \
1380 page->mainFrame()->setFocus();
1382 EventSpy viewEventSpy(container);
1384 QWebElementCollection inputs = page->mainFrame()->documentElement().findAll("input");
1386 QMouseEvent evpres(QEvent::MouseButtonPress, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1387 page->event(&evpres);
1388 QMouseEvent evrel(QEvent::MouseButtonRelease, inputs.at(0).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1389 page->event(&evrel);
1391 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1392 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1394 viewEventSpy.clear();
1396 page->event(&evpres);
1397 page->event(&evrel);
1399 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1400 QVERIFY(viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1404 QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus);
1405 QRect focusRect = variant.toRect();
1406 QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft()));
1409 variant = page->inputMethodQuery(Qt::ImFont);
1410 QFont font = variant.value<QFont>();
1411 QCOMPARE(QString("-webkit-serif"), font.family());
1413 QList<QInputMethodEvent::Attribute> inputAttributes;
1417 QInputMethodEvent eventText("QtWebKit", inputAttributes);
1418 QSignalSpy signalSpy(page, SIGNAL(microFocusChanged()));
1419 page->event(&eventText);
1420 QCOMPARE(signalSpy.count(), 0);
1424 QInputMethodEvent eventText("", inputAttributes);
1425 eventText.setCommitString(QString("QtWebKit"), 0, 0);
1426 page->event(&eventText);
1429 #if QT_VERSION >= 0x040600
1430 //ImMaximumTextLength
1431 variant = page->inputMethodQuery(Qt::ImMaximumTextLength);
1432 QCOMPARE(20, variant.toInt());
1435 inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant());
1436 QInputMethodEvent eventSelection("",inputAttributes);
1437 page->event(&eventSelection);
1440 variant = page->inputMethodQuery(Qt::ImAnchorPosition);
1441 int anchorPosition = variant.toInt();
1442 QCOMPARE(anchorPosition, 3);
1445 variant = page->inputMethodQuery(Qt::ImCursorPosition);
1446 int cursorPosition = variant.toInt();
1447 QCOMPARE(cursorPosition, 5);
1449 //ImCurrentSelection
1450 variant = page->inputMethodQuery(Qt::ImCurrentSelection);
1451 QString selectionValue = variant.value<QString>();
1452 QCOMPARE(selectionValue, QString("eb"));
1456 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1457 QString value = variant.value<QString>();
1458 QCOMPARE(value, QString("QtWebKit"));
1460 #if QT_VERSION >= 0x040600
1462 QList<QInputMethodEvent::Attribute> attributes;
1463 // Clear the selection, so the next test does not clear any contents.
1464 QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant());
1465 attributes.append(newSelection);
1466 QInputMethodEvent event("composition", attributes);
1467 page->event(&event);
1470 // A ongoing composition should not change the surrounding text before it is committed.
1471 variant = page->inputMethodQuery(Qt::ImSurroundingText);
1472 value = variant.value<QString>();
1473 QCOMPARE(value, QString("QtWebKit"));
1477 QMouseEvent evpresPassword(QEvent::MouseButtonPress, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1478 page->event(&evpresPassword);
1479 QMouseEvent evrelPassword(QEvent::MouseButtonRelease, inputs.at(1).geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1480 page->event(&evrelPassword);
1482 QVERIFY(inputMethodEnabled(view));
1483 #if QT_VERSION >= 0x040600
1484 QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText);
1486 page->event(&evpres);
1487 page->event(&evrel);
1488 QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText));
1491 page->mainFrame()->setHtml("<html><body><p>nothing to input here");
1492 viewEventSpy.clear();
1494 QWebElement para = page->mainFrame()->findFirstElement("p");
1496 QMouseEvent evpres(QEvent::MouseButtonPress, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1497 page->event(&evpres);
1498 QMouseEvent evrel(QEvent::MouseButtonRelease, para.geometry().center(), Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
1499 page->event(&evrel);
1502 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1503 QVERIFY(!viewEventSpy.contains(QEvent::RequestSoftwareInputPanel));
1509 // import a little DRT helper function to trigger the garbage collector
1510 void QWEBKIT_EXPORT qt_drt_garbageCollector_collect();
1512 void tst_QWebPage::protectBindingsRuntimeObjectsFromCollector()
1514 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
1516 PluginPage* newPage = new PluginPage(m_view);
1517 m_view->setPage(newPage);
1519 m_view->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
1521 m_view->setHtml(QString("<html><body><object type='application/x-qt-plugin' classid='lineedit' id='mylineedit'/></body></html>"));
1522 QTRY_COMPARE(loadSpy.count(), 1);
1524 newPage->mainFrame()->evaluateJavaScript("function testme(text) { var lineedit = document.getElementById('mylineedit'); lineedit.setText(text); lineedit.selectAll(); }");
1526 newPage->mainFrame()->evaluateJavaScript("testme('foo')");
1528 qt_drt_garbageCollector_collect();
1531 newPage->mainFrame()->evaluateJavaScript("testme('bar')");
1534 void tst_QWebPage::localURLSchemes()
1536 int i = QWebSecurityOrigin::localSchemes().size();
1537 QWebSecurityOrigin::removeLocalScheme("file");
1538 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
1539 QWebSecurityOrigin::addLocalScheme("file");
1540 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
1541 QString myscheme = "myscheme";
1542 QWebSecurityOrigin::addLocalScheme(myscheme);
1543 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i + 1);
1544 QVERIFY(QWebSecurityOrigin::localSchemes().contains(myscheme));
1545 QWebSecurityOrigin::removeLocalScheme(myscheme);
1546 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
1547 QWebSecurityOrigin::removeLocalScheme(myscheme);
1548 QTRY_COMPARE(QWebSecurityOrigin::localSchemes().size(), i);
1551 static inline bool testFlag(QWebPage& webPage, QWebSettings::WebAttribute settingAttribute, const QString& jsObjectName, bool settingValue)
1553 webPage.settings()->setAttribute(settingAttribute, settingValue);
1554 return webPage.mainFrame()->evaluateJavaScript(QString("(window.%1 != undefined)").arg(jsObjectName)).toBool();
1557 void tst_QWebPage::testOptionalJSObjects()
1559 // Once a feature is enabled and the JS object is accessed turning off the setting will not turn off
1560 // the visibility of the JS object any more. For this reason this test uses two QWebPage instances.
1561 // Part of the test is to make sure that the QWebPage instances do not interfere with each other so turning on
1562 // a feature for one instance will not turn it on for another.
1567 webPage1.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl());
1568 webPage2.currentFrame()->setHtml(QString("<html><body>test</body></html>"), QUrl());
1570 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
1571 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
1572 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", true), true);
1573 QEXPECT_FAIL("","Feature enabled/disabled checking problem. Look at bugs.webkit.org/show_bug.cgi?id=29867", Continue);
1574 QCOMPARE(testFlag(webPage1, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), false);
1575 QCOMPARE(testFlag(webPage2, QWebSettings::OfflineWebApplicationCacheEnabled, "applicationCache", false), true);
1577 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
1578 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", true), true);
1579 QCOMPARE(testFlag(webPage1, QWebSettings::LocalStorageEnabled, "localStorage", false), false);
1580 QCOMPARE(testFlag(webPage2, QWebSettings::LocalStorageEnabled, "localStorage", false), true);
1583 void tst_QWebPage::testEnablePersistentStorage()
1587 // By default all persistent options should be disabled
1588 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), false);
1589 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), false);
1590 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), false);
1591 QVERIFY(webPage.settings()->iconDatabasePath().isEmpty());
1593 QWebSettings::enablePersistentStorage();
1595 // Give it some time to initialize - icon database needs it
1598 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::LocalStorageEnabled), true);
1599 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineStorageDatabaseEnabled), true);
1600 QCOMPARE(webPage.settings()->testAttribute(QWebSettings::OfflineWebApplicationCacheEnabled), true);
1602 QVERIFY(!webPage.settings()->offlineStoragePath().isEmpty());
1603 QVERIFY(!webPage.settings()->offlineWebApplicationCachePath().isEmpty());
1604 QVERIFY(!webPage.settings()->iconDatabasePath().isEmpty());
1607 void tst_QWebPage::defaultTextEncoding()
1609 QWebFrame* mainFrame = m_page->mainFrame();
1611 QString defaultCharset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
1612 QVERIFY(!defaultCharset.isEmpty());
1613 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), defaultCharset);
1615 m_page->settings()->setDefaultTextEncoding(QString("utf-8"));
1616 QString charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
1617 QCOMPARE(charset, QString("utf-8"));
1618 QCOMPARE(m_page->settings()->defaultTextEncoding(), charset);
1620 m_page->settings()->setDefaultTextEncoding(QString());
1621 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
1622 QVERIFY(!charset.isEmpty());
1623 QCOMPARE(charset, defaultCharset);
1625 QWebSettings::globalSettings()->setDefaultTextEncoding(QString("utf-8"));
1626 charset = mainFrame->evaluateJavaScript("document.defaultCharset").toString();
1627 QCOMPARE(charset, QString("utf-8"));
1628 QCOMPARE(QWebSettings::globalSettings()->defaultTextEncoding(), charset);
1631 class ErrorPage : public QWebPage
1635 ErrorPage(QWidget* parent = 0): QWebPage(parent)
1639 virtual bool supportsExtension(Extension extension) const
1641 return extension == ErrorPageExtension;
1644 virtual bool extension(Extension, const ExtensionOption* option, ExtensionReturn* output)
1646 ErrorPageExtensionReturn* errorPage = static_cast<ErrorPageExtensionReturn*>(output);
1648 errorPage->content = "data:text/html,error";
1653 void tst_QWebPage::errorPageExtension()
1655 ErrorPage* page = new ErrorPage;
1656 m_view->setPage(page);
1658 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
1660 m_view->setUrl(QUrl("data:text/html,foo"));
1661 QTRY_COMPARE(spyLoadFinished.count(), 1);
1663 page->mainFrame()->setUrl(QUrl("http://non.existent/url"));
1664 QTRY_COMPARE(spyLoadFinished.count(), 2);
1665 QCOMPARE(page->mainFrame()->toPlainText(), QString("data:text/html,error"));
1666 QCOMPARE(page->history()->count(), 2);
1667 QCOMPARE(page->history()->currentItem().url(), QUrl("http://non.existent/url"));
1668 QCOMPARE(page->history()->canGoBack(), true);
1669 QCOMPARE(page->history()->canGoForward(), false);
1671 page->triggerAction(QWebPage::Back);
1673 QCOMPARE(page->history()->canGoBack(), false);
1674 QCOMPARE(page->history()->canGoForward(), true);
1676 page->triggerAction(QWebPage::Forward);
1678 QCOMPARE(page->history()->canGoBack(), true);
1679 QCOMPARE(page->history()->canGoForward(), false);
1681 page->triggerAction(QWebPage::Back);
1683 QCOMPARE(page->history()->canGoBack(), false);
1684 QCOMPARE(page->history()->canGoForward(), true);
1685 QCOMPARE(page->history()->currentItem().url(), QUrl("data:text/html,foo"));
1690 void tst_QWebPage::errorPageExtensionInIFrames()
1692 ErrorPage* page = new ErrorPage;
1693 m_view->setPage(page);
1695 m_view->setHtml(QString("data:text/html,"
1697 "<iframe src='data:text/html,<p/>p'></iframe>"
1698 "<iframe src='non-existent.html'></iframe>"));
1699 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
1700 QTRY_COMPARE(spyLoadFinished.count(), 1);
1702 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("data:text/html,error"));
1707 void tst_QWebPage::errorPageExtensionInFrameset()
1709 ErrorPage* page = new ErrorPage;
1710 m_view->setPage(page);
1712 m_view->load(QUrl("qrc:///frametest/index.html"));
1714 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
1715 QTRY_COMPARE(spyLoadFinished.count(), 1);
1716 QCOMPARE(page->mainFrame()->childFrames()[1]->toPlainText(), QString("data:text/html,error"));
1721 void tst_QWebPage::crashTests_LazyInitializationOfMainFrame()
1728 webPage.selectedText();
1732 webPage.triggerAction(QWebPage::Back, true);
1737 webPage.updatePositionDependentActions(pos);
1741 static void takeScreenshot(QWebPage* page)
1743 QWebFrame* mainFrame = page->mainFrame();
1744 page->setViewportSize(mainFrame->contentsSize());
1745 QImage image(page->viewportSize(), QImage::Format_ARGB32);
1746 QPainter painter(&image);
1747 mainFrame->render(&painter);
1751 void tst_QWebPage::screenshot_data()
1753 QTest::addColumn<QString>("html");
1754 QTest::newRow("WithoutPlugin") << "<html><body id='b'>text</body></html>";
1755 QTest::newRow("WindowedPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf'></embed></body></html>");
1756 QTest::newRow("WindowlessPlugin") << QString("<html><body id='b'>text<embed src='resources/test.swf' wmode='transparent'></embed></body></html>");
1759 void tst_QWebPage::screenshot()
1761 QDir::setCurrent(SRCDIR);
1763 QFETCH(QString, html);
1764 QWebPage* page = new QWebPage;
1765 page->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
1766 QWebFrame* mainFrame = page->mainFrame();
1767 mainFrame->setHtml(html, QUrl::fromLocalFile(QDir::currentPath()));
1768 if (html.contains("</embed>")) {
1769 // some reasonable time for the PluginStream to feed test.swf to flash and start painting
1773 // take screenshot without a view
1774 takeScreenshot(page);
1776 QWebView* view = new QWebView;
1777 view->setPage(page);
1779 // take screenshot when attached to a view
1780 takeScreenshot(page);
1785 QDir::setCurrent(QApplication::applicationDirPath());
1788 void tst_QWebPage::originatingObjectInNetworkRequests()
1790 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
1791 m_page->setNetworkAccessManager(networkManager);
1792 networkManager->requests.clear();
1794 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
1795 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
1796 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
1797 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
1799 QCOMPARE(networkManager->requests.count(), 2);
1801 QList<QWebFrame*> childFrames = m_page->mainFrame()->childFrames();
1802 QCOMPARE(childFrames.count(), 2);
1804 #if QT_VERSION >= QT_VERSION_CHECK(4, 6, 0)
1805 for (int i = 0; i < 2; ++i)
1806 QVERIFY(qobject_cast<QWebFrame*>(networkManager->requests.at(i).originatingObject()) == childFrames.at(i));
1810 QTEST_MAIN(tst_QWebPage)
1811 #include "tst_qwebpage.moc"