622e9fbeeaaffd41afa04c9ee714cd69de02926e
[WebKit-https.git] / WebKit / qt / tests / qwebpage / tst_qwebpage.cpp
1 /*
2     Copyright (C) 2008 Trolltech ASA
3
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.
8
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.
13
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.
18 */
19
20
21 #include <QtTest/QtTest>
22
23 #include <qwebpage.h>
24 #include <qwidget.h>
25 #include <qwebview.h>
26 #include <qwebframe.h>
27 #include <qwebhistory.h>
28 #include <qnetworkrequest.h>
29 #include <QDebug>
30
31 // Will try to wait for the condition while allowing event processing
32 #define QTRY_COMPARE(__expr, __expected) \
33     do { \
34         const int __step = 50; \
35         const int __timeout = 5000; \
36         if ((__expr) != (__expected)) { \
37             QTest::qWait(0); \
38         } \
39         for (int __i = 0; __i < __timeout && ((__expr) != (__expected)); __i+=__step) { \
40             QTest::qWait(__step); \
41         } \
42         QCOMPARE(__expr, __expected); \
43     } while(0)
44
45 //TESTED_CLASS=
46 //TESTED_FILES=
47
48 // Task 160192
49 /**
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.
53  *
54  * \return \p true if the requested signal was received
55  *         \p false on timeout
56  */
57 static bool waitForSignal(QObject* obj, const char* signal, int timeout = 0)
58 {
59     QEventLoop loop;
60     QObject::connect(obj, signal, &loop, SLOT(quit()));
61     QTimer timer;
62     QSignalSpy timeoutSpy(&timer, SIGNAL(timeout()));
63     if (timeout > 0) {
64         QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));
65         timer.setSingleShot(true);
66         timer.start(timeout);
67     }
68     loop.exec();
69     return timeoutSpy.isEmpty();
70 }
71
72 class tst_QWebPage : public QObject
73 {
74     Q_OBJECT
75
76 public:
77     tst_QWebPage();
78     virtual ~tst_QWebPage();
79
80 public slots:
81     void init();
82     void cleanup();
83
84 private slots:
85     void acceptNavigationRequest();
86     void loadFinished();
87     void acceptNavigationRequestWithNewWindow();
88     void userStyleSheet();
89     void modified();
90
91 private:
92
93
94 private:
95     QWebView* m_view;
96     QWebPage* m_page;
97 };
98
99 tst_QWebPage::tst_QWebPage()
100 {
101 }
102
103 tst_QWebPage::~tst_QWebPage()
104 {
105 }
106
107 void tst_QWebPage::init()
108 {
109     m_view = new QWebView();
110     m_page = m_view->page();
111 }
112
113 void tst_QWebPage::cleanup()
114 {
115     delete m_view;
116 }
117
118 class NavigationRequestOverride : public QWebPage
119 {
120 public:
121     NavigationRequestOverride(QWebView* parent, bool initialValue) : QWebPage(parent), m_acceptNavigationRequest(initialValue) {}
122
123     bool m_acceptNavigationRequest;
124 protected:
125     virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, QWebPage::NavigationType type) {
126         Q_UNUSED(frame);
127         Q_UNUSED(request);
128         Q_UNUSED(type);
129
130         return m_acceptNavigationRequest;
131     }
132 };
133
134 void tst_QWebPage::acceptNavigationRequest()
135 {
136     QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
137
138     NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false);
139     m_view->setPage(newPage);
140
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);
144
145     m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
146
147     newPage->m_acceptNavigationRequest = true;
148     m_view->page()->mainFrame()->evaluateJavaScript("tstform.submit();");
149     QTRY_COMPARE(loadSpy.count(), 2);
150
151     QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("foo?"));
152
153     // Restore default page
154     m_view->setPage(0);
155 }
156
157
158 void tst_QWebPage::loadFinished()
159 {
160     QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted()));
161     QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool)));
162
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);
167
168     QTest::qWait(3000);
169
170     QVERIFY(spyLoadStarted.count() > 1);
171     QVERIFY(spyLoadFinished.count() > 1);
172
173     spyLoadFinished.clear();
174
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);
179 }
180
181 class TestPage : public QWebPage
182 {
183 public:
184     TestPage(QObject* parent = 0) : QWebPage(parent) {}
185
186     struct Navigation {
187         QPointer<QWebFrame> frame;
188         QNetworkRequest request;
189         NavigationType type;
190     };
191
192     QList<Navigation> navigations;
193     QList<QWebPage*> createdWindows;
194
195     virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest &request, NavigationType type) {
196         Navigation n;
197         n.frame = frame;
198         n.request = request;
199         n.type = type;
200         navigations.append(n);
201         return true;
202     }
203
204     virtual QWebPage* createWindow(WebWindowType type) {
205         QWebPage* page = new TestPage(this);
206         createdWindows.append(page);
207         return page;
208     }
209 };
210
211 void tst_QWebPage::acceptNavigationRequestWithNewWindow()
212 {
213     TestPage* page = new TestPage;
214     page->settings()->setAttribute(QWebSettings::LinksIncludedInFocusChain, true);
215     m_page = page;
216     m_view->setPage(m_page);
217
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))));
220
221     QFocusEvent fe(QEvent::FocusIn);
222     m_page->event(&fe);
223
224     QVERIFY(m_page->focusNextPrevChild(/*next*/ true));
225
226     QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
227     m_page->event(&keyEnter);
228
229     QCOMPARE(page->navigations.count(), 2);
230
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);
235
236     QCOMPARE(page->createdWindows.count(), 1);
237 }
238
239 class TestNetworkManager : public QNetworkAccessManager
240 {
241 public:
242     TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {}
243
244     QList<QUrl> requestedUrls;
245
246 protected:
247     virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) {
248         requestedUrls.append(request.url());
249         return QNetworkAccessManager::createRequest(op, request, outgoingData);
250     }
251 };
252
253 void tst_QWebPage::userStyleSheet()
254 {
255     TestNetworkManager* networkManager = new TestNetworkManager(m_page);
256     m_page->setNetworkAccessManager(networkManager);
257     networkManager->requestedUrls.clear();
258
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))));
262
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"));
266 }
267
268 void tst_QWebPage::modified()
269 {
270     m_page->mainFrame()->setUrl(QUrl("data:text/html,<body>blub"));
271     QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
272
273     m_page->mainFrame()->setUrl(QUrl("data:text/html,<body id=foo contenteditable>blah"));
274     QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool))));
275
276     QVERIFY(!m_page->isModified());
277
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');");
281
282     QVERIFY(m_page->isModified());
283
284     m_page->mainFrame()->evaluateJavaScript("document.execCommand('Undo', true);");
285
286     QVERIFY(!m_page->isModified());
287
288     m_page->mainFrame()->evaluateJavaScript("document.execCommand('Redo', true);");
289
290     QVERIFY(m_page->isModified());
291
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))));
297
298     QVERIFY(!m_page->history()->canGoBack());
299     QVERIFY(m_page->history()->canGoForward());
300
301     QVERIFY(!m_page->isModified());
302 }
303
304 QTEST_MAIN(tst_QWebPage)
305 #include "tst_qwebpage.moc"