2 Copyright (C) 2008 Trolltech ASA
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
21 #include <QtTest/QtTest>
26 #include <qwebframe.h>
27 #include <qwebhistory.h>
28 #include <qnetworkrequest.h>
32 // Will try to wait for the condition while allowing event processing
33 #define QTRY_COMPARE(__expr, __expected) \
35 const int __step = 50; \
36 const int __timeout = 5000; \
37 if ((__expr) != (__expected)) { \
40 for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
41 QTest::qWait(__step); \
43 QCOMPARE(__expr, __expected); \
51 * Starts an event loop that runs until the given signal is received.
52 Optionally the event loop
53 * can return earlier on a timeout.
55 * \return \p true if the requested signal was received
58 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
61 QObject::connect(obj, signal, &loop, SLOT(quit()));
63 QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
65 QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
66 timer.setSingleShot(true);
70 return timeoutSpy.isEmpty();
73 class tst_QWebPage : public QObject
79 virtual ~tst_QWebPage();
86 void acceptNavigationRequest();
88 void acceptNavigationRequestWithNewWindow();
89 void userStyleSheet();
91 void contextMenuCrash();
101 tst_QWebPage::tst_QWebPage()
105 tst_QWebPage::~tst_QWebPage()
109 void tst_QWebPage::init()
111 m_view = new QWebView();
112 m_page = m_view->page();
115 void tst_QWebPage::cleanup()
120 class NavigationRequestOverride : public QWebPage
123 NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
125 bool m_acceptNavigationRequest;
127 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
132 return m_acceptNavigationRequest;
136 void tst_QWebPage::acceptNavigationRequest()
138 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
140 NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
141 m_view->setPage(newPage);
143 m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
144 "<input type='text'><input type='submit'></form></body></html>"), QUrl());
145 QTRY_COMPARE(loadSpy.count(), 1);
147 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
149 newPage->m_acceptNavigationRequest = true;
150 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
151 QTRY_COMPARE(loadSpy.count(), 2);
153 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
155 // Restore default page
160 void tst_QWebPage::loadFinished()
162 QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
163 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
165 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
166 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
167 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
168 QTRY_COMPARE(spyLoadFinished.count(), 1);
172 QVERIFY(spyLoadStarted.count() > 1);
173 QVERIFY(spyLoadFinished.count() > 1);
175 spyLoadFinished.clear();
177 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
178 "foo \"><frame src=\"data:text/html,bar\"></frameset>"), QUrl());
179 QTRY_COMPARE(spyLoadFinished.count(), 1);
180 QCOMPARE(spyLoadFinished.count(), 1);
183 class TestPage : public QWebPage
186 TestPage(QObject* parent = 0) : QWebPage(parent) {}
189 QPointer<QWebFrame> frame;
190 QNetworkRequest request;
194 QList<Navigation> navigations;
195 QList<QWebPage*> createdWindows;
197 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
202 navigations.append(n);
206 virtual QWebPage* createWindow(WebWindowType type) {
207 QWebPage* page = new TestPage(this);
208 createdWindows.append(page);
213 void tst_QWebPage::acceptNavigationRequestWithNewWindow()
215 TestPage* page = new TestPage(m_view);
216 page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
218 m_view->setPage(m_page);
220 m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
221 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
223 QFocusEvent fe(QEvent::FocusIn);
226 QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
228 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
229 m_page->event(&keyEnter);
231 QCOMPARE(page->navigations.count(), 2);
233 TestPage::Navigation n = page->navigations.at(1);
234 QVERIFY(n.frame.isNull());
235 QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached"));
236 QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked);
238 QCOMPARE(page->createdWindows.count(), 1);
241 class TestNetworkManager : public QNetworkAccessManager
244 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
246 QList<QUrl> requestedUrls;
249 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
250 requestedUrls.append(request.url());
251 return QNetworkAccessManager::createRequest(op, request, outgoingData);
255 void tst_QWebPage::userStyleSheet()
257 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
258 m_page->setNetworkAccessManager(networkManager);
259 networkManager->requestedUrls.clear();
261 m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css,p { background-image: url('http://does.not/exist.png');}"));
262 m_view->setHtml("<p>hello world</p>");
263 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
265 QVERIFY(networkManager->requestedUrls.count() >= 2);
266 QCOMPARE(networkManager->requestedUrls.at(0), QUrl("data:text/css,p { background-image: url('http://does.not/exist.png');}"));
267 QCOMPARE(networkManager->requestedUrls.at(1), QUrl("http://does.not/exist.png"));
270 void tst_QWebPage::modified()
272 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
273 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
275 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
276 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
278 QVERIFY(!m_page->isModified());
280 // m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))");
281 m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()");
282 m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');");
284 QVERIFY(m_page->isModified());
286 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
288 QVERIFY(!m_page->isModified());
290 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
292 QVERIFY(m_page->isModified());
294 QVERIFY(m_page->history()->canGoBack());
295 QVERIFY(!m_page->history()->canGoForward());
296 QCOMPARE(m_page->history()->count(), 2);
297 m_page->history()->back();
298 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
300 QVERIFY(!m_page->history()->canGoBack());
301 QVERIFY(m_page->history()->canGoForward());
303 QVERIFY(!m_page->isModified());
306 void tst_QWebPage::contextMenuCrash()
309 view.setHtml("<p>test");
310 view.page()->updatePositionDependentActions(QPoint(0, 0));
311 QMenu* contextMenu = 0;
312 foreach (QObject* child, view.children()) {
313 contextMenu = qobject_cast<QMenu*>(child);
317 QVERIFY(contextMenu);
321 QTEST_MAIN(tst_QWebPage)
322 #include "tst_qwebpage.moc"