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>
31 // Will try to wait for the condition while allowing event processing
32 #define QTRY_COMPARE(__expr, __expected) \
34 const int __step = 50; \
35 const int __timeout = 5000; \
36 if ((__expr) != (__expected)) { \
39 for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
40 QTest::qWait(__step); \
42 QCOMPARE(__expr, __expected); \
50 * Starts an event loop that runs until the given signal is received.
51 Optionally the event loop
52 * can return earlier on a timeout.
54 * \return \p true if the requested signal was received
57 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
60 QObject::connect(obj, signal, &loop, SLOT(quit()));
62 QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
64 QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
65 timer.setSingleShot(true);
69 return timeoutSpy.isEmpty();
72 class tst_QWebPage : public QObject
78 virtual ~tst_QWebPage();
85 void acceptNavigationRequest();
87 void acceptNavigationRequestWithNewWindow();
88 void userStyleSheet();
99 tst_QWebPage::tst_QWebPage()
103 tst_QWebPage::~tst_QWebPage()
107 void tst_QWebPage::init()
109 m_view = new QWebView();
110 m_page = m_view->page();
113 void tst_QWebPage::cleanup()
118 class NavigationRequestOverride : public QWebPage
121 NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
123 bool m_acceptNavigationRequest;
125 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
130 return m_acceptNavigationRequest;
134 void tst_QWebPage::acceptNavigationRequest()
136 QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
138 NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
139 m_view->setPage(newPage);
141 m_view->setHtml(QString("<html><body><form name='tstform' action='data:text/html,foo'method='get'>"
142 "<input type='text'><input type='submit'></form></body></html>"), QUrl());
143 QTRY_COMPARE(loadSpy.count(), 1);
145 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
147 newPage->m_acceptNavigationRequest = true;
148 m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
149 QTRY_COMPARE(loadSpy.count(), 2);
151 QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
153 // Restore default page
158 void tst_QWebPage::loadFinished()
160 QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
161 QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
163 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
164 "<head><meta http-equiv='refresh' content='1'></head>foo \">"
165 "<frame src=\"data:text/html,bar\"></frameset>"), QUrl());
166 QTRY_COMPARE(spyLoadFinished.count(), 1);
170 QVERIFY(spyLoadStarted.count() > 1);
171 QVERIFY(spyLoadFinished.count() > 1);
173 spyLoadFinished.clear();
175 m_view->setHtml(QString("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html,"
176 "foo \"><frame src=\"data:text/html,bar\"></frameset>"), QUrl());
177 QTRY_COMPARE(spyLoadFinished.count(), 1);
178 QCOMPARE(spyLoadFinished.count(), 1);
181 class TestPage : public QWebPage
184 TestPage(QObject* parent = 0) : QWebPage(parent) {}
187 QPointer<QWebFrame> frame;
188 QNetworkRequest request;
192 QList<Navigation> navigations;
193 QList<QWebPage*> createdWindows;
195 virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
200 navigations.append(n);
204 virtual QWebPage* createWindow(WebWindowType type) {
205 QWebPage* page = new TestPage(this);
206 createdWindows.append(page);
211 void tst_QWebPage::acceptNavigationRequestWithNewWindow()
213 TestPage* page = new TestPage;
214 page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
216 m_view->setPage(m_page);
218 m_view->setUrl(QString("data:text/html,<a href=\"data:text/html,Reached\" target=\"_blank\">Click me</a>"));
219 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
221 QFocusEvent fe(QEvent::FocusIn);
224 QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
226 QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
227 m_page->event(&keyEnter);
229 QCOMPARE(page->navigations.count(), 2);
231 TestPage::Navigation n = page->navigations.at(1);
232 QVERIFY(n.frame.isNull());
233 QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached"));
234 QVERIFY(n.type == QWebPage::NavigationTypeLinkClicked);
236 QCOMPARE(page->createdWindows.count(), 1);
239 class TestNetworkManager : public QNetworkAccessManager
242 TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
244 QList<QUrl> requestedUrls;
247 virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
248 requestedUrls.append(request.url());
249 return QNetworkAccessManager::createRequest(op, request, outgoingData);
253 void tst_QWebPage::userStyleSheet()
255 TestNetworkManager* networkManager = new TestNetworkManager(m_page);
256 m_page->setNetworkAccessManager(networkManager);
257 networkManager->requestedUrls.clear();
259 m_page->settings()->setUserStyleSheetUrl(QUrl::fromEncoded("data:text/css,p { background-image: url(qrc:/does/not/exist.png);}"));
260 m_view->setHtml("<p>hello world</p>");
261 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
263 QCOMPARE(networkManager->requestedUrls.count(), 2);
264 QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("data:text/css,p { background-image: url(qrc:/does/not/exist.png);}"));
265 QCOMPARE(networkManager->requestedUrls.at(1), QUrl::fromEncoded("qrc:/does/not/exist.png"));
268 void tst_QWebPage::modified()
270 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
271 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
273 m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
274 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
276 QVERIFY(!m_page->isModified());
278 // m_page->mainFrame()->evaluateJavaScript("alert(document.getElementById('foo'))");
279 m_page->mainFrame()->evaluateJavaScript("document.getElementById('foo').focus()");
280 m_page->mainFrame()->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');");
282 QVERIFY(m_page->isModified());
284 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
286 QVERIFY(!m_page->isModified());
288 m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
290 QVERIFY(m_page->isModified());
292 QVERIFY(m_page->history()->canGoBack());
293 QVERIFY(!m_page->history()->canGoForward());
294 QCOMPARE(m_page->history()->count(), 2);
295 m_page->history()->back();
296 QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
298 QVERIFY(!m_page->history()->canGoBack());
299 QVERIFY(m_page->history()->canGoForward());
301 QVERIFY(!m_page->isModified());
304 QTEST_MAIN(tst_QWebPage)
305 #include "tst_qwebpage.moc"