From 338e24b48601a3cfdcde0977b6c9390d33d51c9f Mon Sep 17 00:00:00 2001 From: Adam Kallai Date: Mon, 14 Oct 2013 05:57:02 -0700 Subject: Turn on to run all widgets tests by make check. Move widgets test to tests/auto. Change-Id: If3617d86ea44f665a44a54b6ba57935b69220a9e Reviewed-by: Jocelyn Turcotte Reviewed-by: Andras Becsi --- .../widgets/qwebengineframe/qwebengineframe.pro | 2 + .../widgets/qwebengineframe/resources/image.png | Bin 0 -> 14743 bytes .../widgets/qwebengineframe/resources/style.css | 1 + .../widgets/qwebengineframe/resources/test1.html | 1 + .../widgets/qwebengineframe/resources/test2.html | 1 + .../qwebengineframe/resources/testiframe.html | 53 + .../qwebengineframe/resources/testiframe2.html | 20 + .../qwebengineframe/tst_qwebengineframe.cpp | 1569 +++++++++ .../qwebengineframe/tst_qwebengineframe.qrc | 10 + .../qwebenginehistory/qwebenginehistory.pro | 2 + .../widgets/qwebenginehistory/resources/page1.html | 1 + .../widgets/qwebenginehistory/resources/page2.html | 1 + .../widgets/qwebenginehistory/resources/page3.html | 1 + .../widgets/qwebenginehistory/resources/page4.html | 1 + .../widgets/qwebenginehistory/resources/page5.html | 1 + .../widgets/qwebenginehistory/resources/page6.html | 1 + .../qwebenginehistory/tst_qwebenginehistory.cpp | 574 ++++ .../qwebenginehistory/tst_qwebenginehistory.qrc | 10 + .../qwebenginehistoryinterface.pro | 2 + .../tst_qwebenginehistoryinterface.cpp | 98 + .../qwebengineinspector/qwebengineinspector.pro | 2 + .../tst_qwebengineinspector.cpp | 87 + .../auto/widgets/qwebenginepage/qwebenginepage.pro | 3 + .../widgets/qwebenginepage/resources/content.html | 5 + .../widgets/qwebenginepage/resources/frame_a.html | 2 + .../widgets/qwebenginepage/resources/frame_c.html | 1 + .../qwebenginepage/resources/framedindex.html | 6 + .../widgets/qwebenginepage/resources/iframe.html | 6 + .../widgets/qwebenginepage/resources/iframe2.html | 6 + .../widgets/qwebenginepage/resources/iframe3.html | 5 + .../widgets/qwebenginepage/resources/index.html | 6 + .../widgets/qwebenginepage/resources/script.html | 3 + .../auto/widgets/qwebenginepage/resources/user.css | 3 + .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 3628 ++++++++++++++++++++ .../widgets/qwebenginepage/tst_qwebenginepage.qrc | 14 + .../auto/widgets/qwebengineview/qwebengineview.pro | 2 + .../widgets/qwebengineview/resources/frame_a.html | 2 + .../widgets/qwebengineview/resources/index.html | 4 + .../qwebengineview/resources/input_types.html | 9 + .../qwebengineview/resources/scrolltest_page.html | 6 + .../widgets/qwebengineview/tst_qwebengineview.cpp | 552 +++ .../widgets/qwebengineview/tst_qwebengineview.qrc | 8 + tests/auto/widgets/resources/image2.png | Bin 0 -> 14743 bytes tests/auto/widgets/resources/test.swf | Bin 0 -> 10085 bytes tests/auto/widgets/tests.pri | 24 + tests/auto/widgets/util.h | 81 + tests/auto/widgets/widgets.pro | 12 + tests/widgets/qwebengineframe/qwebengineframe.pro | 2 - tests/widgets/qwebengineframe/resources/image.png | Bin 14743 -> 0 bytes tests/widgets/qwebengineframe/resources/style.css | 1 - tests/widgets/qwebengineframe/resources/test1.html | 1 - tests/widgets/qwebengineframe/resources/test2.html | 1 - .../qwebengineframe/resources/testiframe.html | 53 - .../qwebengineframe/resources/testiframe2.html | 20 - .../qwebengineframe/tst_qwebengineframe.cpp | 1569 --------- .../qwebengineframe/tst_qwebengineframe.qrc | 10 - .../qwebenginehistory/qwebenginehistory.pro | 2 - .../widgets/qwebenginehistory/resources/page1.html | 1 - .../widgets/qwebenginehistory/resources/page2.html | 1 - .../widgets/qwebenginehistory/resources/page3.html | 1 - .../widgets/qwebenginehistory/resources/page4.html | 1 - .../widgets/qwebenginehistory/resources/page5.html | 1 - .../widgets/qwebenginehistory/resources/page6.html | 1 - .../qwebenginehistory/tst_qwebenginehistory.cpp | 574 ---- .../qwebenginehistory/tst_qwebenginehistory.qrc | 10 - .../qwebenginehistoryinterface.pro | 2 - .../tst_qwebenginehistoryinterface.cpp | 98 - .../qwebengineinspector/qwebengineinspector.pro | 2 - .../tst_qwebengineinspector.cpp | 87 - tests/widgets/qwebenginepage/qwebenginepage.pro | 3 - .../widgets/qwebenginepage/resources/content.html | 5 - .../widgets/qwebenginepage/resources/frame_a.html | 2 - .../widgets/qwebenginepage/resources/frame_c.html | 1 - .../qwebenginepage/resources/framedindex.html | 6 - tests/widgets/qwebenginepage/resources/iframe.html | 6 - .../widgets/qwebenginepage/resources/iframe2.html | 6 - .../widgets/qwebenginepage/resources/iframe3.html | 5 - tests/widgets/qwebenginepage/resources/index.html | 6 - tests/widgets/qwebenginepage/resources/script.html | 3 - tests/widgets/qwebenginepage/resources/user.css | 3 - .../widgets/qwebenginepage/tst_qwebenginepage.cpp | 3628 -------------------- .../widgets/qwebenginepage/tst_qwebenginepage.qrc | 14 - tests/widgets/qwebengineview/qwebengineview.pro | 2 - .../widgets/qwebengineview/resources/frame_a.html | 2 - tests/widgets/qwebengineview/resources/index.html | 4 - .../qwebengineview/resources/input_types.html | 9 - .../qwebengineview/resources/scrolltest_page.html | 6 - .../widgets/qwebengineview/tst_qwebengineview.cpp | 552 --- .../widgets/qwebengineview/tst_qwebengineview.qrc | 8 - tests/widgets/resources/image2.png | Bin 14743 -> 0 bytes tests/widgets/resources/test.swf | Bin 10085 -> 0 bytes tests/widgets/tests.pri | 23 - tests/widgets/util.h | 81 - tests/widgets/widgets.pro | 12 - 94 files changed, 6826 insertions(+), 6825 deletions(-) create mode 100644 tests/auto/widgets/qwebengineframe/qwebengineframe.pro create mode 100644 tests/auto/widgets/qwebengineframe/resources/image.png create mode 100644 tests/auto/widgets/qwebengineframe/resources/style.css create mode 100644 tests/auto/widgets/qwebengineframe/resources/test1.html create mode 100644 tests/auto/widgets/qwebengineframe/resources/test2.html create mode 100644 tests/auto/widgets/qwebengineframe/resources/testiframe.html create mode 100644 tests/auto/widgets/qwebengineframe/resources/testiframe2.html create mode 100644 tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp create mode 100644 tests/auto/widgets/qwebengineframe/tst_qwebengineframe.qrc create mode 100644 tests/auto/widgets/qwebenginehistory/qwebenginehistory.pro create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page1.html create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page2.html create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page3.html create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page4.html create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page5.html create mode 100644 tests/auto/widgets/qwebenginehistory/resources/page6.html create mode 100644 tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp create mode 100644 tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.qrc create mode 100644 tests/auto/widgets/qwebenginehistoryinterface/qwebenginehistoryinterface.pro create mode 100644 tests/auto/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp create mode 100644 tests/auto/widgets/qwebengineinspector/qwebengineinspector.pro create mode 100644 tests/auto/widgets/qwebengineinspector/tst_qwebengineinspector.cpp create mode 100644 tests/auto/widgets/qwebenginepage/qwebenginepage.pro create mode 100644 tests/auto/widgets/qwebenginepage/resources/content.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/frame_a.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/frame_c.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/framedindex.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/iframe.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/iframe2.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/iframe3.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/index.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/script.html create mode 100644 tests/auto/widgets/qwebenginepage/resources/user.css create mode 100644 tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp create mode 100644 tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc create mode 100644 tests/auto/widgets/qwebengineview/qwebengineview.pro create mode 100644 tests/auto/widgets/qwebengineview/resources/frame_a.html create mode 100644 tests/auto/widgets/qwebengineview/resources/index.html create mode 100644 tests/auto/widgets/qwebengineview/resources/input_types.html create mode 100644 tests/auto/widgets/qwebengineview/resources/scrolltest_page.html create mode 100644 tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp create mode 100644 tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc create mode 100644 tests/auto/widgets/resources/image2.png create mode 100644 tests/auto/widgets/resources/test.swf create mode 100644 tests/auto/widgets/tests.pri create mode 100644 tests/auto/widgets/util.h create mode 100644 tests/auto/widgets/widgets.pro delete mode 100644 tests/widgets/qwebengineframe/qwebengineframe.pro delete mode 100644 tests/widgets/qwebengineframe/resources/image.png delete mode 100644 tests/widgets/qwebengineframe/resources/style.css delete mode 100644 tests/widgets/qwebengineframe/resources/test1.html delete mode 100644 tests/widgets/qwebengineframe/resources/test2.html delete mode 100644 tests/widgets/qwebengineframe/resources/testiframe.html delete mode 100644 tests/widgets/qwebengineframe/resources/testiframe2.html delete mode 100644 tests/widgets/qwebengineframe/tst_qwebengineframe.cpp delete mode 100644 tests/widgets/qwebengineframe/tst_qwebengineframe.qrc delete mode 100644 tests/widgets/qwebenginehistory/qwebenginehistory.pro delete mode 100644 tests/widgets/qwebenginehistory/resources/page1.html delete mode 100644 tests/widgets/qwebenginehistory/resources/page2.html delete mode 100644 tests/widgets/qwebenginehistory/resources/page3.html delete mode 100644 tests/widgets/qwebenginehistory/resources/page4.html delete mode 100644 tests/widgets/qwebenginehistory/resources/page5.html delete mode 100644 tests/widgets/qwebenginehistory/resources/page6.html delete mode 100644 tests/widgets/qwebenginehistory/tst_qwebenginehistory.cpp delete mode 100644 tests/widgets/qwebenginehistory/tst_qwebenginehistory.qrc delete mode 100644 tests/widgets/qwebenginehistoryinterface/qwebenginehistoryinterface.pro delete mode 100644 tests/widgets/qwebenginehistoryinterface/tst_qwebenginehistoryinterface.cpp delete mode 100644 tests/widgets/qwebengineinspector/qwebengineinspector.pro delete mode 100644 tests/widgets/qwebengineinspector/tst_qwebengineinspector.cpp delete mode 100644 tests/widgets/qwebenginepage/qwebenginepage.pro delete mode 100644 tests/widgets/qwebenginepage/resources/content.html delete mode 100644 tests/widgets/qwebenginepage/resources/frame_a.html delete mode 100644 tests/widgets/qwebenginepage/resources/frame_c.html delete mode 100644 tests/widgets/qwebenginepage/resources/framedindex.html delete mode 100644 tests/widgets/qwebenginepage/resources/iframe.html delete mode 100644 tests/widgets/qwebenginepage/resources/iframe2.html delete mode 100644 tests/widgets/qwebenginepage/resources/iframe3.html delete mode 100644 tests/widgets/qwebenginepage/resources/index.html delete mode 100644 tests/widgets/qwebenginepage/resources/script.html delete mode 100644 tests/widgets/qwebenginepage/resources/user.css delete mode 100644 tests/widgets/qwebenginepage/tst_qwebenginepage.cpp delete mode 100644 tests/widgets/qwebenginepage/tst_qwebenginepage.qrc delete mode 100644 tests/widgets/qwebengineview/qwebengineview.pro delete mode 100644 tests/widgets/qwebengineview/resources/frame_a.html delete mode 100644 tests/widgets/qwebengineview/resources/index.html delete mode 100644 tests/widgets/qwebengineview/resources/input_types.html delete mode 100644 tests/widgets/qwebengineview/resources/scrolltest_page.html delete mode 100644 tests/widgets/qwebengineview/tst_qwebengineview.cpp delete mode 100644 tests/widgets/qwebengineview/tst_qwebengineview.qrc delete mode 100644 tests/widgets/resources/image2.png delete mode 100644 tests/widgets/resources/test.swf delete mode 100644 tests/widgets/tests.pri delete mode 100644 tests/widgets/util.h delete mode 100644 tests/widgets/widgets.pro (limited to 'tests') diff --git a/tests/auto/widgets/qwebengineframe/qwebengineframe.pro b/tests/auto/widgets/qwebengineframe/qwebengineframe.pro new file mode 100644 index 000000000..ff6c49628 --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/qwebengineframe.pro @@ -0,0 +1,2 @@ +include(../tests.pri) +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc diff --git a/tests/auto/widgets/qwebengineframe/resources/image.png b/tests/auto/widgets/qwebengineframe/resources/image.png new file mode 100644 index 000000000..8d703640c Binary files /dev/null and b/tests/auto/widgets/qwebengineframe/resources/image.png differ diff --git a/tests/auto/widgets/qwebengineframe/resources/style.css b/tests/auto/widgets/qwebengineframe/resources/style.css new file mode 100644 index 000000000..c05b747f1 --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/resources/style.css @@ -0,0 +1 @@ +#idP {color: red !important} diff --git a/tests/auto/widgets/qwebengineframe/resources/test1.html b/tests/auto/widgets/qwebengineframe/resources/test1.html new file mode 100644 index 000000000..b323f966e --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/resources/test1.html @@ -0,0 +1 @@ +

Some text 1

diff --git a/tests/auto/widgets/qwebengineframe/resources/test2.html b/tests/auto/widgets/qwebengineframe/resources/test2.html new file mode 100644 index 000000000..63ac1f6ec --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/resources/test2.html @@ -0,0 +1 @@ +

Some text 2

diff --git a/tests/auto/widgets/qwebengineframe/resources/testiframe.html b/tests/auto/widgets/qwebengineframe/resources/testiframe.html new file mode 100644 index 000000000..4b0e30ca5 --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/resources/testiframe.html @@ -0,0 +1,53 @@ + + + + + + + +
You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. +You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. +You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. +You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. +You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. +You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
+ + + + \ No newline at end of file diff --git a/tests/auto/widgets/qwebengineframe/resources/testiframe2.html b/tests/auto/widgets/qwebengineframe/resources/testiframe2.html new file mode 100644 index 000000000..8957a5d8a --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/resources/testiframe2.html @@ -0,0 +1,20 @@ + + + + + + +
+ + \ No newline at end of file diff --git a/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp b/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp new file mode 100644 index 000000000..11281082b --- /dev/null +++ b/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp @@ -0,0 +1,1569 @@ +/* + Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef QT_NO_OPENSSL +#include +#endif +#include "../util.h" + +class tst_QWebEngineFrame : public QObject +{ + Q_OBJECT + +public: + bool eventFilter(QObject* watched, QEvent* event); + +public Q_SLOTS: + void init(); + void cleanup(); + +private Q_SLOTS: + void horizontalScrollAfterBack(); + void symmetricUrl(); + void progressSignal(); + void urlChange(); + void requestedUrl(); + void requestedUrlAfterSetAndLoadFailures(); + void javaScriptWindowObjectCleared_data(); + void javaScriptWindowObjectCleared(); + void javaScriptWindowObjectClearedOnEvaluate(); + void setHtml(); + void setHtmlWithImageResource(); + void setHtmlWithStylesheetResource(); + void setHtmlWithBaseURL(); + void setHtmlWithJSAlert(); + void ipv6HostEncoding(); + void metaData(); +#if !defined(QT_NO_COMBOBOX) + void popupFocus(); +#endif + void inputFieldFocus(); + void hitTestContent(); + void baseUrl_data(); + void baseUrl(); + void hasSetFocus(); + void renderGeometry(); + void renderHints(); + void scrollPosition(); + void scrollToAnchor(); + void scrollbarsOff(); + void evaluateWillCauseRepaint(); + void setContent_data(); + void setContent(); + void setCacheLoadControlAttribute(); + void setUrlWithPendingLoads(); + void setUrlWithFragment_data(); + void setUrlWithFragment(); + void setUrlToEmpty(); + void setUrlToInvalid(); + void setUrlHistory(); + void setUrlUsingStateObject(); + void setUrlSameUrl(); + void setUrlThenLoads_data(); + void setUrlThenLoads(); + void loadFinishedAfterNotFoundError(); + void loadInSignalHandlers_data(); + void loadInSignalHandlers(); + +private: + QWebEngineView* m_view; + QWebEnginePage* m_page; + QWebEngineView* m_inputFieldsTestView; + int m_inputFieldTestPaintCount; +}; + +bool tst_QWebEngineFrame::eventFilter(QObject* watched, QEvent* event) +{ + // used on the inputFieldFocus test + if (watched == m_inputFieldsTestView) { + if (event->type() == QEvent::Paint) + m_inputFieldTestPaintCount++; + } + return QObject::eventFilter(watched, event); +} + +void tst_QWebEngineFrame::init() +{ + m_view = new QWebEngineView(); + m_page = m_view->page(); +} + +void tst_QWebEngineFrame::cleanup() +{ + delete m_view; +} + +void tst_QWebEngineFrame::symmetricUrl() +{ + QVERIFY(m_view->url().isEmpty()); + + QCOMPARE(m_view->history()->count(), 0); + + QUrl dataUrl("data:text/html,

Test"); + + m_view->setUrl(dataUrl); + QCOMPARE(m_view->url(), dataUrl); + QCOMPARE(m_view->history()->count(), 0); + + // loading is _not_ immediate, so the text isn't set just yet. + QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty()); + + ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); + + QCOMPARE(m_view->history()->count(), 1); + QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test")); + + QUrl dataUrl2("data:text/html,

Test2"); + QUrl dataUrl3("data:text/html,

Test3"); + + m_view->setUrl(dataUrl2); + m_view->setUrl(dataUrl3); + + QCOMPARE(m_view->url(), dataUrl3); + + ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); + + QCOMPARE(m_view->history()->count(), 2); + + QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3")); +} + +void tst_QWebEngineFrame::progressSignal() +{ + QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int))); + + QUrl dataUrl("data:text/html,

Test"); + m_view->setUrl(dataUrl); + + ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); + + QVERIFY(progressSpy.size() >= 2); + + // WebKit defines initialProgressValue as 10%, not 0% + QCOMPARE(progressSpy.first().first().toInt(), 10); + + // But we always end at 100% + QCOMPARE(progressSpy.last().first().toInt(), 100); +} + +void tst_QWebEngineFrame::urlChange() +{ + QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); + + QUrl dataUrl("data:text/html,

Test"); + m_view->setUrl(dataUrl); + + ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); + + QCOMPARE(urlSpy.size(), 1); + + QUrl dataUrl2("data:text/html,title

Test"); + m_view->setUrl(dataUrl2); + + ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); + + QCOMPARE(urlSpy.size(), 2); +} + +class FakeReply : public QNetworkReply { + Q_OBJECT + +public: + static const QUrl urlFor404ErrorWithoutContents; + + FakeReply(const QNetworkRequest& request, QObject* parent = 0) + : QNetworkReply(parent) + { + setOperation(QNetworkAccessManager::GetOperation); + setRequest(request); + setUrl(request.url()); + if (request.url() == QUrl("qrc:/test1.html")) { + setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html")); + setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html")); + QTimer::singleShot(0, this, SLOT(continueRedirect())); + } +#ifndef QT_NO_OPENSSL + else if (request.url() == QUrl("qrc:/fake-ssl-error.html")) { + setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error!")); + QTimer::singleShot(0, this, SLOT(continueError())); + } +#endif + else if (request.url().host() == QLatin1String("abcdef.abcdef")) { + setError(QNetworkReply::HostNotFoundError, tr("Invalid URL")); + QTimer::singleShot(0, this, SLOT(continueError())); + } else if (request.url() == FakeReply::urlFor404ErrorWithoutContents) { + setError(QNetworkReply::ContentNotFoundError, "Not found"); + setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 404); + QTimer::singleShot(0, this, SLOT(continueError())); + } + + open(QIODevice::ReadOnly); + } + ~FakeReply() + { + close(); + } + virtual void abort() {} + virtual void close() {} + +protected: + qint64 readData(char*, qint64) + { + return 0; + } + +private Q_SLOTS: + void continueRedirect() + { + emit metaDataChanged(); + emit finished(); + } + + void continueError() + { + emit error(this->error()); + emit finished(); + } +}; + +const QUrl FakeReply::urlFor404ErrorWithoutContents = QUrl("http://this.will/return-http-404-error-without-contents.html"); + +class FakeNetworkManager : public QNetworkAccessManager { + Q_OBJECT + +public: + FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { } + +protected: + virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData) + { + QString url = request.url().toString(); + if (op == QNetworkAccessManager::GetOperation) { +#ifndef QT_NO_OPENSSL + if (url == "qrc:/fake-ssl-error.html") { + FakeReply* reply = new FakeReply(request, this); + QList errors; + emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError)); + return reply; + } +#endif + if (url == "qrc:/test1.html" || url == "http://abcdef.abcdef/" || request.url() == FakeReply::urlFor404ErrorWithoutContents) + return new FakeReply(request, this); + } + + return QNetworkAccessManager::createRequest(op, request, outgoingData); + } +}; + +void tst_QWebEngineFrame::requestedUrl() +{ + QWebEnginePage page; + QWebEngineFrame* frame = page.mainFrame(); + + // in few seconds, the image should be completely loaded + QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); + FakeNetworkManager* networkManager = new FakeNetworkManager(&page); + page.setNetworkAccessManager(networkManager); + + frame->setUrl(QUrl("qrc:/test1.html")); + waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); + QCOMPARE(spy.count(), 1); + QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html")); + QCOMPARE(frame->url(), QUrl("qrc:/test2.html")); + + frame->setUrl(QUrl("qrc:/non-existent.html")); + waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); + QCOMPARE(spy.count(), 2); + QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html")); + QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html")); + + frame->setUrl(QUrl("http://abcdef.abcdef")); + waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); + QCOMPARE(spy.count(), 3); + QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/")); + QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/")); + +#ifndef QT_NO_OPENSSL + qRegisterMetaType >("QList"); + qRegisterMetaType("QNetworkReply*"); + + QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList))); + frame->setUrl(QUrl("qrc:/fake-ssl-error.html")); + waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); + QCOMPARE(spy2.count(), 1); + QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html")); + QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html")); +#endif +} + +void tst_QWebEngineFrame::requestedUrlAfterSetAndLoadFailures() +{ + QWebEnginePage page; + QWebEngineFrame* frame = page.mainFrame(); + + QSignalSpy spy(frame, SIGNAL(loadFinished(bool))); + + const QUrl first("http://abcdef.abcdef/"); + frame->setUrl(first); + ::waitForSignal(frame, SIGNAL(loadFinished(bool))); + QCOMPARE(frame->url(), first); + QCOMPARE(frame->requestedUrl(), first); + QVERIFY(!spy.at(0).first().toBool()); + + const QUrl second("http://abcdef.abcdef/another_page.html"); + QVERIFY(first != second); + + frame->load(second); + ::waitForSignal(frame, SIGNAL(loadFinished(bool))); + QCOMPARE(frame->url(), first); + QCOMPARE(frame->requestedUrl(), second); + QVERIFY(!spy.at(1).first().toBool()); +} + +void tst_QWebEngineFrame::javaScriptWindowObjectCleared_data() +{ + QTest::addColumn("html"); + QTest::addColumn("signalCount"); + QTest::newRow("with

hello world

" << 1; + // NOTE: Empty scripts no longer cause this signal to be emitted. + QTest::newRow("with empty

hello world

" << 0; + QTest::newRow("without

hello world

"); + MyPage page; + m_view->setPage(&page); + page.mainFrame()->setHtml(html); + QCOMPARE(page.alerts, 1); + QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=118663", Continue); + QCOMPARE(m_view->page()->mainFrame()->toHtml(), html); +} + +class TestNetworkManager : public QNetworkAccessManager +{ +public: + TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} + + QList requestedUrls; + +protected: + virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { + requestedUrls.append(request.url()); + QNetworkRequest redirectedRequest = request; + redirectedRequest.setUrl(QUrl("data:text/html,

hello")); + return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData); + } +}; + +void tst_QWebEngineFrame::ipv6HostEncoding() +{ + TestNetworkManager* networkManager = new TestNetworkManager(m_page); + m_page->setNetworkAccessManager(networkManager); + networkManager->requestedUrls.clear(); + + QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html"); + m_view->setHtml("

Hi", baseUrl); + m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();" + "r.open('GET', 'http://[::1]/test.xml', false);" + "r.send(null);" + ); + QCOMPARE(networkManager->requestedUrls.count(), 1); + QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml")); +} + +void tst_QWebEngineFrame::metaData() +{ + m_view->setHtml("" + " " + " " + " " + " " + ""); + + QMultiMap metaData = m_view->page()->mainFrame()->metaData(); + + QCOMPARE(metaData.count(), 2); + + QCOMPARE(metaData.value("description"), QString("Test description")); + QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css")); + QCOMPARE(metaData.value("nonexistent"), QString()); + + m_view->setHtml("" + " " + " " + " " + " " + ""); + + metaData = m_view->page()->mainFrame()->metaData(); + + QCOMPARE(metaData.count(), 2); + + QStringList values = metaData.values("samekey"); + QCOMPARE(values.count(), 2); + + QVERIFY(values.contains("FirstValue")); + QVERIFY(values.contains("SecondValue")); + + QCOMPARE(metaData.value("nonexistent"), QString()); +} + +#if !defined(QT_NO_COMBOBOX) +void tst_QWebEngineFrame::popupFocus() +{ + QWebEngineView view; + view.setHtml("" + " " + " " + " " + " " + " " + ""); + view.resize(400, 100); + // Call setFocus before show to work around http://bugreports.qt.nokia.com/browse/QTBUG-14762 + view.setFocus(); + view.show(); + QTest::qWaitForWindowExposed(&view); + view.activateWindow(); + QTRY_VERIFY(view.hasFocus()); + + // open the popup by clicking. check if focus is on the popup + const QWebEngineElement webCombo = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("select[name=select]")); + QTest::mouseClick(&view, Qt::LeftButton, 0, webCombo.geometry().center()); + + QComboBox* combo = view.findChild(); + QVERIFY(combo != 0); + QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup + + // hide the popup and check if focus is on the page + combo->hidePopup(); + QTRY_VERIFY(view.hasFocus()); // Focus should be back on the WebView +} +#endif + +void tst_QWebEngineFrame::inputFieldFocus() +{ + QWebEngineView view; + view.setHtml(""); + view.resize(400, 100); + view.show(); + QTest::qWaitForWindowExposed(&view); + view.activateWindow(); + view.setFocus(); + QTRY_VERIFY(view.hasFocus()); + + // double the flashing time, should at least blink once already + int delay = qApp->cursorFlashTime() * 2; + + // focus the lineedit and check if it blinks + bool autoSipEnabled = qApp->autoSipEnabled(); + qApp->setAutoSipEnabled(false); + const QWebEngineElement inputElement = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("input[type=text]")); + QTest::mouseClick(&view, Qt::LeftButton, 0, inputElement.geometry().center()); + m_inputFieldsTestView = &view; + view.installEventFilter( this ); + QTest::qWait(delay); + QVERIFY2(m_inputFieldTestPaintCount >= 3, + "The input field should have a blinking caret"); + qApp->setAutoSipEnabled(autoSipEnabled); +} + +void tst_QWebEngineFrame::hitTestContent() +{ + QString html("

A paragraph




link text"); + + QWebEnginePage page; + QWebEngineFrame* frame = page.mainFrame(); + frame->setHtml(html); + page.setViewportSize(QSize(200, 0)); //no height so link is not visible + const QWebEngineElement linkElement = frame->documentElement().findFirst(QLatin1String("a#link")); + QWebEngineHitTestResult result = frame->hitTestContent(linkElement.geometry().center()); + QCOMPARE(result.linkText(), QString("link text")); + QWebEngineElement link = result.linkElement(); + QCOMPARE(link.attribute("target"), QString("_foo")); +} + +void tst_QWebEngineFrame::baseUrl_data() +{ + QTest::addColumn("html"); + QTest::addColumn("loadUrl"); + QTest::addColumn("url"); + QTest::addColumn("baseUrl"); + + QTest::newRow("null") << QString() << QUrl() + << QUrl("about:blank") << QUrl("about:blank"); + + QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/") + << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/"); + + QString html = "" + "" + "" + "" + ""; + QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/") + << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/"); +} + +void tst_QWebEngineFrame::baseUrl() +{ + QFETCH(QString, html); + QFETCH(QUrl, loadUrl); + QFETCH(QUrl, url); + QFETCH(QUrl, baseUrl); + + m_page->mainFrame()->setHtml(html, loadUrl); + QCOMPARE(m_page->mainFrame()->url(), url); + QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl); +} + +void tst_QWebEngineFrame::hasSetFocus() +{ + QString html("

top

" \ + " + + diff --git a/tests/auto/widgets/qwebenginepage/resources/iframe3.html b/tests/auto/widgets/qwebenginepage/resources/iframe3.html new file mode 100644 index 000000000..ed6ac5b94 --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/iframe3.html @@ -0,0 +1,5 @@ + + +

inner

+ + diff --git a/tests/auto/widgets/qwebenginepage/resources/index.html b/tests/auto/widgets/qwebenginepage/resources/index.html new file mode 100644 index 000000000..638df364e --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/index.html @@ -0,0 +1,6 @@ + + + + + + diff --git a/tests/auto/widgets/qwebenginepage/resources/script.html b/tests/auto/widgets/qwebenginepage/resources/script.html new file mode 100644 index 000000000..ede986415 --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/script.html @@ -0,0 +1,3 @@ + + + diff --git a/tests/auto/widgets/qwebenginepage/resources/user.css b/tests/auto/widgets/qwebenginepage/resources/user.css new file mode 100644 index 000000000..4ccb2f0fc --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/user.css @@ -0,0 +1,3 @@ +p { + background-image: url('http://does.not/exist.png'); +} \ No newline at end of file diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp new file mode 100644 index 000000000..bbdc6c2e9 --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -0,0 +1,3628 @@ +/* + Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2009 Girish Ramakrishnan + Copyright (C) 2010 Holger Hans Peter Freyther + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "../util.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void removeRecursive(const QString& dirname) +{ + QDir dir(dirname); + QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); + for (int i = 0; i < entries.count(); ++i) + if (entries[i].isDir()) + removeRecursive(entries[i].filePath()); + else + dir.remove(entries[i].fileName()); + QDir().rmdir(dirname); +} + +class TestInputContext : public QPlatformInputContext +{ +public: + TestInputContext() + : m_visible(false) + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = this; + } + + ~TestInputContext() + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; + } + + virtual void showInputPanel() + { + m_visible = true; + } + virtual void hideInputPanel() + { + m_visible = false; + } + virtual bool isInputPanelVisible() const + { + return m_visible; + } + + bool m_visible; +}; + +class tst_QWebEnginePage : public QObject +{ + Q_OBJECT + +public: + tst_QWebEnginePage(); + virtual ~tst_QWebEnginePage(); + +public Q_SLOTS: + void init(); + void cleanup(); + void cleanupFiles(); + +private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void thirdPartyCookiePolicy(); + void contextMenuCopy(); + void contextMenuPopulatedOnce(); + void acceptNavigationRequest(); + void geolocationRequestJS(); + void loadFinished(); + void actionStates(); + void popupFormSubmission(); + void acceptNavigationRequestWithNewWindow(); + void userStyleSheet(); + void userStyleSheetFromLocalFileUrl(); + void userStyleSheetFromQrcUrl(); + void loadHtml5Video(); + void modified(); + void contextMenuCrash(); + void updatePositionDependentActionsCrash(); + void database(); + void createPluginWithPluginsEnabled(); + void createPluginWithPluginsDisabled(); + void destroyPlugin_data(); + void destroyPlugin(); + void createViewlessPlugin_data(); + void createViewlessPlugin(); + void graphicsWidgetPlugin(); + void multiplePageGroupsAndLocalStorage(); + void cursorMovements(); + void textSelection(); + void textEditing(); + void backActionUpdate(); + void frameAt(); + void requestCache(); + void loadCachedPage(); + void protectBindingsRuntimeObjectsFromCollector(); + void localURLSchemes(); + void testOptionalJSObjects(); + void testLocalStorageVisibility(); + void testEnablePersistentStorage(); + void consoleOutput(); + void inputMethods_data(); + void inputMethods(); + void inputMethodsTextFormat_data(); + void inputMethodsTextFormat(); + void defaultTextEncoding(); + void errorPageExtension(); + void errorPageExtensionInIFrames(); + void errorPageExtensionInFrameset(); + void errorPageExtensionLoadFinished(); + void userAgentApplicationName(); + void userAgentNewlineStripping(); + void undoActionHaveCustomText(); + + void viewModes(); + + void crashTests_LazyInitializationOfMainFrame(); + + void screenshot_data(); + void screenshot(); + +#if defined(ENABLE_WEBGL) && ENABLE_WEBGL + void acceleratedWebGLScreenshotWithoutView(); + void unacceleratedWebGLScreenshotWithoutView(); +#endif + + void originatingObjectInNetworkRequests(); + void networkReplyParentDidntChange(); + void destroyQNAMBeforeAbortDoesntCrash(); + void testJSPrompt(); + void showModalDialog(); + void testStopScheduledPageRefresh(); + void findText(); + void supportedContentType(); + // [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT + // https://bugs.webengine.org/show_bug.cgi?id=79040 + // void infiniteLoopJS(); + void navigatorCookieEnabled(); + void deleteQWebEngineViewTwice(); + void renderOnRepaintRequestedShouldNotRecurse(); + void loadSignalsOrder_data(); + void loadSignalsOrder(); + void openWindowDefaultSize(); + void cssMediaTypeGlobalSetting(); + void cssMediaTypePageSetting(); + +#ifdef Q_OS_MAC + void macCopyUnicodeToClipboard(); +#endif + +private: + QWebEngineView* m_view; + QWebEnginePage* m_page; + QString tmpDirPath() const + { + static QString tmpd = QDir::tempPath() + "/tst_qwebenginepage-" + + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")); + return tmpd; + } +}; + +tst_QWebEnginePage::tst_QWebEnginePage() +{ +} + +tst_QWebEnginePage::~tst_QWebEnginePage() +{ +} + +void tst_QWebEnginePage::init() +{ + m_view = new QWebEngineView(); + m_page = m_view->page(); +} + +void tst_QWebEnginePage::cleanup() +{ + delete m_view; +} + +void tst_QWebEnginePage::cleanupFiles() +{ + removeRecursive(tmpDirPath()); +} + +void tst_QWebEnginePage::initTestCase() +{ + cleanupFiles(); // In case there are old files from previous runs +} + +void tst_QWebEnginePage::cleanupTestCase() +{ + cleanupFiles(); // Be nice +} + +class NavigationRequestOverride : public QWebEnginePage +{ +public: + NavigationRequestOverride(QWebEngineView* parent, bool initialValue) : QWebEnginePage(parent), m_acceptNavigationRequest(initialValue) {} + + bool m_acceptNavigationRequest; +protected: + virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, QWebEnginePage::NavigationType type) { + Q_UNUSED(frame); + Q_UNUSED(request); + Q_UNUSED(type); + + return m_acceptNavigationRequest; + } +}; + +void tst_QWebEnginePage::acceptNavigationRequest() +{ +#if !defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) + QSKIP("QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST"); +#else + QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); + + NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); + m_view->setPage(newPage); + + m_view->setHtml(QString("
" + "
"), QUrl()); + QTRY_COMPARE(loadSpy.count(), 1); + + m_view->page()->evaluateJavaScript("tstform.submit();"); + + newPage->m_acceptNavigationRequest = true; + m_view->page()->evaluateJavaScript("tstform.submit();"); + QTRY_COMPARE(loadSpy.count(), 2); + + QCOMPARE(m_view->page()->toPlainText(), QString("foo?")); + + // Restore default page + m_view->setPage(0); +#endif +} + +#if defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) +class JSTestPage : public QWebEnginePage +{ +Q_OBJECT +public: + JSTestPage(QObject* parent = 0) + : QWebEnginePage(parent) {} + + virtual bool shouldInterruptJavaScript() + { + return true; + } +public Q_SLOTS: + void requestPermission(QWebEngineFrame* frame, QWebEnginePage::Feature feature) + { + if (m_allowGeolocation) + setFeaturePermission(frame, feature, PermissionGrantedByUser); + else + setFeaturePermission(frame, feature, PermissionDeniedByUser); + } + +public: + void setGeolocationPermission(bool allow) + { + m_allowGeolocation = allow; + } + +private: + bool m_allowGeolocation; +}; +#endif + +// [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT +// https://bugs.webengine.org/show_bug.cgi?id=79040 +/* +void tst_QWebEnginePage::infiniteLoopJS() +{ + JSTestPage* newPage = new JSTestPage(m_view); + m_view->setPage(newPage); + m_view->setHtml(QString("test"), QUrl()); + m_view->page()->evaluateJavaScript("var run = true; var a = 1; while (run) { a++; }"); + delete newPage; +} +*/ + +void tst_QWebEnginePage::geolocationRequestJS() +{ +#if !defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) + QSKIP("QWEBENGINEPAGE_SETFEATUREPERMISSION"); +#else + JSTestPage* newPage = new JSTestPage(m_view); + + if (newPage->evaluateJavaScript(QLatin1String("!navigator.geolocation")).toBool()) { + delete newPage; + W_QSKIP("Geolocation is not supported.", SkipSingle); + } + + connect(newPage, SIGNAL(featurePermissionRequested(QWebEngineFrame*, QWebEnginePage::Feature)), + newPage, SLOT(requestPermission(QWebEngineFrame*, QWebEnginePage::Feature))); + + newPage->setGeolocationPermission(false); + m_view->setPage(newPage); + m_view->setHtml(QString("test"), QUrl()); + m_view->page()->evaluateJavaScript("var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)"); + QTest::qWait(2000); + QVariant empty = m_view->page()->evaluateJavaScript("errorCode"); + + QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=102235", Continue); + QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0); + + newPage->setGeolocationPermission(true); + m_view->page()->evaluateJavaScript("errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);"); + empty = m_view->page()->evaluateJavaScript("errorCode"); + + //http://dev.w3.org/geo/api/spec-source.html#position + //PositionError: const unsigned short PERMISSION_DENIED = 1; + QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1); + delete newPage; +#endif +} + +void tst_QWebEnginePage::loadFinished() +{ + qRegisterMetaType("QNetworkRequest*"); + QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted())); + QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); + + m_view->page()->load(QUrl("data:text/html,foo \">" + "")); + QTRY_COMPARE(spyLoadFinished.count(), 1); + + QTRY_VERIFY(spyLoadStarted.count() > 1); + QTRY_VERIFY(spyLoadFinished.count() > 1); + + spyLoadFinished.clear(); + + m_view->page()->load(QUrl("data:text/html,")); + QTRY_COMPARE(spyLoadFinished.count(), 1); + QCOMPARE(spyLoadFinished.count(), 1); +} + +void tst_QWebEnginePage::actionStates() +{ + QWebEnginePage* page = m_view->page(); + + page->load(QUrl("qrc:///resources/script.html")); + + QAction* reloadAction = page->action(QWebEnginePage::Reload); + QAction* stopAction = page->action(QWebEnginePage::Stop); + + QTRY_VERIFY(reloadAction->isEnabled()); + QTRY_VERIFY(!stopAction->isEnabled()); +} + +class ConsolePage : public QWebEnginePage +{ +public: + ConsolePage(QObject* parent = 0) : QWebEnginePage(parent) {} + + virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) + { + messages.append(message); + lineNumbers.append(lineNumber); + sourceIDs.append(sourceID); + } + + QStringList messages; + QList lineNumbers; + QStringList sourceIDs; +}; + +void tst_QWebEnginePage::consoleOutput() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + ConsolePage page; + page.evaluateJavaScript("this is not valid JavaScript"); + QCOMPARE(page.messages.count(), 1); + QCOMPARE(page.lineNumbers.at(0), 1); +#endif +} + +class TestPage : public QWebEnginePage { + Q_OBJECT +public: + TestPage(QObject* parent = 0) : QWebEnginePage(parent) + { + connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect))); + } + + struct Navigation { + QWebEngineFrame *frame; + QNetworkRequest request; + NavigationType type; + }; + + QList navigations; + QList createdWindows; + QRect requestedGeometry; + + virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, NavigationType type) { + Navigation n; + n.frame = frame; + n.request = request; + n.type = type; + navigations.append(n); + return true; + } + + virtual QWebEnginePage* createWindow(WebWindowType) { + TestPage* page = new TestPage(this); + createdWindows.append(page); + return page; + } + +private Q_SLOTS: + void slotGeometryChangeRequested(const QRect& geom) { + requestedGeometry = geom; + } +}; + +void tst_QWebEnginePage::popupFormSubmission() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + TestPage page; + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); + page.setHtml("
"\ + ""\ + "
"); + page.evaluateJavaScript("window.open('', 'myNewWin', 'width=500,height=300,toolbar=0')"); + page.evaluateJavaScript("document.form1.submit();"); + + QTest::qWait(500); + // The number of popup created should be one. + QVERIFY(page.createdWindows.size() == 1); + + QString url = page.createdWindows.takeFirst()->url().toString(); + // Check if the form submission was OK. + QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=118597", Continue); + QVERIFY(url.contains("?foo=bar")); +#endif +} + +void tst_QWebEnginePage::acceptNavigationRequestWithNewWindow() +{ +#if !defined(QWEBENGINESETTINGS) + QSKIP("QWEBENGINESETTINGS"); +#else + TestPage* page = new TestPage(m_view); + page->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true); + m_page = page; + m_view->setPage(m_page); + + m_view->setUrl(QString("data:text/html,Click me")); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QFocusEvent fe(QEvent::FocusIn); + m_page->event(&fe); + + QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); + + QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + m_page->event(&keyEnter); + + QCOMPARE(page->navigations.count(), 2); + + TestPage::Navigation n = page->navigations.at(1); + QVERIFY(!n.frame); + QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); + QVERIFY(n.type == QWebEnginePage::NavigationTypeLinkClicked); + + QCOMPARE(page->createdWindows.count(), 1); +#endif +} + +class TestNetworkManager : public QNetworkAccessManager +{ +public: + TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} + + QList requestedUrls; + QList requests; + +protected: + virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { + requests.append(request); + requestedUrls.append(request.url()); + return QNetworkAccessManager::createRequest(op, request, outgoingData); + } +}; + +void tst_QWebEnginePage::userStyleSheet() +{ +#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) + QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); +#else + TestNetworkManager* networkManager = new TestNetworkManager(m_page); + m_page->setNetworkAccessManager(networkManager); + + m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64," + + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64())); + m_view->setHtml("

hello world

"); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QVERIFY(networkManager->requestedUrls.count() >= 1); + QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); +#endif +} + +void tst_QWebEnginePage::userStyleSheetFromLocalFileUrl() +{ +#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) + QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); +#else + TestNetworkManager* networkManager = new TestNetworkManager(m_page); + m_page->setNetworkAccessManager(networkManager); + + QUrl styleSheetUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginepage/resources/user.css")); + m_page->settings()->setUserStyleSheetUrl(styleSheetUrl); + m_view->setHtml("

hello world

"); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QVERIFY(networkManager->requestedUrls.count() >= 1); + QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); +#endif +} + +void tst_QWebEnginePage::userStyleSheetFromQrcUrl() +{ +#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) + QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); +#else + TestNetworkManager* networkManager = new TestNetworkManager(m_page); + m_page->setNetworkAccessManager(networkManager); + + m_page->settings()->setUserStyleSheetUrl(QUrl("qrc:///resources/user.css")); + m_view->setHtml("

hello world

"); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QVERIFY(networkManager->requestedUrls.count() >= 1); + QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); +#endif +} + +void tst_QWebEnginePage::loadHtml5Video() +{ +#if defined(WTF_USE_QT_MULTIMEDIA) && WTF_USE_QT_MULTIMEDIA + QByteArray url("http://does.not/exist?a=1%2Cb=2"); + m_view->setHtml("

"); + QTest::qWait(2000); + QUrl mUrl = DumpRenderTreeSupportQt::mediaContentUrlByElementId(m_page->mainFrame()->handle(), "video"); + QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=65452", Continue); + QCOMPARE(mUrl.toEncoded(), url); +#else + W_QSKIP("This test requires Qt Multimedia", SkipAll); +#endif +} + +void tst_QWebEnginePage::viewModes() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + m_view->setHtml(""); + m_page->setProperty("_q_viewMode", "minimized"); + + QVariant empty = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode)\")"); + QVERIFY(empty.type() == QVariant::Bool && empty.toBool()); + + QVariant minimized = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode: minimized)\")"); + QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool()); + + QVariant maximized = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode: maximized)\")"); + QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool()); +#endif +} + +void tst_QWebEnginePage::modified() +{ +#if !defined(QWEBENGINEPAGE_ISMODIFIED) + QSKIP("QWEBENGINEPAGE_ISMODIFIED"); +#else + m_page->setUrl(QUrl("data:text/html,blub")); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + m_page->setUrl(QUrl("data:text/html,blah")); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QVERIFY(!m_page->isModified()); + +// m_page->evaluateJavaScript("alert(document.getElementById('foo'))"); + m_page->evaluateJavaScript("document.getElementById('foo').focus()"); + m_page->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');"); + + QVERIFY(m_page->isModified()); + + m_page->evaluateJavaScript("document.execCommand('Undo', true);"); + + QVERIFY(!m_page->isModified()); + + m_page->evaluateJavaScript("document.execCommand('Redo', true);"); + + QVERIFY(m_page->isModified()); + + QVERIFY(m_page->history()->canGoBack()); + QVERIFY(!m_page->history()->canGoForward()); + QCOMPARE(m_page->history()->count(), 2); + QVERIFY(m_page->history()->backItem().isValid()); + QVERIFY(!m_page->history()->forwardItem().isValid()); + + m_page->history()->back(); + QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); + + QVERIFY(!m_page->history()->canGoBack()); + QVERIFY(m_page->history()->canGoForward()); + + QVERIFY(!m_page->isModified()); + + QVERIFY(m_page->history()->currentItemIndex() == 0); + + m_page->history()->setMaximumItemCount(3); + QVERIFY(m_page->history()->maximumItemCount() == 3); + + QVariant variant("string test"); + m_page->history()->currentItem().setUserData(variant); + QVERIFY(m_page->history()->currentItem().userData().toString() == "string test"); + + m_page->setUrl(QUrl("data:text/html,This is second page")); + m_page->setUrl(QUrl("data:text/html,This is third page")); + QVERIFY(m_page->history()->count() == 2); + m_page->setUrl(QUrl("data:text/html,This is fourth page")); + QVERIFY(m_page->history()->count() == 2); + m_page->setUrl(QUrl("data:text/html,This is fifth page")); + QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebEngineFrame*,QWebEngineHistoryItem*)))); +#endif +} + +// https://bugs.webengine.org/show_bug.cgi?id=51331 +void tst_QWebEnginePage::updatePositionDependentActionsCrash() +{ +#if !defined(QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS) + QSKIP("QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS"); +#else + QWebEngineView view; + view.setHtml("

test"); + QPoint pos(0, 0); + view.page()->updatePositionDependentActions(pos); + QMenu* contextMenu = 0; + foreach (QObject* child, view.children()) { + contextMenu = qobject_cast(child); + if (contextMenu) + break; + } + QVERIFY(!contextMenu); +#endif +} + +// https://bugs.webengine.org/show_bug.cgi?id=20357 +void tst_QWebEnginePage::contextMenuCrash() +{ +#if !defined(QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT) + QSKIP("QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT"); +#else + QWebEngineView view; + view.setHtml("

test"); + QPoint pos(0, 0); + QContextMenuEvent event(QContextMenuEvent::Mouse, pos); + view.page()->swallowContextMenuEvent(&event); + view.page()->updatePositionDependentActions(pos); + QMenu* contextMenu = 0; + foreach (QObject* child, view.children()) { + contextMenu = qobject_cast(child); + if (contextMenu) + break; + } + QVERIFY(contextMenu); + delete contextMenu; +#endif +} + +void tst_QWebEnginePage::database() +{ +#if !defined(QWEBENGINEDATABASE) + QSKIP("QWEBENGINEDATABASE"); +#else + QString path = tmpDirPath(); + m_page->settings()->setOfflineStoragePath(path); + QVERIFY(m_page->settings()->offlineStoragePath() == path); + + QWebEngineSettings::setOfflineStorageDefaultQuota(1024 * 1024); + QVERIFY(QWebEngineSettings::offlineStorageDefaultQuota() == 1024 * 1024); + + m_page->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + m_page->settings()->setAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled, true); + + QString dbFileName = path + "Databases.db"; + + if (QFile::exists(dbFileName)) + QFile::remove(dbFileName); + + qRegisterMetaType("QWebEngineFrame*"); + QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebEngineFrame*,QString))); + m_view->setHtml(QString("

"), QUrl("http://www.myexample.com")); + QTRY_COMPARE(spy.count(), 1); + m_page->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);"); + QTRY_COMPARE(spy.count(),1); + + m_page->evaluateJavaScript("localStorage.test='This is a test for local storage';"); + m_view->setHtml(QString("text"), QUrl("http://www.myexample.com")); + + QVariant s1 = m_page->evaluateJavaScript("localStorage.test"); + QCOMPARE(s1.toString(), QString("This is a test for local storage")); + + m_page->evaluateJavaScript("sessionStorage.test='This is a test for session storage';"); + m_view->setHtml(QString("text"), QUrl("http://www.myexample.com")); + QVariant s2 = m_page->evaluateJavaScript("sessionStorage.test"); + QCOMPARE(s2.toString(), QString("This is a test for session storage")); + + m_view->setHtml(QString("
"), QUrl("http://www.myexample.com")); + m_page->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) { });"); + QTest::qWait(200); + + // Remove all databases. + QWebEngineSecurityOrigin origin = m_page->mainFrame()->securityOrigin(); + QList dbs = origin.databases(); + for (int i = 0; i < dbs.count(); i++) { + QString fileName = dbs[i].fileName(); + QVERIFY(QFile::exists(fileName)); + QWebEngineDatabase::removeDatabase(dbs[i]); + QVERIFY(!QFile::exists(fileName)); + } + QVERIFY(!origin.databases().size()); + // Remove removed test :-) + QWebEngineDatabase::removeAllDatabases(); + QVERIFY(!origin.databases().size()); +#endif +} + +#if defined(QWEBENGINEPAGE_CREATEPLUGIN) +class PluginPage : public QWebEnginePage +{ +public: + PluginPage(QObject *parent = 0) + : QWebEnginePage(parent) {} + + struct CallInfo + { + CallInfo(const QString &c, const QUrl &u, + const QStringList &pn, const QStringList &pv, + QObject *r) + : classid(c), url(u), paramNames(pn), + paramValues(pv), returnValue(r) + {} + QString classid; + QUrl url; + QStringList paramNames; + QStringList paramValues; + QObject *returnValue; + }; + + QList calls; + +protected: + virtual QObject *createPlugin(const QString &classid, const QUrl &url, + const QStringList ¶mNames, + const QStringList ¶mValues) + { + QObject *result = 0; + if (classid == "pushbutton") + result = new QPushButton(); +#ifndef QT_NO_INPUTDIALOG + else if (classid == "lineedit") + result = new QLineEdit(); +#endif + else if (classid == "graphicswidget") + result = new QGraphicsWidget(); + if (result) + result->setObjectName(classid); + calls.append(CallInfo(classid, url, paramNames, paramValues, result)); + return result; + } +}; + +static void createPlugin(QWebEngineView *view) +{ + QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); + + PluginPage* newPage = new PluginPage(view); + view->setPage(newPage); + + // type has to be application/x-qt-plugin + view->setHtml(QString("")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(newPage->calls.count(), 0); + + view->setHtml(QString("")); + QTRY_COMPARE(loadSpy.count(), 2); + QCOMPARE(newPage->calls.count(), 1); + { + PluginPage::CallInfo ci = newPage->calls.takeFirst(); + QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); + QCOMPARE(ci.url, QUrl()); + QCOMPARE(ci.paramNames.count(), 3); + QCOMPARE(ci.paramValues.count(), 3); + QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); + QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); + QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); + QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); + QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); + QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); + QVERIFY(ci.returnValue != 0); + QVERIFY(ci.returnValue->inherits("QPushButton")); + } + // test JS bindings + QCOMPARE(newPage->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(), + QString::fromLatin1("[object HTMLObjectElement]")); + QCOMPARE(newPage->evaluateJavaScript("mybutton.toString()").toString(), + QString::fromLatin1("[object HTMLObjectElement]")); + QCOMPARE(newPage->evaluateJavaScript("typeof mybutton.objectName").toString(), + QString::fromLatin1("string")); + QCOMPARE(newPage->evaluateJavaScript("mybutton.objectName").toString(), + QString::fromLatin1("pushbutton")); + QCOMPARE(newPage->evaluateJavaScript("typeof mybutton.clicked").toString(), + QString::fromLatin1("function")); + QCOMPARE(newPage->evaluateJavaScript("mybutton.clicked.toString()").toString(), + QString::fromLatin1("function clicked() {\n [native code]\n}")); + + view->setHtml(QString("" + "" + "" + "
"), QUrl("http://foo.bar.baz")); + QTRY_COMPARE(loadSpy.count(), 3); + QCOMPARE(newPage->calls.count(), 2); + { + PluginPage::CallInfo ci = newPage->calls.takeFirst(); + QCOMPARE(ci.classid, QString::fromLatin1("lineedit")); + QCOMPARE(ci.url, QUrl()); + QCOMPARE(ci.paramNames.count(), 3); + QCOMPARE(ci.paramValues.count(), 3); + QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); + QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); + QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); + QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit")); + QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); + QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit")); + QVERIFY(ci.returnValue != 0); + QVERIFY(ci.returnValue->inherits("QLineEdit")); + } + { + PluginPage::CallInfo ci = newPage->calls.takeFirst(); + QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); + QCOMPARE(ci.url, QUrl()); + QCOMPARE(ci.paramNames.count(), 3); + QCOMPARE(ci.paramValues.count(), 3); + QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); + QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); + QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); + QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); + QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); + QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); + QVERIFY(ci.returnValue != 0); + QVERIFY(ci.returnValue->inherits("QPushButton")); + } +} +#endif + +void tst_QWebEnginePage::graphicsWidgetPlugin() +{ +#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) + QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); +#else + m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + QGraphicsWebView webView; + + QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool))); + + PluginPage* newPage = new PluginPage(&webView); + webView.setPage(newPage); + + // type has to be application/x-qt-plugin + webView.setHtml(QString("")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(newPage->calls.count(), 0); + + webView.setHtml(QString("")); + QTRY_COMPARE(loadSpy.count(), 2); + QCOMPARE(newPage->calls.count(), 1); + { + PluginPage::CallInfo ci = newPage->calls.takeFirst(); + QCOMPARE(ci.classid, QString::fromLatin1("graphicswidget")); + QCOMPARE(ci.url, QUrl()); + QCOMPARE(ci.paramNames.count(), 3); + QCOMPARE(ci.paramValues.count(), 3); + QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); + QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); + QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); + QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("graphicswidget")); + QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); + QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mygraphicswidget")); + QVERIFY(ci.returnValue); + QVERIFY(ci.returnValue->inherits("QGraphicsWidget")); + } + // test JS bindings + QCOMPARE(newPage->evaluateJavaScript("document.getElementById('mygraphicswidget').toString()").toString(), + QString::fromLatin1("[object HTMLObjectElement]")); + QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.toString()").toString(), + QString::fromLatin1("[object HTMLObjectElement]")); + QCOMPARE(newPage->evaluateJavaScript("typeof mygraphicswidget.objectName").toString(), + QString::fromLatin1("string")); + QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.objectName").toString(), + QString::fromLatin1("graphicswidget")); + QCOMPARE(newPage->evaluateJavaScript("typeof mygraphicswidget.geometryChanged").toString(), + QString::fromLatin1("function")); + QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.geometryChanged.toString()").toString(), + QString::fromLatin1("function geometryChanged() {\n [native code]\n}")); +#endif +} + +void tst_QWebEnginePage::createPluginWithPluginsEnabled() +{ +#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) + QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); +#else + m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + createPlugin(m_view); +#endif +} + +void tst_QWebEnginePage::createPluginWithPluginsDisabled() +{ +#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) + QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); +#else + // Qt Plugins should be loaded by QtWebEngine even when PluginsEnabled is + // false. The client decides whether a Qt plugin is enabled or not when + // it decides whether or not to instantiate it. + m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); + createPlugin(m_view); +#endif +} + +#if defined(QWEBENGINEPAGE_CREATEPLUGIN) +// Standard base class for template PluginTracerPage. In tests it is used as interface. +class PluginCounterPage : public QWebEnginePage { +public: + int m_count; + QPointer m_widget; + QObject* m_pluginParent; + PluginCounterPage(QObject* parent = 0) + : QWebEnginePage(parent) + , m_count(0) + , m_pluginParent(0) + { + settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + } + ~PluginCounterPage() + { + if (m_pluginParent) + m_pluginParent->deleteLater(); + } +}; + +template +class PluginTracerPage : public PluginCounterPage { +public: + PluginTracerPage(QObject* parent = 0) + : PluginCounterPage(parent) + { + // this is a dummy parent object for the created plugin + m_pluginParent = new T; + } + virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) + { + m_count++; + m_widget = new T; + // need a cast to the specific type, as QObject::setParent cannot be called, + // because it is not virtual. Instead it is necessary to call QWidget::setParent, + // which also takes a QWidget* instead of a QObject*. Therefore we need to + // upcast to T*, which is a QWidget. + static_cast(m_widget.data())->setParent(static_cast(m_pluginParent)); + return m_widget.data(); + } +}; + +class PluginFactory { +public: + enum FactoredType {QWidgetType, QGraphicsWidgetType}; + static PluginCounterPage* create(FactoredType type, QObject* parent = 0) + { + PluginCounterPage* result = 0; + switch (type) { + case QWidgetType: + result = new PluginTracerPage(parent); + break; + case QGraphicsWidgetType: + result = new PluginTracerPage(parent); + break; + default: {/*Oops*/}; + } + return result; + } + + static void prepareTestData() + { + QTest::addColumn("type"); + QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType; + QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType; + } +}; +#endif + +void tst_QWebEnginePage::destroyPlugin_data() +{ +#if defined(QWEBENGINEPAGE_CREATEPLUGIN) + PluginFactory::prepareTestData(); +#endif +} + +void tst_QWebEnginePage::destroyPlugin() +{ +#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) + QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); +#else + QFETCH(int, type); + PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view); + m_view->setPage(page); + + // we create the plugin, so the widget should be constructed + QString content(""); + m_view->setHtml(content); + QVERIFY(page->m_widget); + QCOMPARE(page->m_count, 1); + + // navigate away, the plugin widget should be destructed + m_view->setHtml("Hi"); + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!page->m_widget); +#endif +} + +void tst_QWebEnginePage::createViewlessPlugin_data() +{ +#if defined(QWEBENGINEPAGE_CREATEPLUGIN) + PluginFactory::prepareTestData(); +#endif +} + +void tst_QWebEnginePage::createViewlessPlugin() +{ +#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) + QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); +#else + QFETCH(int, type); + PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type); + QString content(""); + page->setHtml(content); + QCOMPARE(page->m_count, 1); + QVERIFY(page->m_widget); + QVERIFY(page->m_pluginParent); + QVERIFY(page->m_widget.data()->parent() == page->m_pluginParent); + delete page; +#endif +} + +void tst_QWebEnginePage::multiplePageGroupsAndLocalStorage() +{ +#if !defined(QWEBENGINESETTINGS_SETLOCALSTORAGEPATH) + QSKIP("QWEBENGINESETTINGS_SETLOCALSTORAGEPATH"); +#else + QDir dir(tmpDirPath()); + dir.mkdir("path1"); + dir.mkdir("path2"); + + QWebEngineView view1; + QWebEngineView view2; + + view1.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path1")); + DumpRenderTreeSupportQt::webPageSetGroupName(view1.page()->handle(), "group1"); + view2.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); + view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path2")); + DumpRenderTreeSupportQt::webPageSetGroupName(view2.page()->handle(), "group2"); + QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()->handle()), QString("group1")); + QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()->handle()), QString("group2")); + + + view1.setHtml(QString(" "), QUrl("http://www.myexample.com")); + view2.setHtml(QString(" "), QUrl("http://www.myexample.com")); + + view1.page()->evaluateJavaScript("localStorage.test='value1';"); + view2.page()->evaluateJavaScript("localStorage.test='value2';"); + + view1.setHtml(QString(" "), QUrl("http://www.myexample.com")); + view2.setHtml(QString(" "), QUrl("http://www.myexample.com")); + + QVariant s1 = view1.page()->evaluateJavaScript("localStorage.test"); + QCOMPARE(s1.toString(), QString("value1")); + + QVariant s2 = view2.page()->evaluateJavaScript("localStorage.test"); + QCOMPARE(s2.toString(), QString("value2")); + + QTest::qWait(1000); + + QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path1/http_www.myexample.com_0.localstorage")); + QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path2/http_www.myexample.com_0.localstorage")); + dir.rmdir(QDir::toNativeSeparators("./path1")); + dir.rmdir(QDir::toNativeSeparators("./path2")); +#endif +} + +#if defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) +class CursorTrackedPage : public QWebEnginePage +{ +public: + + CursorTrackedPage(QWidget *parent = 0): QWebEnginePage(parent) { + setViewportSize(QSize(1024, 768)); // big space + } + + QString selectedText() { + return evaluateJavaScript("window.getSelection().toString()").toString(); + } + + int selectionStartOffset() { + return evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt(); + } + + int selectionEndOffset() { + return evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt(); + } + + // true if start offset == end offset, i.e. no selected text + int isSelectionCollapsed() { + return evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool(); + } +}; +#endif + +void tst_QWebEnginePage::cursorMovements() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + CursorTrackedPage* page = new CursorTrackedPage; + QString content("

The quick brown fox

jumps over the lazy dog

May the source
be with you!

"); + page->setHtml(content); + + // this will select the first paragraph + QString script = "var range = document.createRange(); " \ + "var node = document.getElementById(\"one\"); " \ + "range.selectNode(node); " \ + "getSelection().addRange(range);"; + page->evaluateJavaScript(script); + QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); + + QRegExp regExp(" style=\".*\""); + regExp.setMinimal(true); + QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("

The quick brown fox

")); + + // these actions must exist + QVERIFY(page->action(QWebEnginePage::MoveToNextChar) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToPreviousChar) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToNextWord) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToPreviousWord) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToNextLine) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToPreviousLine) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToStartOfLine) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToEndOfLine) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToStartOfBlock) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToEndOfBlock) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToStartOfDocument) != 0); + QVERIFY(page->action(QWebEnginePage::MoveToEndOfDocument) != 0); + + // right now they are disabled because contentEditable is false + QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), false); + + // make it editable before navigating the cursor + page->setContentEditable(true); + + // here the actions are enabled after contentEditable is true + QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), true); + + // cursor will be before the word "jump" + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // cursor will be between 'j' and 'u' in the word "jump" + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 1); + + // cursor will be between 'u' and 'm' in the word "jump" + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 2); + + // cursor will be after the word "jump" + page->triggerAction(QWebEnginePage::MoveToNextWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 5); + + // cursor will be after the word "lazy" + page->triggerAction(QWebEnginePage::MoveToNextWord); + page->triggerAction(QWebEnginePage::MoveToNextWord); + page->triggerAction(QWebEnginePage::MoveToNextWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 19); + + // cursor will be between 'z' and 'y' in "lazy" + page->triggerAction(QWebEnginePage::MoveToPreviousChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 18); + + // cursor will be between 'a' and 'z' in "lazy" + page->triggerAction(QWebEnginePage::MoveToPreviousChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 17); + + // cursor will be before the word "lazy" + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 15); + + // cursor will be before the word "quick" + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 4); + + // cursor will be between 'p' and 's' in the word "jumps" + page->triggerAction(QWebEnginePage::MoveToNextWord); + page->triggerAction(QWebEnginePage::MoveToNextWord); + page->triggerAction(QWebEnginePage::MoveToNextWord); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 4); + + // cursor will be before the word "jumps" + page->triggerAction(QWebEnginePage::MoveToStartOfLine); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // cursor will be after the word "dog" + page->triggerAction(QWebEnginePage::MoveToEndOfLine); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 23); + + // cursor will be between 'w' and 'n' in "brown" + page->triggerAction(QWebEnginePage::MoveToStartOfLine); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 14); + + // cursor will be after the word "fox" + page->triggerAction(QWebEnginePage::MoveToEndOfLine); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 19); + + // cursor will be before the word "The" + page->triggerAction(QWebEnginePage::MoveToStartOfDocument); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // cursor will be after the word "you!" + page->triggerAction(QWebEnginePage::MoveToEndOfDocument); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 12); + + // cursor will be before the word "be" + page->triggerAction(QWebEnginePage::MoveToStartOfBlock); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // cursor will be after the word "you!" + page->triggerAction(QWebEnginePage::MoveToEndOfBlock); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 12); + + // try to move before the document start + page->triggerAction(QWebEnginePage::MoveToStartOfDocument); + page->triggerAction(QWebEnginePage::MoveToPreviousChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + page->triggerAction(QWebEnginePage::MoveToStartOfDocument); + page->triggerAction(QWebEnginePage::MoveToPreviousWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // try to move past the document end + page->triggerAction(QWebEnginePage::MoveToEndOfDocument); + page->triggerAction(QWebEnginePage::MoveToNextChar); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 12); + page->triggerAction(QWebEnginePage::MoveToEndOfDocument); + page->triggerAction(QWebEnginePage::MoveToNextWord); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 12); + + delete page; +#endif +} + +void tst_QWebEnginePage::textSelection() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + CursorTrackedPage* page = new CursorTrackedPage; + QString content("

The quick brown fox

" \ + "

jumps over the lazy dog

" \ + "

May the source
be with you!

"); + page->setHtml(content); + + // these actions must exist + QVERIFY(page->action(QWebEnginePage::SelectAll) != 0); + QVERIFY(page->action(QWebEnginePage::SelectNextChar) != 0); + QVERIFY(page->action(QWebEnginePage::SelectPreviousChar) != 0); + QVERIFY(page->action(QWebEnginePage::SelectNextWord) != 0); + QVERIFY(page->action(QWebEnginePage::SelectPreviousWord) != 0); + QVERIFY(page->action(QWebEnginePage::SelectNextLine) != 0); + QVERIFY(page->action(QWebEnginePage::SelectPreviousLine) != 0); + QVERIFY(page->action(QWebEnginePage::SelectStartOfLine) != 0); + QVERIFY(page->action(QWebEnginePage::SelectEndOfLine) != 0); + QVERIFY(page->action(QWebEnginePage::SelectStartOfBlock) != 0); + QVERIFY(page->action(QWebEnginePage::SelectEndOfBlock) != 0); + QVERIFY(page->action(QWebEnginePage::SelectStartOfDocument) != 0); + QVERIFY(page->action(QWebEnginePage::SelectEndOfDocument) != 0); + + // right now they are disabled because contentEditable is false and + // there isn't an existing selection to modify + QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), false); + + // ..but SelectAll is awalys enabled + QCOMPARE(page->action(QWebEnginePage::SelectAll)->isEnabled(), true); + + // Verify hasSelection returns false since there is no selection yet... + QCOMPARE(page->hasSelection(), false); + + // this will select the first paragraph + QString selectScript = "var range = document.createRange(); " \ + "var node = document.getElementById(\"one\"); " \ + "range.selectNode(node); " \ + "getSelection().addRange(range);"; + page->evaluateJavaScript(selectScript); + QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); + QRegExp regExp(" style=\".*\""); + regExp.setMinimal(true); + QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("

The quick brown fox

")); + + // Make sure hasSelection returns true, since there is selected text now... + QCOMPARE(page->hasSelection(), true); + + // here the actions are enabled after a selection has been created + QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); + + // make it editable before navigating the cursor + page->setContentEditable(true); + + // cursor will be before the word "The", this makes sure there is a charet + page->triggerAction(QWebEnginePage::MoveToStartOfDocument); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // here the actions are enabled after contentEditable is true + QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); + + delete page; +#endif +} + +void tst_QWebEnginePage::textEditing() +{ +#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) + QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); +#else + CursorTrackedPage* page = new CursorTrackedPage; + QString content("

The quick brown fox

" \ + "

jumps over the lazy dog

" \ + "

May the source
be with you!

"); + page->setHtml(content); + + // these actions must exist + QVERIFY(page->action(QWebEnginePage::Cut) != 0); + QVERIFY(page->action(QWebEnginePage::Copy) != 0); + QVERIFY(page->action(QWebEnginePage::Paste) != 0); + QVERIFY(page->action(QWebEnginePage::DeleteStartOfWord) != 0); + QVERIFY(page->action(QWebEnginePage::DeleteEndOfWord) != 0); + QVERIFY(page->action(QWebEnginePage::SetTextDirectionDefault) != 0); + QVERIFY(page->action(QWebEnginePage::SetTextDirectionLeftToRight) != 0); + QVERIFY(page->action(QWebEnginePage::SetTextDirectionRightToLeft) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleBold) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleItalic) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleUnderline) != 0); + QVERIFY(page->action(QWebEnginePage::InsertParagraphSeparator) != 0); + QVERIFY(page->action(QWebEnginePage::InsertLineSeparator) != 0); + QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle) != 0); + QVERIFY(page->action(QWebEnginePage::RemoveFormat) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleStrikethrough) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleSubscript) != 0); + QVERIFY(page->action(QWebEnginePage::ToggleSuperscript) != 0); + QVERIFY(page->action(QWebEnginePage::InsertUnorderedList) != 0); + QVERIFY(page->action(QWebEnginePage::InsertOrderedList) != 0); + QVERIFY(page->action(QWebEnginePage::Indent) != 0); + QVERIFY(page->action(QWebEnginePage::Outdent) != 0); + QVERIFY(page->action(QWebEnginePage::AlignCenter) != 0); + QVERIFY(page->action(QWebEnginePage::AlignJustified) != 0); + QVERIFY(page->action(QWebEnginePage::AlignLeft) != 0); + QVERIFY(page->action(QWebEnginePage::AlignRight) != 0); + + // right now they are disabled because contentEditable is false + QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), false); + + // Select everything + page->triggerAction(QWebEnginePage::SelectAll); + + // make sure it is enabled since there is a selection + QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), true); + + // make it editable before navigating the cursor + page->setContentEditable(true); + + // clear the selection + page->triggerAction(QWebEnginePage::MoveToStartOfDocument); + QVERIFY(page->isSelectionCollapsed()); + QCOMPARE(page->selectionStartOffset(), 0); + + // make sure it is disabled since there isn't a selection + QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), false); + + // here the actions are enabled after contentEditable is true + QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), true); + + // make sure these are disabled since there isn't a selection + QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); + QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); + + // make sure everything is selected + page->triggerAction(QWebEnginePage::SelectAll); + + // this is only true if there is an editable selection + QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), true); + QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), true); + + delete page; +#endif +} + +void tst_QWebEnginePage::requestCache() +{ + TestPage page; + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + + page.setUrl(QString("data:text/html,Click me")); + QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(page.navigations.count(), 1); + + page.setUrl(QString("data:text/html,Click me2")); + QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(page.navigations.count(), 2); + + page.triggerAction(QWebEnginePage::Stop); + QVERIFY(page.history()->canGoBack()); + page.triggerAction(QWebEnginePage::Back); + + QTRY_COMPARE(loadSpy.count(), 3); + QTRY_COMPARE(page.navigations.count(), 3); + QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), + (int)QNetworkRequest::PreferNetwork); + QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), + (int)QNetworkRequest::PreferNetwork); + QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), + (int)QNetworkRequest::PreferCache); +} + +void tst_QWebEnginePage::loadCachedPage() +{ +#if !defined(QWEBENGINESETTINGS) + QSKIP("QWEBENGINESETTINGS"); +#else + TestPage page; + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + page.settings()->setMaximumPagesInCache(3); + + page.load(QUrl("data:text/html,This is first page")); + + QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(page.navigations.count(), 1); + + QUrl firstPageUrl = page.url(); + page.load(QUrl("data:text/html,This is second page")); + + QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(page.navigations.count(), 2); + + page.triggerAction(QWebEnginePage::Stop); + QVERIFY(page.history()->canGoBack()); + + QSignalSpy urlSpy(&page, SIGNAL(urlChanged(QUrl))); + QVERIFY(urlSpy.isValid()); + + page.triggerAction(QWebEnginePage::Back); + ::waitForSignal(&page, SIGNAL(urlChanged(QUrl))); + QCOMPARE(urlSpy.size(), 1); + + QList arguments1 = urlSpy.takeFirst(); + QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl); +#endif +} + +void tst_QWebEnginePage::backActionUpdate() +{ + QWebEngineView view; + QWebEnginePage *page = view.page(); + QAction *action = page->action(QWebEnginePage::Back); + QVERIFY(!action->isEnabled()); + QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); + QUrl url = QUrl("qrc:///resources/framedindex.html"); + page->load(url); + QTRY_COMPARE(loadSpy.count(), 1); + QVERIFY(!action->isEnabled()); + QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10)); + QTRY_COMPARE(loadSpy.count(), 2); + + QVERIFY(action->isEnabled()); +} + +#if defined(QWEBENGINEFRAME) +void frameAtHelper(QWebEnginePage* webPage, QWebEngineFrame* webFrame, QPoint framePosition) +{ + if (!webFrame) + return; + + framePosition += QPoint(webFrame->pos()); + QList children = webFrame->childFrames(); + for (int i = 0; i < children.size(); ++i) { + if (children.at(i)->childFrames().size() > 0) + frameAtHelper(webPage, children.at(i), framePosition); + + QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size()); + QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft())); + } +} +#endif + +void tst_QWebEnginePage::frameAt() +{ +#if !defined(QWEBENGINEFRAME) + QSKIP("QWEBENGINEFRAME"); +#else + QWebEngineView webView; + QWebEnginePage* webPage = webView.page(); + QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool))); + QUrl url = QUrl("qrc:///resources/iframe.html"); + webPage->load(url); + QTRY_COMPARE(loadSpy.count(), 1); + frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos()); +#endif +} + +void tst_QWebEnginePage::inputMethods_data() +{ + QTest::addColumn("viewType"); + QTest::newRow("QWebEngineView") << "QWebEngineView"; + QTest::newRow("QGraphicsWebView") << "QGraphicsWebView"; +} + +static Qt::InputMethodHints inputMethodHints(QObject* object) +{ + if (QGraphicsObject* o = qobject_cast(object)) + return o->inputMethodHints(); + if (QWidget* w = qobject_cast(object)) + return w->inputMethodHints(); + return Qt::InputMethodHints(); +} + +static bool inputMethodEnabled(QObject* object) +{ + if (QGraphicsObject* o = qobject_cast(object)) + return o->flags() & QGraphicsItem::ItemAcceptsInputMethod; + if (QWidget* w = qobject_cast(object)) + return w->testAttribute(Qt::WA_InputMethodEnabled); + return false; +} + +static void clickOnPage(QWebEnginePage* page, const QPoint& position) +{ + QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); + page->event(&evpres); + QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); + page->event(&evrel); +} + +void tst_QWebEnginePage::inputMethods() +{ +#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) + QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); +#else + QFETCH(QString, viewType); + QWebEnginePage* page = new QWebEnginePage; + QObject* view = 0; + QObject* container = 0; + if (viewType == "QWebEngineView") { + QWebEngineView* wv = new QWebEngineView; + wv->setPage(page); + view = wv; + container = view; + } else if (viewType == "QGraphicsWebView") { + QGraphicsWebView* wv = new QGraphicsWebView; + wv->setPage(page); + view = wv; + + QGraphicsView* gv = new QGraphicsView; + QGraphicsScene* scene = new QGraphicsScene(gv); + gv->setScene(scene); + scene->addItem(wv); + wv->setGeometry(QRect(0, 0, 500, 500)); + + container = gv; + } else + QVERIFY2(false, "Unknown view type"); + + page->settings()->setFontFamily(QWebEngineSettings::SerifFont, page->settings()->fontFamily(QWebEngineSettings::FixedFont)); + page->setHtml("" \ + "
" \ + "" \ + ""); + page->mainFrame()->setFocus(); + + TestInputContext testContext; + + QWebEngineElementCollection inputs = page->mainFrame()->documentElement().findAll("input"); + QPoint textInputCenter = inputs.at(0).geometry().center(); + + clickOnPage(page, textInputCenter); + + // This part of the test checks if the SIP (Software Input Panel) is triggered, + // which normally happens on mobile platforms, when a user input form receives + // a mouse click. + int inputPanel = 0; + if (viewType == "QWebEngineView") { + if (QWebEngineView* wv = qobject_cast(view)) + inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); + } else if (viewType == "QGraphicsWebView") { + if (QGraphicsWebView* wv = qobject_cast(view)) + inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); + } + + // For non-mobile platforms RequestSoftwareInputPanel event is not called + // because there is no SIP (Software Input Panel) triggered. In the case of a + // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked + // and the RequestSoftwareInputPanel event is called. For these two situations + // this part of the test can verified as the checks below. + if (inputPanel) + QVERIFY(testContext.isInputPanelVisible()); + else + QVERIFY(!testContext.isInputPanelVisible()); + testContext.hideInputPanel(); + + clickOnPage(page, textInputCenter); + QVERIFY(testContext.isInputPanelVisible()); + + //ImMicroFocus + QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus); + QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); + + // We assigned the serif font famility to be the same as the fixef font family. + // Then test ImFont on a serif styled element, we should get our fixef font family. + variant = page->inputMethodQuery(Qt::ImFont); + QFont font = variant.value(); + QCOMPARE(page->settings()->fontFamily(QWebEngineSettings::FixedFont), font.family()); + + QList inputAttributes; + + //Insert text. + { + QInputMethodEvent eventText("QtWebEngine", inputAttributes); + QSignalSpy signalSpy(page, SIGNAL(microFocusChanged())); + page->event(&eventText); + QCOMPARE(signalSpy.count(), 0); + } + + { + QInputMethodEvent eventText("", inputAttributes); + eventText.setCommitString(QString("QtWebEngine"), 0, 0); + page->event(&eventText); + } + + //ImMaximumTextLength + variant = page->inputMethodQuery(Qt::ImMaximumTextLength); + QCOMPARE(20, variant.toInt()); + + //Set selection + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); + QInputMethodEvent eventSelection("",inputAttributes); + page->event(&eventSelection); + + //ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + int anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 3); + + //ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + int cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 5); + + //ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + QString selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("eb")); + + //Set selection with negative length + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); + QInputMethodEvent eventSelection3("",inputAttributes); + page->event(&eventSelection3); + + //ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 1); + + //ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 6); + + //ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("tWebK")); + + //ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + QString value = variant.value(); + QCOMPARE(value, QString("QtWebEngine")); + + { + QList attributes; + // Clear the selection, so the next test does not clear any contents. + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("composition", attributes); + page->event(&event); + } + + // A ongoing composition should not change the surrounding text before it is committed. + variant = page->inputMethodQuery(Qt::ImSurroundingText); + value = variant.value(); + QCOMPARE(value, QString("QtWebEngine")); + + // Cancel current composition first + inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); + QInputMethodEvent eventSelection4("", inputAttributes); + page->event(&eventSelection4); + + // START - Tests for Selection when the Editor is NOT in Composition mode + + // LEFT to RIGHT selection + // Deselect the selection by sending MouseButtonPress events + // This moves the current cursor to the end of the text + clickOnPage(page, textInputCenter); + + { + QList attributes; + QInputMethodEvent event(QString(), attributes); + event.setCommitString("XXX", 0, 0); + page->event(&event); + event.setCommitString(QString(), -2, 2); // Erase two characters. + page->event(&event); + event.setCommitString(QString(), -1, 1); // Erase one character. + page->event(&event); + variant = page->inputMethodQuery(Qt::ImSurroundingText); + value = variant.value(); + QCOMPARE(value, QString("QtWebEngine")); + } + + //Move to the start of the line + page->triggerAction(QWebEnginePage::MoveToStartOfLine); + + QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier); + QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier); + + //Move 2 characters RIGHT + for (int j = 0; j < 2; ++j) { + page->event(&keyRightEventPress); + page->event(&keyRightEventRelease); + } + + //Select to the end of the line + page->triggerAction(QWebEnginePage::SelectEndOfLine); + + //ImAnchorPosition QtWebEngine + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 2); + + //ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 8); + + //ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("WebKit")); + + //RIGHT to LEFT selection + //Deselect the selection (this moves the current cursor to the end of the text) + clickOnPage(page, textInputCenter); + + //ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 8); + + //ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 8); + + //ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); + QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier); + + //Move 2 characters LEFT + for (int i = 0; i < 2; ++i) { + page->event(&keyLeftEventPress); + page->event(&keyLeftEventRelease); + } + + //Select to the start of the line + page->triggerAction(QWebEnginePage::SelectStartOfLine); + + //ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 6); + + //ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 0); + + //ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("QtWebK")); + + //END - Tests for Selection when the Editor is not in Composition mode + + //ImhHiddenText + QPoint passwordInputCenter = inputs.at(1).geometry().center(); + clickOnPage(page, passwordInputCenter); + + QVERIFY(inputMethodEnabled(view)); + QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText); + + clickOnPage(page, textInputCenter); + QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText)); + + page->setHtml("

nothing to input here"); + testContext.hideInputPanel(); + + QWebEngineElement para = page->mainFrame()->findFirstElement("p"); + clickOnPage(page, para.geometry().center()); + + QVERIFY(!testContext.isInputPanelVisible()); + + //START - Test for sending empty QInputMethodEvent + page->setHtml("" \ + "" \ + ""); + page->evaluateJavaScript("var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();"); + + //Send empty QInputMethodEvent + QInputMethodEvent emptyEvent; + page->event(&emptyEvent); + + QString inputValue = page->evaluateJavaScript("document.getElementById('input3').value").toString(); + QCOMPARE(inputValue, QString("QtWebEngine2")); + //END - Test for sending empty QInputMethodEvent + + page->setHtml("" \ + "" \ + ""); + page->evaluateJavaScript("var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();"); + + // Clear the selection, also cancel the ongoing composition if there is one. + { + QList attributes; + QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); + attributes.append(newSelection); + QInputMethodEvent event("", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + variant = page->inputMethodQuery(Qt::ImSurroundingText); + QString surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 0); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 0); + + // 1. Insert a character to the beginning of the line. + // Send temporary text, which makes the editor has composition 'm'. + { + QList attributes; + QInputMethodEvent event("m", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 0); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 0); + + // Send temporary text, which makes the editor has composition 'n'. + { + QList attributes; + QInputMethodEvent event("n", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 0); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 0); + + // Send commit text, which makes the editor conforms composition. + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("o"); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 1); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 1); + + // 2. insert a character to the middle of the line. + // Send temporary text, which makes the editor has composition 'd'. + { + QList attributes; + QInputMethodEvent event("d", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 1); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 1); + + // Send commit text, which makes the editor conforms composition. + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("e"); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 2); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 2); + + // 3. Insert a character to the end of the line. + page->triggerAction(QWebEnginePage::MoveToEndOfLine); + + // Send temporary text, which makes the editor has composition 't'. + { + QList attributes; + QInputMethodEvent event("t", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 22); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 22); + + // Send commit text, which makes the editor conforms composition. + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("t"); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 23); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 23); + + // 4. Replace the selection. + page->triggerAction(QWebEnginePage::SelectPreviousWord); + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("inputMethodt")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 11); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 23); + + // Send temporary text, which makes the editor has composition 'w'. + { + QList attributes; + QInputMethodEvent event("w", attributes); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine ")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 11); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 11); + + // Send commit text, which makes the editor conforms composition. + { + QList attributes; + QInputMethodEvent event("", attributes); + event.setCommitString("2"); + page->event(&event); + } + + // ImCurrentSelection + variant = page->inputMethodQuery(Qt::ImCurrentSelection); + selectionValue = variant.value(); + QCOMPARE(selectionValue, QString("")); + + // ImSurroundingText + variant = page->inputMethodQuery(Qt::ImSurroundingText); + surroundingValue = variant.value(); + QCOMPARE(surroundingValue, QString("oeQtWebEngine 2")); + + // ImCursorPosition + variant = page->inputMethodQuery(Qt::ImCursorPosition); + cursorPosition = variant.toInt(); + QCOMPARE(cursorPosition, 12); + + // ImAnchorPosition + variant = page->inputMethodQuery(Qt::ImAnchorPosition); + anchorPosition = variant.toInt(); + QCOMPARE(anchorPosition, 12); + + // Check sending RequestSoftwareInputPanel event + page->setHtml("" \ + "" \ + "

abc
"\ + ""); + QWebEngineElement inputElement = page->mainFrame()->findFirstElement("div"); + clickOnPage(page, inputElement.geometry().center()); + + QVERIFY(!testContext.isInputPanelVisible()); + + // START - Newline test for textarea + qApp->processEvents(); + page->setHtml("" \ + "
+ diff --git a/tests/auto/widgets/qwebengineview/resources/scrolltest_page.html b/tests/auto/widgets/qwebengineview/resources/scrolltest_page.html new file mode 100644 index 000000000..18fcbbebe --- /dev/null +++ b/tests/auto/widgets/qwebengineview/resources/scrolltest_page.html @@ -0,0 +1,6 @@ + +Scrolling test + +
+ + diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp new file mode 100644 index 000000000..352040bab --- /dev/null +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -0,0 +1,552 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2009 Torch Mobile Inc. + Copyright (C) 2009 Girish Ramakrishnan + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include +#include "../util.h" + +#include +#include +#include +#include +#include + +#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \ + QVERIFY(actual == expect); + +class tst_QWebEngineView : public QObject +{ + Q_OBJECT + +public Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void init(); + void cleanup(); + +private Q_SLOTS: + void renderingAfterMaxAndBack(); + void renderHints(); + void getWebKitVersion(); + + void reusePage_data(); + void reusePage(); + void microFocusCoordinates(); + void focusInputTypes(); + void horizontalScrollbarTest(); + + void crashTests(); +#if !(defined(WTF_USE_QT_MOBILE_THEME) && WTF_USE_QT_MOBILE_THEME) + void setPalette_data(); + void setPalette(); +#endif +}; + +// This will be called before the first test function is executed. +// It is only called once. +void tst_QWebEngineView::initTestCase() +{ +} + +// This will be called after the last test function is executed. +// It is only called once. +void tst_QWebEngineView::cleanupTestCase() +{ +} + +// This will be called before each test function is executed. +void tst_QWebEngineView::init() +{ +} + +// This will be called after every test function. +void tst_QWebEngineView::cleanup() +{ +} + +void tst_QWebEngineView::renderHints() +{ +#if !defined(QWEBENGINEVIEW_RENDERHINTS) + QSKIP("QWEBENGINEVIEW_RENDERHINTS"); +#else + QWebEngineView webView; + + // default is only text antialiasing + smooth pixmap transform + QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); + QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); + QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); + QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); + + webView.setRenderHint(QPainter::Antialiasing, true); + QVERIFY(webView.renderHints() & QPainter::Antialiasing); + QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); + QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); + QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); + + webView.setRenderHint(QPainter::Antialiasing, false); + QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); + QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); + QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); + QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); + + webView.setRenderHint(QPainter::SmoothPixmapTransform, true); + QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); + QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); + QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); + QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); + + webView.setRenderHint(QPainter::SmoothPixmapTransform, false); + QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); + QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform)); + QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); +#endif +} + +void tst_QWebEngineView::getWebKitVersion() +{ +#if !defined(QWEBENGINEVERSION) + QSKIP("QWEBENGINEVERSION"); +#else + QVERIFY(qWebKitVersion().toDouble() > 0); +#endif +} + +void tst_QWebEngineView::reusePage_data() +{ + QTest::addColumn("html"); + QTest::newRow("WithoutPlugin") << "text"; + QTest::newRow("WindowedPlugin") << QString("text"); + QTest::newRow("WindowlessPlugin") << QString("text"); +} + +void tst_QWebEngineView::reusePage() +{ +#if !defined(QWEBENGINEPAGE_SETHTML) + QSKIP("QWEBENGINEPAGE_SETHTML"); +#else + if (!QDir(TESTS_SOURCE_DIR).exists()) + W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); + + QDir::setCurrent(TESTS_SOURCE_DIR); + + QFETCH(QString, html); + QWebEngineView* view1 = new QWebEngineView; + QPointer page = new QWebEnginePage; + view1->setPage(page.data()); + page.data()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); + page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); + if (html.contains("")) { + // some reasonable time for the PluginStream to feed test.swf to flash and start painting + waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000); + } + + view1->show(); + QTest::qWaitForWindowExposed(view1); + delete view1; + QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view + + QWebEngineView *view2 = new QWebEngineView; + view2->setPage(page.data()); + view2->show(); // in Windowless mode, you should still be able to see the plugin here + QTest::qWaitForWindowExposed(view2); + delete view2; + + delete page.data(); // must not crash + + QDir::setCurrent(QApplication::applicationDirPath()); +#endif +} + +// Class used in crashTests +class WebViewCrashTest : public QObject { + Q_OBJECT + QWebEngineView* m_view; +public: + bool m_executed; + + + WebViewCrashTest(QWebEngineView* view) + : m_view(view) + , m_executed(false) + { + view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int))); + } + +private Q_SLOTS: + void loading(int progress) + { + if (progress >= 20 && progress < 90) { + QVERIFY(!m_executed); + m_view->stop(); + m_executed = true; + } + } +}; + + +// Should not crash. +void tst_QWebEngineView::crashTests() +{ + // Test if loading can be stopped in loadProgress handler without crash. + // Test page should have frames. + QWebEngineView view; + WebViewCrashTest tester(&view); + QUrl url("qrc:///resources/index.html"); + view.load(url); + QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed. +} + +void tst_QWebEngineView::microFocusCoordinates() +{ +#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) + QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); +#else + QWebEnginePage* page = new QWebEnginePage; + QWebEngineView* webView = new QWebEngineView; + webView->setPage( page ); + + page->setHtml("" \ + "
" \ + "" \ + "
" \ + "" \ + ""); + +#if defined(QWEBENGINEFRAME) + page->mainFrame()->setFocus(); +#endif + + QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); + QVERIFY(initialMicroFocus.isValid()); + + page->scroll(0,50); + + QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); + QVERIFY(currentMicroFocus.isValid()); + + QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect()); +#endif +} + +void tst_QWebEngineView::focusInputTypes() +{ +#if !defined(QWEBENGINEELEMENT) + QSKIP("QWEBENGINEELEMENT"); +#else + QWebEngineView webView; + webView.show(); + QTest::qWaitForWindowExposed(&webView); + + QUrl url("qrc:///resources/input_types.html"); + QWebEngineFrame* const mainFrame = webView.page()->mainFrame(); + webView.load(url); + mainFrame->setFocus(); + + QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); + + // 'text' type + QWebEngineElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + QVERIFY(webView.inputMethodHints() == Qt::ImhNone); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'password' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'tel' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDialableCharactersOnly); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'number' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDigitsOnly); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'email' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhEmailCharactersOnly); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'url' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhUrlCharactersOnly); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'password' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'text' type + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + QVERIFY(webView.inputMethodHints() == Qt::ImhNone); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'password' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); + + // 'text area' field + inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea")); + QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); + QVERIFY(webView.inputMethodHints() == Qt::ImhNone); + QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); +#endif +} + +void tst_QWebEngineView::horizontalScrollbarTest() +{ +#if !defined(QWEBENGINEPAGE_SCROLL) + QSKIP("QWEBENGINEPAGE_SCROLL"); +#else + QWebEngineView webView; + webView.resize(600, 600); + webView.show(); + QTest::qWaitForWindowExposed(&webView); + + QUrl url("qrc:///resources/scrolltest_page.html"); + webView.page()->load(url); + webView.page()->setFocus(); + + QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); + + QVERIFY(webView.page()->scrollPosition() == QPoint(0, 0)); + + // Note: The test below assumes that the layout direction is Qt::LeftToRight. + QTest::mouseClick(&webView, Qt::LeftButton, 0, QPoint(550, 595)); + QVERIFY(webView.page()->scrollPosition().x() > 0); + + // Note: The test below assumes that the layout direction is Qt::LeftToRight. + QTest::mouseClick(&webView, Qt::LeftButton, 0, QPoint(20, 595)); + QVERIFY(webView.page()->scrollPosition() == QPoint(0, 0)); +#endif +} + + +#if !(defined(WTF_USE_QT_MOBILE_THEME) && WTF_USE_QT_MOBILE_THEME) +void tst_QWebEngineView::setPalette_data() +{ + QTest::addColumn("active"); + QTest::addColumn("background"); + QTest::newRow("activeBG") << true << true; + QTest::newRow("activeFG") << true << false; + QTest::newRow("inactiveBG") << false << true; + QTest::newRow("inactiveFG") << false << false; +} + +// Render a QWebEngineView to a QImage twice, each time with a different palette set, +// verify that images rendered are not the same, confirming WebCore usage of +// custom palette on selections. +void tst_QWebEngineView::setPalette() +{ +#if !defined(QWEBCONTENTVIEW_SETPALETTE) + QSKIP("QWEBCONTENTVIEW_SETPALETTE"); +#else + QString html = "" + "" + "Some text here" + "" + ""; + + QFETCH(bool, active); + QFETCH(bool, background); + + QWidget* activeView = 0; + + // Use controlView to manage active/inactive state of test views by raising + // or lowering their position in the window stack. + QWebEngineView controlView; + controlView.setHtml(html); + + QWebEngineView view1; + + QPalette palette1; + QBrush brush1(Qt::red); + brush1.setStyle(Qt::SolidPattern); + if (active && background) { + // Rendered image must have red background on an active QWebEngineView. + palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1); + } else if (active && !background) { + // Rendered image must have red foreground on an active QWebEngineView. + palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1); + } else if (!active && background) { + // Rendered image must have red background on an inactive QWebEngineView. + palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1); + } else if (!active && !background) { + // Rendered image must have red foreground on an inactive QWebEngineView. + palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1); + } + + view1.setPalette(palette1); + view1.setHtml(html); + view1.page()->setViewportSize(view1.page()->contentsSize()); + view1.show(); + + QTest::qWaitForWindowExposed(&view1); + + if (!active) { + controlView.show(); + QTest::qWaitForWindowExposed(&controlView); + activeView = &controlView; + controlView.activateWindow(); + } else { + view1.activateWindow(); + activeView = &view1; + } + + QTRY_COMPARE(QApplication::activeWindow(), activeView); + + view1.page()->triggerAction(QWebEnginePage::SelectAll); + + QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32); + QPainter painter1(&img1); + view1.page()->render(&painter1); + painter1.end(); + view1.close(); + controlView.close(); + + QWebEngineView view2; + + QPalette palette2; + QBrush brush2(Qt::blue); + brush2.setStyle(Qt::SolidPattern); + if (active && background) { + // Rendered image must have blue background on an active QWebEngineView. + palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2); + } else if (active && !background) { + // Rendered image must have blue foreground on an active QWebEngineView. + palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2); + } else if (!active && background) { + // Rendered image must have blue background on an inactive QWebEngineView. + palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2); + } else if (!active && !background) { + // Rendered image must have blue foreground on an inactive QWebEngineView. + palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2); + } + + view2.setPalette(palette2); + view2.setHtml(html); + view2.page()->setViewportSize(view2.page()->contentsSize()); + view2.show(); + + QTest::qWaitForWindowExposed(&view2); + + if (!active) { + controlView.show(); + QTest::qWaitForWindowExposed(&controlView); + activeView = &controlView; + controlView.activateWindow(); + } else { + view2.activateWindow(); + activeView = &view2; + } + + QTRY_COMPARE(QApplication::activeWindow(), activeView); + + view2.page()->triggerAction(QWebEnginePage::SelectAll); + + QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32); + QPainter painter2(&img2); + view2.page()->render(&painter2); + painter2.end(); + + view2.close(); + controlView.close(); + + QVERIFY(img1 != img2); +#endif +} +#endif + +void tst_QWebEngineView::renderingAfterMaxAndBack() +{ +#if !defined(QWEBENGINEPAGE_RENDER) + QSKIP("QWEBENGINEPAGE_RENDER"); +#else + QUrl url = QUrl("data:text/html," + "" + "" + ""); + + QWebEngineView view; + view.page()->load(url); + QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); + view.show(); + + view.page()->settings()->setMaximumPagesInCache(3); + + QTest::qWaitForWindowExposed(&view); + + QPixmap reference(view.page()->viewportSize()); + reference.fill(Qt::red); + + QPixmap image(view.page()->viewportSize()); + QPainter painter(&image); + view.page()->render(&painter); + + QCOMPARE(image, reference); + + QUrl url2 = QUrl("data:text/html," + "" + "" + ""); + view.page()->load(url2); + + QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); + + view.showMaximized(); + + QTest::qWaitForWindowExposed(&view); + + QPixmap reference2(view.page()->viewportSize()); + reference2.fill(Qt::blue); + + QPixmap image2(view.page()->viewportSize()); + QPainter painter2(&image2); + view.page()->render(&painter2); + + QCOMPARE(image2, reference2); + + view.back(); + + QPixmap reference3(view.page()->viewportSize()); + reference3.fill(Qt::red); + QPixmap image3(view.page()->viewportSize()); + QPainter painter3(&image3); + view.page()->render(&painter3); + + QCOMPARE(image3, reference3); +#endif +} + +QTEST_MAIN(tst_QWebEngineView) +#include "tst_qwebengineview.moc" diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc new file mode 100644 index 000000000..6685a8086 --- /dev/null +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.qrc @@ -0,0 +1,8 @@ + + + resources/index.html + resources/frame_a.html + resources/input_types.html + resources/scrolltest_page.html + + diff --git a/tests/auto/widgets/resources/image2.png b/tests/auto/widgets/resources/image2.png new file mode 100644 index 000000000..8d703640c Binary files /dev/null and b/tests/auto/widgets/resources/image2.png differ diff --git a/tests/auto/widgets/resources/test.swf b/tests/auto/widgets/resources/test.swf new file mode 100644 index 000000000..895298271 Binary files /dev/null and b/tests/auto/widgets/resources/test.swf differ diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri new file mode 100644 index 000000000..3d3979986 --- /dev/null +++ b/tests/auto/widgets/tests.pri @@ -0,0 +1,24 @@ +TEMPLATE = app + +CONFIG += testcase +VPATH += $$_PRO_FILE_PWD_ +TARGET = tst_$$TARGET + +# Load mobilityconfig if Qt Mobility is available +load(mobilityconfig, true) +contains(MOBILITY_CONFIG, multimedia) { + # This define is used by tests depending on Qt Multimedia + DEFINES -= WTF_USE_QT_MULTIMEDIA=0 + DEFINES += WTF_USE_QT_MULTIMEDIA=1 +} + +SOURCES += $${TARGET}.cpp +INCLUDEPATH += \ + $$PWD \ + $$PWD/../Api + +QT += testlib network webenginewidgets widgets +include($$QTWEBENGINE_ROOT/common.pri) + +# This define is used by some tests to look up resources in the source tree +DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h new file mode 100644 index 000000000..4925aa4c7 --- /dev/null +++ b/tests/auto/widgets/util.h @@ -0,0 +1,81 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ +// Functions and macros that really need to be in QTestLib + +#if 0 +#pragma qt_no_master_include +#endif + +#include +#include +#include + +#if !defined(TESTS_SOURCE_DIR) +#define TESTS_SOURCE_DIR "" +#endif + +/** + * Starts an event loop that runs until the given signal is received. + * Optionally the event loop + * can return earlier on a timeout. + * + * \return \p true if the requested signal was received + * \p false on timeout + */ +static inline bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) +{ + QEventLoop loop; + QObject::connect(obj, signal, &loop, SLOT(quit())); + QTimer timer; + QSignalSpy timeoutSpy(&timer, SIGNAL(timeout())); + if (timeout > 0) { + QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); + timer.setSingleShot(true); + timer.start(timeout); + } + loop.exec(); + return timeoutSpy.isEmpty(); +} + +/** + * Just like QSignalSpy but facilitates sync and async + * signal emission. For example if you want to verify that + * page->foo() emitted a signal, it could be that the + * implementation decides to emit the signal asynchronously + * - in which case we want to spin a local event loop until + * emission - or that the call to foo() emits it right away. + */ +class SignalBarrier : private QSignalSpy +{ +public: + SignalBarrier(const QObject* obj, const char* aSignal) + : QSignalSpy(obj, aSignal) + { } + + bool ensureSignalEmitted() + { + bool result = count() > 0; + if (!result) + result = wait(); + clear(); + return result; + } +}; + +#define W_QSKIP(a, b) QSKIP(a) diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro new file mode 100644 index 000000000..1dd9a01a9 --- /dev/null +++ b/tests/auto/widgets/widgets.pro @@ -0,0 +1,12 @@ +TEMPLATE = subdirs + +CONFIG += ordered + +SUBDIRS += \ + # FIXME: Move useful qwebengineframe tests to qwebenginepage + # qwebengineframe \ + qwebenginepage \ + qwebenginehistoryinterface \ + qwebengineview \ + qwebenginehistory \ + qwebengineinspector \ diff --git a/tests/widgets/qwebengineframe/qwebengineframe.pro b/tests/widgets/qwebengineframe/qwebengineframe.pro deleted file mode 100644 index ff6c49628..000000000 --- a/tests/widgets/qwebengineframe/qwebengineframe.pro +++ /dev/null @@ -1,2 +0,0 @@ -include(../tests.pri) -exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc diff --git a/tests/widgets/qwebengineframe/resources/image.png b/tests/widgets/qwebengineframe/resources/image.png deleted file mode 100644 index 8d703640c..000000000 Binary files a/tests/widgets/qwebengineframe/resources/image.png and /dev/null differ diff --git a/tests/widgets/qwebengineframe/resources/style.css b/tests/widgets/qwebengineframe/resources/style.css deleted file mode 100644 index c05b747f1..000000000 --- a/tests/widgets/qwebengineframe/resources/style.css +++ /dev/null @@ -1 +0,0 @@ -#idP {color: red !important} diff --git a/tests/widgets/qwebengineframe/resources/test1.html b/tests/widgets/qwebengineframe/resources/test1.html deleted file mode 100644 index b323f966e..000000000 --- a/tests/widgets/qwebengineframe/resources/test1.html +++ /dev/null @@ -1 +0,0 @@ -

Some text 1

diff --git a/tests/widgets/qwebengineframe/resources/test2.html b/tests/widgets/qwebengineframe/resources/test2.html deleted file mode 100644 index 63ac1f6ec..000000000 --- a/tests/widgets/qwebengineframe/resources/test2.html +++ /dev/null @@ -1 +0,0 @@ -

Some text 2

diff --git a/tests/widgets/qwebengineframe/resources/testiframe.html b/tests/widgets/qwebengineframe/resources/testiframe.html deleted file mode 100644 index 4b0e30ca5..000000000 --- a/tests/widgets/qwebengineframe/resources/testiframe.html +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - -
You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. -You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. -You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. -You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. -You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible. -You can use the overflow property when you want to have better control of the layout. Try to change the overflow property to: visible, hidden, auto, or inherit and see what happens. The default value is visible.
- - - - \ No newline at end of file diff --git a/tests/widgets/qwebengineframe/resources/testiframe2.html b/tests/widgets/qwebengineframe/resources/testiframe2.html deleted file mode 100644 index 8957a5d8a..000000000 --- a/tests/widgets/qwebengineframe/resources/testiframe2.html +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - -
- - \ No newline at end of file diff --git a/tests/widgets/qwebengineframe/tst_qwebengineframe.cpp b/tests/widgets/qwebengineframe/tst_qwebengineframe.cpp deleted file mode 100644 index 11281082b..000000000 --- a/tests/widgets/qwebengineframe/tst_qwebengineframe.cpp +++ /dev/null @@ -1,1569 +0,0 @@ -/* - Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifndef QT_NO_OPENSSL -#include -#endif -#include "../util.h" - -class tst_QWebEngineFrame : public QObject -{ - Q_OBJECT - -public: - bool eventFilter(QObject* watched, QEvent* event); - -public Q_SLOTS: - void init(); - void cleanup(); - -private Q_SLOTS: - void horizontalScrollAfterBack(); - void symmetricUrl(); - void progressSignal(); - void urlChange(); - void requestedUrl(); - void requestedUrlAfterSetAndLoadFailures(); - void javaScriptWindowObjectCleared_data(); - void javaScriptWindowObjectCleared(); - void javaScriptWindowObjectClearedOnEvaluate(); - void setHtml(); - void setHtmlWithImageResource(); - void setHtmlWithStylesheetResource(); - void setHtmlWithBaseURL(); - void setHtmlWithJSAlert(); - void ipv6HostEncoding(); - void metaData(); -#if !defined(QT_NO_COMBOBOX) - void popupFocus(); -#endif - void inputFieldFocus(); - void hitTestContent(); - void baseUrl_data(); - void baseUrl(); - void hasSetFocus(); - void renderGeometry(); - void renderHints(); - void scrollPosition(); - void scrollToAnchor(); - void scrollbarsOff(); - void evaluateWillCauseRepaint(); - void setContent_data(); - void setContent(); - void setCacheLoadControlAttribute(); - void setUrlWithPendingLoads(); - void setUrlWithFragment_data(); - void setUrlWithFragment(); - void setUrlToEmpty(); - void setUrlToInvalid(); - void setUrlHistory(); - void setUrlUsingStateObject(); - void setUrlSameUrl(); - void setUrlThenLoads_data(); - void setUrlThenLoads(); - void loadFinishedAfterNotFoundError(); - void loadInSignalHandlers_data(); - void loadInSignalHandlers(); - -private: - QWebEngineView* m_view; - QWebEnginePage* m_page; - QWebEngineView* m_inputFieldsTestView; - int m_inputFieldTestPaintCount; -}; - -bool tst_QWebEngineFrame::eventFilter(QObject* watched, QEvent* event) -{ - // used on the inputFieldFocus test - if (watched == m_inputFieldsTestView) { - if (event->type() == QEvent::Paint) - m_inputFieldTestPaintCount++; - } - return QObject::eventFilter(watched, event); -} - -void tst_QWebEngineFrame::init() -{ - m_view = new QWebEngineView(); - m_page = m_view->page(); -} - -void tst_QWebEngineFrame::cleanup() -{ - delete m_view; -} - -void tst_QWebEngineFrame::symmetricUrl() -{ - QVERIFY(m_view->url().isEmpty()); - - QCOMPARE(m_view->history()->count(), 0); - - QUrl dataUrl("data:text/html,

Test"); - - m_view->setUrl(dataUrl); - QCOMPARE(m_view->url(), dataUrl); - QCOMPARE(m_view->history()->count(), 0); - - // loading is _not_ immediate, so the text isn't set just yet. - QVERIFY(m_view->page()->mainFrame()->toPlainText().isEmpty()); - - ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); - - QCOMPARE(m_view->history()->count(), 1); - QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test")); - - QUrl dataUrl2("data:text/html,

Test2"); - QUrl dataUrl3("data:text/html,

Test3"); - - m_view->setUrl(dataUrl2); - m_view->setUrl(dataUrl3); - - QCOMPARE(m_view->url(), dataUrl3); - - ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); - - QCOMPARE(m_view->history()->count(), 2); - - QCOMPARE(m_view->page()->mainFrame()->toPlainText(), QString("Test3")); -} - -void tst_QWebEngineFrame::progressSignal() -{ - QSignalSpy progressSpy(m_view, SIGNAL(loadProgress(int))); - - QUrl dataUrl("data:text/html,

Test"); - m_view->setUrl(dataUrl); - - ::waitForSignal(m_view, SIGNAL(loadFinished(bool))); - - QVERIFY(progressSpy.size() >= 2); - - // WebKit defines initialProgressValue as 10%, not 0% - QCOMPARE(progressSpy.first().first().toInt(), 10); - - // But we always end at 100% - QCOMPARE(progressSpy.last().first().toInt(), 100); -} - -void tst_QWebEngineFrame::urlChange() -{ - QSignalSpy urlSpy(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); - - QUrl dataUrl("data:text/html,

Test"); - m_view->setUrl(dataUrl); - - ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); - - QCOMPARE(urlSpy.size(), 1); - - QUrl dataUrl2("data:text/html,title

Test"); - m_view->setUrl(dataUrl2); - - ::waitForSignal(m_page->mainFrame(), SIGNAL(urlChanged(QUrl))); - - QCOMPARE(urlSpy.size(), 2); -} - -class FakeReply : public QNetworkReply { - Q_OBJECT - -public: - static const QUrl urlFor404ErrorWithoutContents; - - FakeReply(const QNetworkRequest& request, QObject* parent = 0) - : QNetworkReply(parent) - { - setOperation(QNetworkAccessManager::GetOperation); - setRequest(request); - setUrl(request.url()); - if (request.url() == QUrl("qrc:/test1.html")) { - setHeader(QNetworkRequest::LocationHeader, QString("qrc:/test2.html")); - setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html")); - QTimer::singleShot(0, this, SLOT(continueRedirect())); - } -#ifndef QT_NO_OPENSSL - else if (request.url() == QUrl("qrc:/fake-ssl-error.html")) { - setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error!")); - QTimer::singleShot(0, this, SLOT(continueError())); - } -#endif - else if (request.url().host() == QLatin1String("abcdef.abcdef")) { - setError(QNetworkReply::HostNotFoundError, tr("Invalid URL")); - QTimer::singleShot(0, this, SLOT(continueError())); - } else if (request.url() == FakeReply::urlFor404ErrorWithoutContents) { - setError(QNetworkReply::ContentNotFoundError, "Not found"); - setAttribute(QNetworkRequest::HttpStatusCodeAttribute, 404); - QTimer::singleShot(0, this, SLOT(continueError())); - } - - open(QIODevice::ReadOnly); - } - ~FakeReply() - { - close(); - } - virtual void abort() {} - virtual void close() {} - -protected: - qint64 readData(char*, qint64) - { - return 0; - } - -private Q_SLOTS: - void continueRedirect() - { - emit metaDataChanged(); - emit finished(); - } - - void continueError() - { - emit error(this->error()); - emit finished(); - } -}; - -const QUrl FakeReply::urlFor404ErrorWithoutContents = QUrl("http://this.will/return-http-404-error-without-contents.html"); - -class FakeNetworkManager : public QNetworkAccessManager { - Q_OBJECT - -public: - FakeNetworkManager(QObject* parent) : QNetworkAccessManager(parent) { } - -protected: - virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest& request, QIODevice* outgoingData) - { - QString url = request.url().toString(); - if (op == QNetworkAccessManager::GetOperation) { -#ifndef QT_NO_OPENSSL - if (url == "qrc:/fake-ssl-error.html") { - FakeReply* reply = new FakeReply(request, this); - QList errors; - emit sslErrors(reply, errors << QSslError(QSslError::UnspecifiedError)); - return reply; - } -#endif - if (url == "qrc:/test1.html" || url == "http://abcdef.abcdef/" || request.url() == FakeReply::urlFor404ErrorWithoutContents) - return new FakeReply(request, this); - } - - return QNetworkAccessManager::createRequest(op, request, outgoingData); - } -}; - -void tst_QWebEngineFrame::requestedUrl() -{ - QWebEnginePage page; - QWebEngineFrame* frame = page.mainFrame(); - - // in few seconds, the image should be completely loaded - QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); - FakeNetworkManager* networkManager = new FakeNetworkManager(&page); - page.setNetworkAccessManager(networkManager); - - frame->setUrl(QUrl("qrc:/test1.html")); - waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); - QCOMPARE(spy.count(), 1); - QCOMPARE(frame->requestedUrl(), QUrl("qrc:/test1.html")); - QCOMPARE(frame->url(), QUrl("qrc:/test2.html")); - - frame->setUrl(QUrl("qrc:/non-existent.html")); - waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); - QCOMPARE(spy.count(), 2); - QCOMPARE(frame->requestedUrl(), QUrl("qrc:/non-existent.html")); - QCOMPARE(frame->url(), QUrl("qrc:/non-existent.html")); - - frame->setUrl(QUrl("http://abcdef.abcdef")); - waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); - QCOMPARE(spy.count(), 3); - QCOMPARE(frame->requestedUrl(), QUrl("http://abcdef.abcdef/")); - QCOMPARE(frame->url(), QUrl("http://abcdef.abcdef/")); - -#ifndef QT_NO_OPENSSL - qRegisterMetaType >("QList"); - qRegisterMetaType("QNetworkReply*"); - - QSignalSpy spy2(page.networkAccessManager(), SIGNAL(sslErrors(QNetworkReply*,QList))); - frame->setUrl(QUrl("qrc:/fake-ssl-error.html")); - waitForSignal(frame, SIGNAL(loadFinished(bool)), 200); - QCOMPARE(spy2.count(), 1); - QCOMPARE(frame->requestedUrl(), QUrl("qrc:/fake-ssl-error.html")); - QCOMPARE(frame->url(), QUrl("qrc:/fake-ssl-error.html")); -#endif -} - -void tst_QWebEngineFrame::requestedUrlAfterSetAndLoadFailures() -{ - QWebEnginePage page; - QWebEngineFrame* frame = page.mainFrame(); - - QSignalSpy spy(frame, SIGNAL(loadFinished(bool))); - - const QUrl first("http://abcdef.abcdef/"); - frame->setUrl(first); - ::waitForSignal(frame, SIGNAL(loadFinished(bool))); - QCOMPARE(frame->url(), first); - QCOMPARE(frame->requestedUrl(), first); - QVERIFY(!spy.at(0).first().toBool()); - - const QUrl second("http://abcdef.abcdef/another_page.html"); - QVERIFY(first != second); - - frame->load(second); - ::waitForSignal(frame, SIGNAL(loadFinished(bool))); - QCOMPARE(frame->url(), first); - QCOMPARE(frame->requestedUrl(), second); - QVERIFY(!spy.at(1).first().toBool()); -} - -void tst_QWebEngineFrame::javaScriptWindowObjectCleared_data() -{ - QTest::addColumn("html"); - QTest::addColumn("signalCount"); - QTest::newRow("with

hello world

" << 1; - // NOTE: Empty scripts no longer cause this signal to be emitted. - QTest::newRow("with empty

hello world

" << 0; - QTest::newRow("without

hello world

"); - MyPage page; - m_view->setPage(&page); - page.mainFrame()->setHtml(html); - QCOMPARE(page.alerts, 1); - QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=118663", Continue); - QCOMPARE(m_view->page()->mainFrame()->toHtml(), html); -} - -class TestNetworkManager : public QNetworkAccessManager -{ -public: - TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} - - QList requestedUrls; - -protected: - virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { - requestedUrls.append(request.url()); - QNetworkRequest redirectedRequest = request; - redirectedRequest.setUrl(QUrl("data:text/html,

hello")); - return QNetworkAccessManager::createRequest(op, redirectedRequest, outgoingData); - } -}; - -void tst_QWebEngineFrame::ipv6HostEncoding() -{ - TestNetworkManager* networkManager = new TestNetworkManager(m_page); - m_page->setNetworkAccessManager(networkManager); - networkManager->requestedUrls.clear(); - - QUrl baseUrl = QUrl::fromEncoded("http://[::1]/index.html"); - m_view->setHtml("

Hi", baseUrl); - m_view->page()->mainFrame()->evaluateJavaScript("var r = new XMLHttpRequest();" - "r.open('GET', 'http://[::1]/test.xml', false);" - "r.send(null);" - ); - QCOMPARE(networkManager->requestedUrls.count(), 1); - QCOMPARE(networkManager->requestedUrls.at(0), QUrl::fromEncoded("http://[::1]/test.xml")); -} - -void tst_QWebEngineFrame::metaData() -{ - m_view->setHtml("" - " " - " " - " " - " " - ""); - - QMultiMap metaData = m_view->page()->mainFrame()->metaData(); - - QCOMPARE(metaData.count(), 2); - - QCOMPARE(metaData.value("description"), QString("Test description")); - QCOMPARE(metaData.value("keywords"), QString("HTML, JavaScript, Css")); - QCOMPARE(metaData.value("nonexistent"), QString()); - - m_view->setHtml("" - " " - " " - " " - " " - ""); - - metaData = m_view->page()->mainFrame()->metaData(); - - QCOMPARE(metaData.count(), 2); - - QStringList values = metaData.values("samekey"); - QCOMPARE(values.count(), 2); - - QVERIFY(values.contains("FirstValue")); - QVERIFY(values.contains("SecondValue")); - - QCOMPARE(metaData.value("nonexistent"), QString()); -} - -#if !defined(QT_NO_COMBOBOX) -void tst_QWebEngineFrame::popupFocus() -{ - QWebEngineView view; - view.setHtml("" - " " - " " - " " - " " - " " - ""); - view.resize(400, 100); - // Call setFocus before show to work around http://bugreports.qt.nokia.com/browse/QTBUG-14762 - view.setFocus(); - view.show(); - QTest::qWaitForWindowExposed(&view); - view.activateWindow(); - QTRY_VERIFY(view.hasFocus()); - - // open the popup by clicking. check if focus is on the popup - const QWebEngineElement webCombo = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("select[name=select]")); - QTest::mouseClick(&view, Qt::LeftButton, 0, webCombo.geometry().center()); - - QComboBox* combo = view.findChild(); - QVERIFY(combo != 0); - QTRY_VERIFY(!view.hasFocus() && combo->view()->hasFocus()); // Focus should be on the popup - - // hide the popup and check if focus is on the page - combo->hidePopup(); - QTRY_VERIFY(view.hasFocus()); // Focus should be back on the WebView -} -#endif - -void tst_QWebEngineFrame::inputFieldFocus() -{ - QWebEngineView view; - view.setHtml(""); - view.resize(400, 100); - view.show(); - QTest::qWaitForWindowExposed(&view); - view.activateWindow(); - view.setFocus(); - QTRY_VERIFY(view.hasFocus()); - - // double the flashing time, should at least blink once already - int delay = qApp->cursorFlashTime() * 2; - - // focus the lineedit and check if it blinks - bool autoSipEnabled = qApp->autoSipEnabled(); - qApp->setAutoSipEnabled(false); - const QWebEngineElement inputElement = view.page()->mainFrame()->documentElement().findFirst(QLatin1String("input[type=text]")); - QTest::mouseClick(&view, Qt::LeftButton, 0, inputElement.geometry().center()); - m_inputFieldsTestView = &view; - view.installEventFilter( this ); - QTest::qWait(delay); - QVERIFY2(m_inputFieldTestPaintCount >= 3, - "The input field should have a blinking caret"); - qApp->setAutoSipEnabled(autoSipEnabled); -} - -void tst_QWebEngineFrame::hitTestContent() -{ - QString html("

A paragraph




link text"); - - QWebEnginePage page; - QWebEngineFrame* frame = page.mainFrame(); - frame->setHtml(html); - page.setViewportSize(QSize(200, 0)); //no height so link is not visible - const QWebEngineElement linkElement = frame->documentElement().findFirst(QLatin1String("a#link")); - QWebEngineHitTestResult result = frame->hitTestContent(linkElement.geometry().center()); - QCOMPARE(result.linkText(), QString("link text")); - QWebEngineElement link = result.linkElement(); - QCOMPARE(link.attribute("target"), QString("_foo")); -} - -void tst_QWebEngineFrame::baseUrl_data() -{ - QTest::addColumn("html"); - QTest::addColumn("loadUrl"); - QTest::addColumn("url"); - QTest::addColumn("baseUrl"); - - QTest::newRow("null") << QString() << QUrl() - << QUrl("about:blank") << QUrl("about:blank"); - - QTest::newRow("foo") << QString() << QUrl("http://foobar.baz/") - << QUrl("http://foobar.baz/") << QUrl("http://foobar.baz/"); - - QString html = "" - "" - "" - "" - ""; - QTest::newRow("customBaseUrl") << html << QUrl("http://foobar.baz/") - << QUrl("http://foobar.baz/") << QUrl("http://foobaz.bar/"); -} - -void tst_QWebEngineFrame::baseUrl() -{ - QFETCH(QString, html); - QFETCH(QUrl, loadUrl); - QFETCH(QUrl, url); - QFETCH(QUrl, baseUrl); - - m_page->mainFrame()->setHtml(html, loadUrl); - QCOMPARE(m_page->mainFrame()->url(), url); - QCOMPARE(m_page->mainFrame()->baseUrl(), baseUrl); -} - -void tst_QWebEngineFrame::hasSetFocus() -{ - QString html("

top

" \ - " - - diff --git a/tests/widgets/qwebenginepage/resources/iframe3.html b/tests/widgets/qwebenginepage/resources/iframe3.html deleted file mode 100644 index ed6ac5b94..000000000 --- a/tests/widgets/qwebenginepage/resources/iframe3.html +++ /dev/null @@ -1,5 +0,0 @@ - - -

inner

- - diff --git a/tests/widgets/qwebenginepage/resources/index.html b/tests/widgets/qwebenginepage/resources/index.html deleted file mode 100644 index 638df364e..000000000 --- a/tests/widgets/qwebenginepage/resources/index.html +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/tests/widgets/qwebenginepage/resources/script.html b/tests/widgets/qwebenginepage/resources/script.html deleted file mode 100644 index ede986415..000000000 --- a/tests/widgets/qwebenginepage/resources/script.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/tests/widgets/qwebenginepage/resources/user.css b/tests/widgets/qwebenginepage/resources/user.css deleted file mode 100644 index 4ccb2f0fc..000000000 --- a/tests/widgets/qwebenginepage/resources/user.css +++ /dev/null @@ -1,3 +0,0 @@ -p { - background-image: url('http://does.not/exist.png'); -} \ No newline at end of file diff --git a/tests/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/widgets/qwebenginepage/tst_qwebenginepage.cpp deleted file mode 100644 index bbdc6c2e9..000000000 --- a/tests/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ /dev/null @@ -1,3628 +0,0 @@ -/* - Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2009 Girish Ramakrishnan - Copyright (C) 2010 Holger Hans Peter Freyther - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include "../util.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void removeRecursive(const QString& dirname) -{ - QDir dir(dirname); - QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); - for (int i = 0; i < entries.count(); ++i) - if (entries[i].isDir()) - removeRecursive(entries[i].filePath()); - else - dir.remove(entries[i].fileName()); - QDir().rmdir(dirname); -} - -class TestInputContext : public QPlatformInputContext -{ -public: - TestInputContext() - : m_visible(false) - { - QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = this; - } - - ~TestInputContext() - { - QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; - } - - virtual void showInputPanel() - { - m_visible = true; - } - virtual void hideInputPanel() - { - m_visible = false; - } - virtual bool isInputPanelVisible() const - { - return m_visible; - } - - bool m_visible; -}; - -class tst_QWebEnginePage : public QObject -{ - Q_OBJECT - -public: - tst_QWebEnginePage(); - virtual ~tst_QWebEnginePage(); - -public Q_SLOTS: - void init(); - void cleanup(); - void cleanupFiles(); - -private Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void thirdPartyCookiePolicy(); - void contextMenuCopy(); - void contextMenuPopulatedOnce(); - void acceptNavigationRequest(); - void geolocationRequestJS(); - void loadFinished(); - void actionStates(); - void popupFormSubmission(); - void acceptNavigationRequestWithNewWindow(); - void userStyleSheet(); - void userStyleSheetFromLocalFileUrl(); - void userStyleSheetFromQrcUrl(); - void loadHtml5Video(); - void modified(); - void contextMenuCrash(); - void updatePositionDependentActionsCrash(); - void database(); - void createPluginWithPluginsEnabled(); - void createPluginWithPluginsDisabled(); - void destroyPlugin_data(); - void destroyPlugin(); - void createViewlessPlugin_data(); - void createViewlessPlugin(); - void graphicsWidgetPlugin(); - void multiplePageGroupsAndLocalStorage(); - void cursorMovements(); - void textSelection(); - void textEditing(); - void backActionUpdate(); - void frameAt(); - void requestCache(); - void loadCachedPage(); - void protectBindingsRuntimeObjectsFromCollector(); - void localURLSchemes(); - void testOptionalJSObjects(); - void testLocalStorageVisibility(); - void testEnablePersistentStorage(); - void consoleOutput(); - void inputMethods_data(); - void inputMethods(); - void inputMethodsTextFormat_data(); - void inputMethodsTextFormat(); - void defaultTextEncoding(); - void errorPageExtension(); - void errorPageExtensionInIFrames(); - void errorPageExtensionInFrameset(); - void errorPageExtensionLoadFinished(); - void userAgentApplicationName(); - void userAgentNewlineStripping(); - void undoActionHaveCustomText(); - - void viewModes(); - - void crashTests_LazyInitializationOfMainFrame(); - - void screenshot_data(); - void screenshot(); - -#if defined(ENABLE_WEBGL) && ENABLE_WEBGL - void acceleratedWebGLScreenshotWithoutView(); - void unacceleratedWebGLScreenshotWithoutView(); -#endif - - void originatingObjectInNetworkRequests(); - void networkReplyParentDidntChange(); - void destroyQNAMBeforeAbortDoesntCrash(); - void testJSPrompt(); - void showModalDialog(); - void testStopScheduledPageRefresh(); - void findText(); - void supportedContentType(); - // [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT - // https://bugs.webengine.org/show_bug.cgi?id=79040 - // void infiniteLoopJS(); - void navigatorCookieEnabled(); - void deleteQWebEngineViewTwice(); - void renderOnRepaintRequestedShouldNotRecurse(); - void loadSignalsOrder_data(); - void loadSignalsOrder(); - void openWindowDefaultSize(); - void cssMediaTypeGlobalSetting(); - void cssMediaTypePageSetting(); - -#ifdef Q_OS_MAC - void macCopyUnicodeToClipboard(); -#endif - -private: - QWebEngineView* m_view; - QWebEnginePage* m_page; - QString tmpDirPath() const - { - static QString tmpd = QDir::tempPath() + "/tst_qwebenginepage-" - + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")); - return tmpd; - } -}; - -tst_QWebEnginePage::tst_QWebEnginePage() -{ -} - -tst_QWebEnginePage::~tst_QWebEnginePage() -{ -} - -void tst_QWebEnginePage::init() -{ - m_view = new QWebEngineView(); - m_page = m_view->page(); -} - -void tst_QWebEnginePage::cleanup() -{ - delete m_view; -} - -void tst_QWebEnginePage::cleanupFiles() -{ - removeRecursive(tmpDirPath()); -} - -void tst_QWebEnginePage::initTestCase() -{ - cleanupFiles(); // In case there are old files from previous runs -} - -void tst_QWebEnginePage::cleanupTestCase() -{ - cleanupFiles(); // Be nice -} - -class NavigationRequestOverride : public QWebEnginePage -{ -public: - NavigationRequestOverride(QWebEngineView* parent, bool initialValue) : QWebEnginePage(parent), m_acceptNavigationRequest(initialValue) {} - - bool m_acceptNavigationRequest; -protected: - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, QWebEnginePage::NavigationType type) { - Q_UNUSED(frame); - Q_UNUSED(request); - Q_UNUSED(type); - - return m_acceptNavigationRequest; - } -}; - -void tst_QWebEnginePage::acceptNavigationRequest() -{ -#if !defined(QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST) - QSKIP("QWEBENGINEPAGE_ACCEPTNAVIGATIONREQUEST"); -#else - QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); - - NavigationRequestOverride* newPage = new NavigationRequestOverride(m_view, false); - m_view->setPage(newPage); - - m_view->setHtml(QString("
" - "
"), QUrl()); - QTRY_COMPARE(loadSpy.count(), 1); - - m_view->page()->evaluateJavaScript("tstform.submit();"); - - newPage->m_acceptNavigationRequest = true; - m_view->page()->evaluateJavaScript("tstform.submit();"); - QTRY_COMPARE(loadSpy.count(), 2); - - QCOMPARE(m_view->page()->toPlainText(), QString("foo?")); - - // Restore default page - m_view->setPage(0); -#endif -} - -#if defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) -class JSTestPage : public QWebEnginePage -{ -Q_OBJECT -public: - JSTestPage(QObject* parent = 0) - : QWebEnginePage(parent) {} - - virtual bool shouldInterruptJavaScript() - { - return true; - } -public Q_SLOTS: - void requestPermission(QWebEngineFrame* frame, QWebEnginePage::Feature feature) - { - if (m_allowGeolocation) - setFeaturePermission(frame, feature, PermissionGrantedByUser); - else - setFeaturePermission(frame, feature, PermissionDeniedByUser); - } - -public: - void setGeolocationPermission(bool allow) - { - m_allowGeolocation = allow; - } - -private: - bool m_allowGeolocation; -}; -#endif - -// [Qt] tst_QWebEnginePage::infiniteLoopJS() timeouts with DFG JIT -// https://bugs.webengine.org/show_bug.cgi?id=79040 -/* -void tst_QWebEnginePage::infiniteLoopJS() -{ - JSTestPage* newPage = new JSTestPage(m_view); - m_view->setPage(newPage); - m_view->setHtml(QString("test"), QUrl()); - m_view->page()->evaluateJavaScript("var run = true; var a = 1; while (run) { a++; }"); - delete newPage; -} -*/ - -void tst_QWebEnginePage::geolocationRequestJS() -{ -#if !defined(QWEBENGINEPAGE_SETFEATUREPERMISSION) - QSKIP("QWEBENGINEPAGE_SETFEATUREPERMISSION"); -#else - JSTestPage* newPage = new JSTestPage(m_view); - - if (newPage->evaluateJavaScript(QLatin1String("!navigator.geolocation")).toBool()) { - delete newPage; - W_QSKIP("Geolocation is not supported.", SkipSingle); - } - - connect(newPage, SIGNAL(featurePermissionRequested(QWebEngineFrame*, QWebEnginePage::Feature)), - newPage, SLOT(requestPermission(QWebEngineFrame*, QWebEnginePage::Feature))); - - newPage->setGeolocationPermission(false); - m_view->setPage(newPage); - m_view->setHtml(QString("test"), QUrl()); - m_view->page()->evaluateJavaScript("var errorCode = 0; function error(err) { errorCode = err.code; } function success(pos) { } navigator.geolocation.getCurrentPosition(success, error)"); - QTest::qWait(2000); - QVariant empty = m_view->page()->evaluateJavaScript("errorCode"); - - QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=102235", Continue); - QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 0); - - newPage->setGeolocationPermission(true); - m_view->page()->evaluateJavaScript("errorCode = 0; navigator.geolocation.getCurrentPosition(success, error);"); - empty = m_view->page()->evaluateJavaScript("errorCode"); - - //http://dev.w3.org/geo/api/spec-source.html#position - //PositionError: const unsigned short PERMISSION_DENIED = 1; - QVERIFY(empty.type() == QVariant::Double && empty.toInt() != 1); - delete newPage; -#endif -} - -void tst_QWebEnginePage::loadFinished() -{ - qRegisterMetaType("QNetworkRequest*"); - QSignalSpy spyLoadStarted(m_view, SIGNAL(loadStarted())); - QSignalSpy spyLoadFinished(m_view, SIGNAL(loadFinished(bool))); - - m_view->page()->load(QUrl("data:text/html,foo \">" - "")); - QTRY_COMPARE(spyLoadFinished.count(), 1); - - QTRY_VERIFY(spyLoadStarted.count() > 1); - QTRY_VERIFY(spyLoadFinished.count() > 1); - - spyLoadFinished.clear(); - - m_view->page()->load(QUrl("data:text/html,")); - QTRY_COMPARE(spyLoadFinished.count(), 1); - QCOMPARE(spyLoadFinished.count(), 1); -} - -void tst_QWebEnginePage::actionStates() -{ - QWebEnginePage* page = m_view->page(); - - page->load(QUrl("qrc:///resources/script.html")); - - QAction* reloadAction = page->action(QWebEnginePage::Reload); - QAction* stopAction = page->action(QWebEnginePage::Stop); - - QTRY_VERIFY(reloadAction->isEnabled()); - QTRY_VERIFY(!stopAction->isEnabled()); -} - -class ConsolePage : public QWebEnginePage -{ -public: - ConsolePage(QObject* parent = 0) : QWebEnginePage(parent) {} - - virtual void javaScriptConsoleMessage(const QString& message, int lineNumber, const QString& sourceID) - { - messages.append(message); - lineNumbers.append(lineNumber); - sourceIDs.append(sourceID); - } - - QStringList messages; - QList lineNumbers; - QStringList sourceIDs; -}; - -void tst_QWebEnginePage::consoleOutput() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - ConsolePage page; - page.evaluateJavaScript("this is not valid JavaScript"); - QCOMPARE(page.messages.count(), 1); - QCOMPARE(page.lineNumbers.at(0), 1); -#endif -} - -class TestPage : public QWebEnginePage { - Q_OBJECT -public: - TestPage(QObject* parent = 0) : QWebEnginePage(parent) - { - connect(this, SIGNAL(geometryChangeRequested(QRect)), this, SLOT(slotGeometryChangeRequested(QRect))); - } - - struct Navigation { - QWebEngineFrame *frame; - QNetworkRequest request; - NavigationType type; - }; - - QList navigations; - QList createdWindows; - QRect requestedGeometry; - - virtual bool acceptNavigationRequest(QWebEngineFrame* frame, const QNetworkRequest &request, NavigationType type) { - Navigation n; - n.frame = frame; - n.request = request; - n.type = type; - navigations.append(n); - return true; - } - - virtual QWebEnginePage* createWindow(WebWindowType) { - TestPage* page = new TestPage(this); - createdWindows.append(page); - return page; - } - -private Q_SLOTS: - void slotGeometryChangeRequested(const QRect& geom) { - requestedGeometry = geom; - } -}; - -void tst_QWebEnginePage::popupFormSubmission() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - TestPage page; - page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); - page.setHtml("
"\ - ""\ - "
"); - page.evaluateJavaScript("window.open('', 'myNewWin', 'width=500,height=300,toolbar=0')"); - page.evaluateJavaScript("document.form1.submit();"); - - QTest::qWait(500); - // The number of popup created should be one. - QVERIFY(page.createdWindows.size() == 1); - - QString url = page.createdWindows.takeFirst()->url().toString(); - // Check if the form submission was OK. - QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=118597", Continue); - QVERIFY(url.contains("?foo=bar")); -#endif -} - -void tst_QWebEnginePage::acceptNavigationRequestWithNewWindow() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage* page = new TestPage(m_view); - page->settings()->setAttribute(QWebEngineSettings::LinksIncludedInFocusChain, true); - m_page = page; - m_view->setPage(m_page); - - m_view->setUrl(QString("data:text/html,Click me")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QFocusEvent fe(QEvent::FocusIn); - m_page->event(&fe); - - QVERIFY(m_page->focusNextPrevChild(/*next*/ true)); - - QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - m_page->event(&keyEnter); - - QCOMPARE(page->navigations.count(), 2); - - TestPage::Navigation n = page->navigations.at(1); - QVERIFY(!n.frame); - QCOMPARE(n.request.url().toString(), QString("data:text/html,Reached")); - QVERIFY(n.type == QWebEnginePage::NavigationTypeLinkClicked); - - QCOMPARE(page->createdWindows.count(), 1); -#endif -} - -class TestNetworkManager : public QNetworkAccessManager -{ -public: - TestNetworkManager(QObject* parent) : QNetworkAccessManager(parent) {} - - QList requestedUrls; - QList requests; - -protected: - virtual QNetworkReply* createRequest(Operation op, const QNetworkRequest &request, QIODevice* outgoingData) { - requests.append(request); - requestedUrls.append(request.url()); - return QNetworkAccessManager::createRequest(op, request, outgoingData); - } -}; - -void tst_QWebEnginePage::userStyleSheet() -{ -#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); -#else - TestNetworkManager* networkManager = new TestNetworkManager(m_page); - m_page->setNetworkAccessManager(networkManager); - - m_page->settings()->setUserStyleSheetUrl(QUrl("data:text/css;charset=utf-8;base64," - + QByteArray("p { background-image: url('http://does.not/exist.png');}").toBase64())); - m_view->setHtml("

hello world

"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QVERIFY(networkManager->requestedUrls.count() >= 1); - QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); -#endif -} - -void tst_QWebEnginePage::userStyleSheetFromLocalFileUrl() -{ -#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); -#else - TestNetworkManager* networkManager = new TestNetworkManager(m_page); - m_page->setNetworkAccessManager(networkManager); - - QUrl styleSheetUrl = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginepage/resources/user.css")); - m_page->settings()->setUserStyleSheetUrl(styleSheetUrl); - m_view->setHtml("

hello world

"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QVERIFY(networkManager->requestedUrls.count() >= 1); - QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); -#endif -} - -void tst_QWebEnginePage::userStyleSheetFromQrcUrl() -{ -#if !defined(QWEBENGINEPAGE_SETNETWORKACCESSMANAGER) - QSKIP("QWEBENGINEPAGE_SETNETWORKACCESSMANAGER"); -#else - TestNetworkManager* networkManager = new TestNetworkManager(m_page); - m_page->setNetworkAccessManager(networkManager); - - m_page->settings()->setUserStyleSheetUrl(QUrl("qrc:///resources/user.css")); - m_view->setHtml("

hello world

"); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QVERIFY(networkManager->requestedUrls.count() >= 1); - QCOMPARE(networkManager->requestedUrls.at(0), QUrl("http://does.not/exist.png")); -#endif -} - -void tst_QWebEnginePage::loadHtml5Video() -{ -#if defined(WTF_USE_QT_MULTIMEDIA) && WTF_USE_QT_MULTIMEDIA - QByteArray url("http://does.not/exist?a=1%2Cb=2"); - m_view->setHtml("

"); - QTest::qWait(2000); - QUrl mUrl = DumpRenderTreeSupportQt::mediaContentUrlByElementId(m_page->mainFrame()->handle(), "video"); - QEXPECT_FAIL("", "https://bugs.webengine.org/show_bug.cgi?id=65452", Continue); - QCOMPARE(mUrl.toEncoded(), url); -#else - W_QSKIP("This test requires Qt Multimedia", SkipAll); -#endif -} - -void tst_QWebEnginePage::viewModes() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - m_view->setHtml(""); - m_page->setProperty("_q_viewMode", "minimized"); - - QVariant empty = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode)\")"); - QVERIFY(empty.type() == QVariant::Bool && empty.toBool()); - - QVariant minimized = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode: minimized)\")"); - QVERIFY(minimized.type() == QVariant::Bool && minimized.toBool()); - - QVariant maximized = m_page->evaluateJavaScript("window.styleMedia.matchMedium(\"(-webengine-view-mode: maximized)\")"); - QVERIFY(maximized.type() == QVariant::Bool && !maximized.toBool()); -#endif -} - -void tst_QWebEnginePage::modified() -{ -#if !defined(QWEBENGINEPAGE_ISMODIFIED) - QSKIP("QWEBENGINEPAGE_ISMODIFIED"); -#else - m_page->setUrl(QUrl("data:text/html,blub")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - m_page->setUrl(QUrl("data:text/html,blah")); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QVERIFY(!m_page->isModified()); - -// m_page->evaluateJavaScript("alert(document.getElementById('foo'))"); - m_page->evaluateJavaScript("document.getElementById('foo').focus()"); - m_page->evaluateJavaScript("document.execCommand('InsertText', true, 'Test');"); - - QVERIFY(m_page->isModified()); - - m_page->evaluateJavaScript("document.execCommand('Undo', true);"); - - QVERIFY(!m_page->isModified()); - - m_page->evaluateJavaScript("document.execCommand('Redo', true);"); - - QVERIFY(m_page->isModified()); - - QVERIFY(m_page->history()->canGoBack()); - QVERIFY(!m_page->history()->canGoForward()); - QCOMPARE(m_page->history()->count(), 2); - QVERIFY(m_page->history()->backItem().isValid()); - QVERIFY(!m_page->history()->forwardItem().isValid()); - - m_page->history()->back(); - QVERIFY(::waitForSignal(m_view, SIGNAL(loadFinished(bool)))); - - QVERIFY(!m_page->history()->canGoBack()); - QVERIFY(m_page->history()->canGoForward()); - - QVERIFY(!m_page->isModified()); - - QVERIFY(m_page->history()->currentItemIndex() == 0); - - m_page->history()->setMaximumItemCount(3); - QVERIFY(m_page->history()->maximumItemCount() == 3); - - QVariant variant("string test"); - m_page->history()->currentItem().setUserData(variant); - QVERIFY(m_page->history()->currentItem().userData().toString() == "string test"); - - m_page->setUrl(QUrl("data:text/html,This is second page")); - m_page->setUrl(QUrl("data:text/html,This is third page")); - QVERIFY(m_page->history()->count() == 2); - m_page->setUrl(QUrl("data:text/html,This is fourth page")); - QVERIFY(m_page->history()->count() == 2); - m_page->setUrl(QUrl("data:text/html,This is fifth page")); - QVERIFY(::waitForSignal(m_page, SIGNAL(saveFrameStateRequested(QWebEngineFrame*,QWebEngineHistoryItem*)))); -#endif -} - -// https://bugs.webengine.org/show_bug.cgi?id=51331 -void tst_QWebEnginePage::updatePositionDependentActionsCrash() -{ -#if !defined(QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS) - QSKIP("QWEBENGINEPAGE_UPDATEPOSITIONDEPENDENTACTIONS"); -#else - QWebEngineView view; - view.setHtml("

test"); - QPoint pos(0, 0); - view.page()->updatePositionDependentActions(pos); - QMenu* contextMenu = 0; - foreach (QObject* child, view.children()) { - contextMenu = qobject_cast(child); - if (contextMenu) - break; - } - QVERIFY(!contextMenu); -#endif -} - -// https://bugs.webengine.org/show_bug.cgi?id=20357 -void tst_QWebEnginePage::contextMenuCrash() -{ -#if !defined(QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT) - QSKIP("QWEBENGINEPAGE_SWALLOWCONTEXTMENUEVENT"); -#else - QWebEngineView view; - view.setHtml("

test"); - QPoint pos(0, 0); - QContextMenuEvent event(QContextMenuEvent::Mouse, pos); - view.page()->swallowContextMenuEvent(&event); - view.page()->updatePositionDependentActions(pos); - QMenu* contextMenu = 0; - foreach (QObject* child, view.children()) { - contextMenu = qobject_cast(child); - if (contextMenu) - break; - } - QVERIFY(contextMenu); - delete contextMenu; -#endif -} - -void tst_QWebEnginePage::database() -{ -#if !defined(QWEBENGINEDATABASE) - QSKIP("QWEBENGINEDATABASE"); -#else - QString path = tmpDirPath(); - m_page->settings()->setOfflineStoragePath(path); - QVERIFY(m_page->settings()->offlineStoragePath() == path); - - QWebEngineSettings::setOfflineStorageDefaultQuota(1024 * 1024); - QVERIFY(QWebEngineSettings::offlineStorageDefaultQuota() == 1024 * 1024); - - m_page->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); - m_page->settings()->setAttribute(QWebEngineSettings::OfflineStorageDatabaseEnabled, true); - - QString dbFileName = path + "Databases.db"; - - if (QFile::exists(dbFileName)) - QFile::remove(dbFileName); - - qRegisterMetaType("QWebEngineFrame*"); - QSignalSpy spy(m_page, SIGNAL(databaseQuotaExceeded(QWebEngineFrame*,QString))); - m_view->setHtml(QString("

"), QUrl("http://www.myexample.com")); - QTRY_COMPARE(spy.count(), 1); - m_page->evaluateJavaScript("var db2; db2=openDatabase('testdb', '1.0', 'test database API', 50000);"); - QTRY_COMPARE(spy.count(),1); - - m_page->evaluateJavaScript("localStorage.test='This is a test for local storage';"); - m_view->setHtml(QString("text"), QUrl("http://www.myexample.com")); - - QVariant s1 = m_page->evaluateJavaScript("localStorage.test"); - QCOMPARE(s1.toString(), QString("This is a test for local storage")); - - m_page->evaluateJavaScript("sessionStorage.test='This is a test for session storage';"); - m_view->setHtml(QString("text"), QUrl("http://www.myexample.com")); - QVariant s2 = m_page->evaluateJavaScript("sessionStorage.test"); - QCOMPARE(s2.toString(), QString("This is a test for session storage")); - - m_view->setHtml(QString("
"), QUrl("http://www.myexample.com")); - m_page->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) { });"); - QTest::qWait(200); - - // Remove all databases. - QWebEngineSecurityOrigin origin = m_page->mainFrame()->securityOrigin(); - QList dbs = origin.databases(); - for (int i = 0; i < dbs.count(); i++) { - QString fileName = dbs[i].fileName(); - QVERIFY(QFile::exists(fileName)); - QWebEngineDatabase::removeDatabase(dbs[i]); - QVERIFY(!QFile::exists(fileName)); - } - QVERIFY(!origin.databases().size()); - // Remove removed test :-) - QWebEngineDatabase::removeAllDatabases(); - QVERIFY(!origin.databases().size()); -#endif -} - -#if defined(QWEBENGINEPAGE_CREATEPLUGIN) -class PluginPage : public QWebEnginePage -{ -public: - PluginPage(QObject *parent = 0) - : QWebEnginePage(parent) {} - - struct CallInfo - { - CallInfo(const QString &c, const QUrl &u, - const QStringList &pn, const QStringList &pv, - QObject *r) - : classid(c), url(u), paramNames(pn), - paramValues(pv), returnValue(r) - {} - QString classid; - QUrl url; - QStringList paramNames; - QStringList paramValues; - QObject *returnValue; - }; - - QList calls; - -protected: - virtual QObject *createPlugin(const QString &classid, const QUrl &url, - const QStringList ¶mNames, - const QStringList ¶mValues) - { - QObject *result = 0; - if (classid == "pushbutton") - result = new QPushButton(); -#ifndef QT_NO_INPUTDIALOG - else if (classid == "lineedit") - result = new QLineEdit(); -#endif - else if (classid == "graphicswidget") - result = new QGraphicsWidget(); - if (result) - result->setObjectName(classid); - calls.append(CallInfo(classid, url, paramNames, paramValues, result)); - return result; - } -}; - -static void createPlugin(QWebEngineView *view) -{ - QSignalSpy loadSpy(view, SIGNAL(loadFinished(bool))); - - PluginPage* newPage = new PluginPage(view); - view->setPage(newPage); - - // type has to be application/x-qt-plugin - view->setHtml(QString("")); - QTRY_COMPARE(loadSpy.count(), 1); - QCOMPARE(newPage->calls.count(), 0); - - view->setHtml(QString("")); - QTRY_COMPARE(loadSpy.count(), 2); - QCOMPARE(newPage->calls.count(), 1); - { - PluginPage::CallInfo ci = newPage->calls.takeFirst(); - QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); - QCOMPARE(ci.url, QUrl()); - QCOMPARE(ci.paramNames.count(), 3); - QCOMPARE(ci.paramValues.count(), 3); - QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); - QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); - QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); - QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); - QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); - QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); - QVERIFY(ci.returnValue != 0); - QVERIFY(ci.returnValue->inherits("QPushButton")); - } - // test JS bindings - QCOMPARE(newPage->evaluateJavaScript("document.getElementById('mybutton').toString()").toString(), - QString::fromLatin1("[object HTMLObjectElement]")); - QCOMPARE(newPage->evaluateJavaScript("mybutton.toString()").toString(), - QString::fromLatin1("[object HTMLObjectElement]")); - QCOMPARE(newPage->evaluateJavaScript("typeof mybutton.objectName").toString(), - QString::fromLatin1("string")); - QCOMPARE(newPage->evaluateJavaScript("mybutton.objectName").toString(), - QString::fromLatin1("pushbutton")); - QCOMPARE(newPage->evaluateJavaScript("typeof mybutton.clicked").toString(), - QString::fromLatin1("function")); - QCOMPARE(newPage->evaluateJavaScript("mybutton.clicked.toString()").toString(), - QString::fromLatin1("function clicked() {\n [native code]\n}")); - - view->setHtml(QString("" - "" - "" - "
"), QUrl("http://foo.bar.baz")); - QTRY_COMPARE(loadSpy.count(), 3); - QCOMPARE(newPage->calls.count(), 2); - { - PluginPage::CallInfo ci = newPage->calls.takeFirst(); - QCOMPARE(ci.classid, QString::fromLatin1("lineedit")); - QCOMPARE(ci.url, QUrl()); - QCOMPARE(ci.paramNames.count(), 3); - QCOMPARE(ci.paramValues.count(), 3); - QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); - QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); - QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); - QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("lineedit")); - QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); - QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("myedit")); - QVERIFY(ci.returnValue != 0); - QVERIFY(ci.returnValue->inherits("QLineEdit")); - } - { - PluginPage::CallInfo ci = newPage->calls.takeFirst(); - QCOMPARE(ci.classid, QString::fromLatin1("pushbutton")); - QCOMPARE(ci.url, QUrl()); - QCOMPARE(ci.paramNames.count(), 3); - QCOMPARE(ci.paramValues.count(), 3); - QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); - QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); - QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); - QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("pushbutton")); - QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); - QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mybutton")); - QVERIFY(ci.returnValue != 0); - QVERIFY(ci.returnValue->inherits("QPushButton")); - } -} -#endif - -void tst_QWebEnginePage::graphicsWidgetPlugin() -{ -#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) - QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); -#else - m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); - QGraphicsWebView webView; - - QSignalSpy loadSpy(&webView, SIGNAL(loadFinished(bool))); - - PluginPage* newPage = new PluginPage(&webView); - webView.setPage(newPage); - - // type has to be application/x-qt-plugin - webView.setHtml(QString("")); - QTRY_COMPARE(loadSpy.count(), 1); - QCOMPARE(newPage->calls.count(), 0); - - webView.setHtml(QString("")); - QTRY_COMPARE(loadSpy.count(), 2); - QCOMPARE(newPage->calls.count(), 1); - { - PluginPage::CallInfo ci = newPage->calls.takeFirst(); - QCOMPARE(ci.classid, QString::fromLatin1("graphicswidget")); - QCOMPARE(ci.url, QUrl()); - QCOMPARE(ci.paramNames.count(), 3); - QCOMPARE(ci.paramValues.count(), 3); - QCOMPARE(ci.paramNames.at(0), QString::fromLatin1("type")); - QCOMPARE(ci.paramValues.at(0), QString::fromLatin1("application/x-qt-plugin")); - QCOMPARE(ci.paramNames.at(1), QString::fromLatin1("classid")); - QCOMPARE(ci.paramValues.at(1), QString::fromLatin1("graphicswidget")); - QCOMPARE(ci.paramNames.at(2), QString::fromLatin1("id")); - QCOMPARE(ci.paramValues.at(2), QString::fromLatin1("mygraphicswidget")); - QVERIFY(ci.returnValue); - QVERIFY(ci.returnValue->inherits("QGraphicsWidget")); - } - // test JS bindings - QCOMPARE(newPage->evaluateJavaScript("document.getElementById('mygraphicswidget').toString()").toString(), - QString::fromLatin1("[object HTMLObjectElement]")); - QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.toString()").toString(), - QString::fromLatin1("[object HTMLObjectElement]")); - QCOMPARE(newPage->evaluateJavaScript("typeof mygraphicswidget.objectName").toString(), - QString::fromLatin1("string")); - QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.objectName").toString(), - QString::fromLatin1("graphicswidget")); - QCOMPARE(newPage->evaluateJavaScript("typeof mygraphicswidget.geometryChanged").toString(), - QString::fromLatin1("function")); - QCOMPARE(newPage->evaluateJavaScript("mygraphicswidget.geometryChanged.toString()").toString(), - QString::fromLatin1("function geometryChanged() {\n [native code]\n}")); -#endif -} - -void tst_QWebEnginePage::createPluginWithPluginsEnabled() -{ -#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) - QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); -#else - m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); - createPlugin(m_view); -#endif -} - -void tst_QWebEnginePage::createPluginWithPluginsDisabled() -{ -#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) - QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); -#else - // Qt Plugins should be loaded by QtWebEngine even when PluginsEnabled is - // false. The client decides whether a Qt plugin is enabled or not when - // it decides whether or not to instantiate it. - m_view->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, false); - createPlugin(m_view); -#endif -} - -#if defined(QWEBENGINEPAGE_CREATEPLUGIN) -// Standard base class for template PluginTracerPage. In tests it is used as interface. -class PluginCounterPage : public QWebEnginePage { -public: - int m_count; - QPointer m_widget; - QObject* m_pluginParent; - PluginCounterPage(QObject* parent = 0) - : QWebEnginePage(parent) - , m_count(0) - , m_pluginParent(0) - { - settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); - } - ~PluginCounterPage() - { - if (m_pluginParent) - m_pluginParent->deleteLater(); - } -}; - -template -class PluginTracerPage : public PluginCounterPage { -public: - PluginTracerPage(QObject* parent = 0) - : PluginCounterPage(parent) - { - // this is a dummy parent object for the created plugin - m_pluginParent = new T; - } - virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&) - { - m_count++; - m_widget = new T; - // need a cast to the specific type, as QObject::setParent cannot be called, - // because it is not virtual. Instead it is necessary to call QWidget::setParent, - // which also takes a QWidget* instead of a QObject*. Therefore we need to - // upcast to T*, which is a QWidget. - static_cast(m_widget.data())->setParent(static_cast(m_pluginParent)); - return m_widget.data(); - } -}; - -class PluginFactory { -public: - enum FactoredType {QWidgetType, QGraphicsWidgetType}; - static PluginCounterPage* create(FactoredType type, QObject* parent = 0) - { - PluginCounterPage* result = 0; - switch (type) { - case QWidgetType: - result = new PluginTracerPage(parent); - break; - case QGraphicsWidgetType: - result = new PluginTracerPage(parent); - break; - default: {/*Oops*/}; - } - return result; - } - - static void prepareTestData() - { - QTest::addColumn("type"); - QTest::newRow("QWidget") << (int)PluginFactory::QWidgetType; - QTest::newRow("QGraphicsWidget") << (int)PluginFactory::QGraphicsWidgetType; - } -}; -#endif - -void tst_QWebEnginePage::destroyPlugin_data() -{ -#if defined(QWEBENGINEPAGE_CREATEPLUGIN) - PluginFactory::prepareTestData(); -#endif -} - -void tst_QWebEnginePage::destroyPlugin() -{ -#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) - QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); -#else - QFETCH(int, type); - PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type, m_view); - m_view->setPage(page); - - // we create the plugin, so the widget should be constructed - QString content(""); - m_view->setHtml(content); - QVERIFY(page->m_widget); - QCOMPARE(page->m_count, 1); - - // navigate away, the plugin widget should be destructed - m_view->setHtml("Hi"); - QTestEventLoop::instance().enterLoop(1); - QVERIFY(!page->m_widget); -#endif -} - -void tst_QWebEnginePage::createViewlessPlugin_data() -{ -#if defined(QWEBENGINEPAGE_CREATEPLUGIN) - PluginFactory::prepareTestData(); -#endif -} - -void tst_QWebEnginePage::createViewlessPlugin() -{ -#if !defined(QWEBENGINEPAGE_CREATEPLUGIN) - QSKIP("QWEBENGINEPAGE_CREATEPLUGIN"); -#else - QFETCH(int, type); - PluginCounterPage* page = PluginFactory::create((PluginFactory::FactoredType)type); - QString content(""); - page->setHtml(content); - QCOMPARE(page->m_count, 1); - QVERIFY(page->m_widget); - QVERIFY(page->m_pluginParent); - QVERIFY(page->m_widget.data()->parent() == page->m_pluginParent); - delete page; -#endif -} - -void tst_QWebEnginePage::multiplePageGroupsAndLocalStorage() -{ -#if !defined(QWEBENGINESETTINGS_SETLOCALSTORAGEPATH) - QSKIP("QWEBENGINESETTINGS_SETLOCALSTORAGEPATH"); -#else - QDir dir(tmpDirPath()); - dir.mkdir("path1"); - dir.mkdir("path2"); - - QWebEngineView view1; - QWebEngineView view2; - - view1.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); - view1.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path1")); - DumpRenderTreeSupportQt::webPageSetGroupName(view1.page()->handle(), "group1"); - view2.page()->settings()->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); - view2.page()->settings()->setLocalStoragePath(QDir::toNativeSeparators(tmpDirPath() + "/path2")); - DumpRenderTreeSupportQt::webPageSetGroupName(view2.page()->handle(), "group2"); - QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view1.page()->handle()), QString("group1")); - QCOMPARE(DumpRenderTreeSupportQt::webPageGroupName(view2.page()->handle()), QString("group2")); - - - view1.setHtml(QString(" "), QUrl("http://www.myexample.com")); - view2.setHtml(QString(" "), QUrl("http://www.myexample.com")); - - view1.page()->evaluateJavaScript("localStorage.test='value1';"); - view2.page()->evaluateJavaScript("localStorage.test='value2';"); - - view1.setHtml(QString(" "), QUrl("http://www.myexample.com")); - view2.setHtml(QString(" "), QUrl("http://www.myexample.com")); - - QVariant s1 = view1.page()->evaluateJavaScript("localStorage.test"); - QCOMPARE(s1.toString(), QString("value1")); - - QVariant s2 = view2.page()->evaluateJavaScript("localStorage.test"); - QCOMPARE(s2.toString(), QString("value2")); - - QTest::qWait(1000); - - QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path1/http_www.myexample.com_0.localstorage")); - QFile::remove(QDir::toNativeSeparators(tmpDirPath() + "/path2/http_www.myexample.com_0.localstorage")); - dir.rmdir(QDir::toNativeSeparators("./path1")); - dir.rmdir(QDir::toNativeSeparators("./path2")); -#endif -} - -#if defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) -class CursorTrackedPage : public QWebEnginePage -{ -public: - - CursorTrackedPage(QWidget *parent = 0): QWebEnginePage(parent) { - setViewportSize(QSize(1024, 768)); // big space - } - - QString selectedText() { - return evaluateJavaScript("window.getSelection().toString()").toString(); - } - - int selectionStartOffset() { - return evaluateJavaScript("window.getSelection().getRangeAt(0).startOffset").toInt(); - } - - int selectionEndOffset() { - return evaluateJavaScript("window.getSelection().getRangeAt(0).endOffset").toInt(); - } - - // true if start offset == end offset, i.e. no selected text - int isSelectionCollapsed() { - return evaluateJavaScript("window.getSelection().getRangeAt(0).collapsed").toBool(); - } -}; -#endif - -void tst_QWebEnginePage::cursorMovements() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - CursorTrackedPage* page = new CursorTrackedPage; - QString content("

The quick brown fox

jumps over the lazy dog

May the source
be with you!

"); - page->setHtml(content); - - // this will select the first paragraph - QString script = "var range = document.createRange(); " \ - "var node = document.getElementById(\"one\"); " \ - "range.selectNode(node); " \ - "getSelection().addRange(range);"; - page->evaluateJavaScript(script); - QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); - - QRegExp regExp(" style=\".*\""); - regExp.setMinimal(true); - QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("

The quick brown fox

")); - - // these actions must exist - QVERIFY(page->action(QWebEnginePage::MoveToNextChar) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToPreviousChar) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToNextWord) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToPreviousWord) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToNextLine) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToPreviousLine) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToStartOfLine) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToEndOfLine) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToStartOfBlock) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToEndOfBlock) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToStartOfDocument) != 0); - QVERIFY(page->action(QWebEnginePage::MoveToEndOfDocument) != 0); - - // right now they are disabled because contentEditable is false - QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), false); - - // make it editable before navigating the cursor - page->setContentEditable(true); - - // here the actions are enabled after contentEditable is true - QCOMPARE(page->action(QWebEnginePage::MoveToNextChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToNextWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToNextLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToPreviousLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToStartOfDocument)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::MoveToEndOfDocument)->isEnabled(), true); - - // cursor will be before the word "jump" - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // cursor will be between 'j' and 'u' in the word "jump" - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 1); - - // cursor will be between 'u' and 'm' in the word "jump" - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 2); - - // cursor will be after the word "jump" - page->triggerAction(QWebEnginePage::MoveToNextWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 5); - - // cursor will be after the word "lazy" - page->triggerAction(QWebEnginePage::MoveToNextWord); - page->triggerAction(QWebEnginePage::MoveToNextWord); - page->triggerAction(QWebEnginePage::MoveToNextWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 19); - - // cursor will be between 'z' and 'y' in "lazy" - page->triggerAction(QWebEnginePage::MoveToPreviousChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 18); - - // cursor will be between 'a' and 'z' in "lazy" - page->triggerAction(QWebEnginePage::MoveToPreviousChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 17); - - // cursor will be before the word "lazy" - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 15); - - // cursor will be before the word "quick" - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 4); - - // cursor will be between 'p' and 's' in the word "jumps" - page->triggerAction(QWebEnginePage::MoveToNextWord); - page->triggerAction(QWebEnginePage::MoveToNextWord); - page->triggerAction(QWebEnginePage::MoveToNextWord); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 4); - - // cursor will be before the word "jumps" - page->triggerAction(QWebEnginePage::MoveToStartOfLine); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // cursor will be after the word "dog" - page->triggerAction(QWebEnginePage::MoveToEndOfLine); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 23); - - // cursor will be between 'w' and 'n' in "brown" - page->triggerAction(QWebEnginePage::MoveToStartOfLine); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 14); - - // cursor will be after the word "fox" - page->triggerAction(QWebEnginePage::MoveToEndOfLine); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 19); - - // cursor will be before the word "The" - page->triggerAction(QWebEnginePage::MoveToStartOfDocument); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // cursor will be after the word "you!" - page->triggerAction(QWebEnginePage::MoveToEndOfDocument); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 12); - - // cursor will be before the word "be" - page->triggerAction(QWebEnginePage::MoveToStartOfBlock); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // cursor will be after the word "you!" - page->triggerAction(QWebEnginePage::MoveToEndOfBlock); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 12); - - // try to move before the document start - page->triggerAction(QWebEnginePage::MoveToStartOfDocument); - page->triggerAction(QWebEnginePage::MoveToPreviousChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - page->triggerAction(QWebEnginePage::MoveToStartOfDocument); - page->triggerAction(QWebEnginePage::MoveToPreviousWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // try to move past the document end - page->triggerAction(QWebEnginePage::MoveToEndOfDocument); - page->triggerAction(QWebEnginePage::MoveToNextChar); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 12); - page->triggerAction(QWebEnginePage::MoveToEndOfDocument); - page->triggerAction(QWebEnginePage::MoveToNextWord); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 12); - - delete page; -#endif -} - -void tst_QWebEnginePage::textSelection() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - CursorTrackedPage* page = new CursorTrackedPage; - QString content("

The quick brown fox

" \ - "

jumps over the lazy dog

" \ - "

May the source
be with you!

"); - page->setHtml(content); - - // these actions must exist - QVERIFY(page->action(QWebEnginePage::SelectAll) != 0); - QVERIFY(page->action(QWebEnginePage::SelectNextChar) != 0); - QVERIFY(page->action(QWebEnginePage::SelectPreviousChar) != 0); - QVERIFY(page->action(QWebEnginePage::SelectNextWord) != 0); - QVERIFY(page->action(QWebEnginePage::SelectPreviousWord) != 0); - QVERIFY(page->action(QWebEnginePage::SelectNextLine) != 0); - QVERIFY(page->action(QWebEnginePage::SelectPreviousLine) != 0); - QVERIFY(page->action(QWebEnginePage::SelectStartOfLine) != 0); - QVERIFY(page->action(QWebEnginePage::SelectEndOfLine) != 0); - QVERIFY(page->action(QWebEnginePage::SelectStartOfBlock) != 0); - QVERIFY(page->action(QWebEnginePage::SelectEndOfBlock) != 0); - QVERIFY(page->action(QWebEnginePage::SelectStartOfDocument) != 0); - QVERIFY(page->action(QWebEnginePage::SelectEndOfDocument) != 0); - - // right now they are disabled because contentEditable is false and - // there isn't an existing selection to modify - QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), false); - - // ..but SelectAll is awalys enabled - QCOMPARE(page->action(QWebEnginePage::SelectAll)->isEnabled(), true); - - // Verify hasSelection returns false since there is no selection yet... - QCOMPARE(page->hasSelection(), false); - - // this will select the first paragraph - QString selectScript = "var range = document.createRange(); " \ - "var node = document.getElementById(\"one\"); " \ - "range.selectNode(node); " \ - "getSelection().addRange(range);"; - page->evaluateJavaScript(selectScript); - QCOMPARE(page->selectedText().trimmed(), QString::fromLatin1("The quick brown fox")); - QRegExp regExp(" style=\".*\""); - regExp.setMinimal(true); - QCOMPARE(page->selectedHtml().trimmed().replace(regExp, ""), QString::fromLatin1("

The quick brown fox

")); - - // Make sure hasSelection returns true, since there is selected text now... - QCOMPARE(page->hasSelection(), true); - - // here the actions are enabled after a selection has been created - QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); - - // make it editable before navigating the cursor - page->setContentEditable(true); - - // cursor will be before the word "The", this makes sure there is a charet - page->triggerAction(QWebEnginePage::MoveToStartOfDocument); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // here the actions are enabled after contentEditable is true - QCOMPARE(page->action(QWebEnginePage::SelectNextChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousChar)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectNextWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectNextLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectPreviousLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfLine)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfBlock)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectStartOfDocument)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SelectEndOfDocument)->isEnabled(), true); - - delete page; -#endif -} - -void tst_QWebEnginePage::textEditing() -{ -#if !defined(QWEBENGINEPAGE_EVALUATEJAVASCRIPT) - QSKIP("QWEBENGINEPAGE_EVALUATEJAVASCRIPT"); -#else - CursorTrackedPage* page = new CursorTrackedPage; - QString content("

The quick brown fox

" \ - "

jumps over the lazy dog

" \ - "

May the source
be with you!

"); - page->setHtml(content); - - // these actions must exist - QVERIFY(page->action(QWebEnginePage::Cut) != 0); - QVERIFY(page->action(QWebEnginePage::Copy) != 0); - QVERIFY(page->action(QWebEnginePage::Paste) != 0); - QVERIFY(page->action(QWebEnginePage::DeleteStartOfWord) != 0); - QVERIFY(page->action(QWebEnginePage::DeleteEndOfWord) != 0); - QVERIFY(page->action(QWebEnginePage::SetTextDirectionDefault) != 0); - QVERIFY(page->action(QWebEnginePage::SetTextDirectionLeftToRight) != 0); - QVERIFY(page->action(QWebEnginePage::SetTextDirectionRightToLeft) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleBold) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleItalic) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleUnderline) != 0); - QVERIFY(page->action(QWebEnginePage::InsertParagraphSeparator) != 0); - QVERIFY(page->action(QWebEnginePage::InsertLineSeparator) != 0); - QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle) != 0); - QVERIFY(page->action(QWebEnginePage::RemoveFormat) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleStrikethrough) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleSubscript) != 0); - QVERIFY(page->action(QWebEnginePage::ToggleSuperscript) != 0); - QVERIFY(page->action(QWebEnginePage::InsertUnorderedList) != 0); - QVERIFY(page->action(QWebEnginePage::InsertOrderedList) != 0); - QVERIFY(page->action(QWebEnginePage::Indent) != 0); - QVERIFY(page->action(QWebEnginePage::Outdent) != 0); - QVERIFY(page->action(QWebEnginePage::AlignCenter) != 0); - QVERIFY(page->action(QWebEnginePage::AlignJustified) != 0); - QVERIFY(page->action(QWebEnginePage::AlignLeft) != 0); - QVERIFY(page->action(QWebEnginePage::AlignRight) != 0); - - // right now they are disabled because contentEditable is false - QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), false); - - // Select everything - page->triggerAction(QWebEnginePage::SelectAll); - - // make sure it is enabled since there is a selection - QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), true); - - // make it editable before navigating the cursor - page->setContentEditable(true); - - // clear the selection - page->triggerAction(QWebEnginePage::MoveToStartOfDocument); - QVERIFY(page->isSelectionCollapsed()); - QCOMPARE(page->selectionStartOffset(), 0); - - // make sure it is disabled since there isn't a selection - QCOMPARE(page->action(QWebEnginePage::Copy)->isEnabled(), false); - - // here the actions are enabled after contentEditable is true - QCOMPARE(page->action(QWebEnginePage::Paste)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::DeleteStartOfWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::DeleteEndOfWord)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionDefault)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionLeftToRight)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::SetTextDirectionRightToLeft)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleBold)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleItalic)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleUnderline)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::InsertParagraphSeparator)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::InsertLineSeparator)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleStrikethrough)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleSubscript)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::ToggleSuperscript)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::InsertUnorderedList)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::InsertOrderedList)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::Indent)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::Outdent)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::AlignCenter)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::AlignJustified)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::AlignLeft)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::AlignRight)->isEnabled(), true); - - // make sure these are disabled since there isn't a selection - QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), false); - QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), false); - - // make sure everything is selected - page->triggerAction(QWebEnginePage::SelectAll); - - // this is only true if there is an editable selection - QCOMPARE(page->action(QWebEnginePage::Cut)->isEnabled(), true); - QCOMPARE(page->action(QWebEnginePage::RemoveFormat)->isEnabled(), true); - - delete page; -#endif -} - -void tst_QWebEnginePage::requestCache() -{ - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - - page.setUrl(QString("data:text/html,Click me")); - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - page.setUrl(QString("data:text/html,Click me2")); - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - page.triggerAction(QWebEnginePage::Back); - - QTRY_COMPARE(loadSpy.count(), 3); - QTRY_COMPARE(page.navigations.count(), 3); - QCOMPARE(page.navigations.at(0).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(1).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferNetwork); - QCOMPARE(page.navigations.at(2).request.attribute(QNetworkRequest::CacheLoadControlAttribute, QNetworkRequest::PreferNetwork).toInt(), - (int)QNetworkRequest::PreferCache); -} - -void tst_QWebEnginePage::loadCachedPage() -{ -#if !defined(QWEBENGINESETTINGS) - QSKIP("QWEBENGINESETTINGS"); -#else - TestPage page; - QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); - page.settings()->setMaximumPagesInCache(3); - - page.load(QUrl("data:text/html,This is first page")); - - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(page.navigations.count(), 1); - - QUrl firstPageUrl = page.url(); - page.load(QUrl("data:text/html,This is second page")); - - QTRY_COMPARE(loadSpy.count(), 2); - QTRY_COMPARE(page.navigations.count(), 2); - - page.triggerAction(QWebEnginePage::Stop); - QVERIFY(page.history()->canGoBack()); - - QSignalSpy urlSpy(&page, SIGNAL(urlChanged(QUrl))); - QVERIFY(urlSpy.isValid()); - - page.triggerAction(QWebEnginePage::Back); - ::waitForSignal(&page, SIGNAL(urlChanged(QUrl))); - QCOMPARE(urlSpy.size(), 1); - - QList arguments1 = urlSpy.takeFirst(); - QCOMPARE(arguments1.at(0).toUrl(), firstPageUrl); -#endif -} - -void tst_QWebEnginePage::backActionUpdate() -{ - QWebEngineView view; - QWebEnginePage *page = view.page(); - QAction *action = page->action(QWebEnginePage::Back); - QVERIFY(!action->isEnabled()); - QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); - QUrl url = QUrl("qrc:///resources/framedindex.html"); - page->load(url); - QTRY_COMPARE(loadSpy.count(), 1); - QVERIFY(!action->isEnabled()); - QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10)); - QTRY_COMPARE(loadSpy.count(), 2); - - QVERIFY(action->isEnabled()); -} - -#if defined(QWEBENGINEFRAME) -void frameAtHelper(QWebEnginePage* webPage, QWebEngineFrame* webFrame, QPoint framePosition) -{ - if (!webFrame) - return; - - framePosition += QPoint(webFrame->pos()); - QList children = webFrame->childFrames(); - for (int i = 0; i < children.size(); ++i) { - if (children.at(i)->childFrames().size() > 0) - frameAtHelper(webPage, children.at(i), framePosition); - - QRect frameRect(children.at(i)->pos() + framePosition, children.at(i)->geometry().size()); - QVERIFY(children.at(i) == webPage->frameAt(frameRect.topLeft())); - } -} -#endif - -void tst_QWebEnginePage::frameAt() -{ -#if !defined(QWEBENGINEFRAME) - QSKIP("QWEBENGINEFRAME"); -#else - QWebEngineView webView; - QWebEnginePage* webPage = webView.page(); - QSignalSpy loadSpy(webPage, SIGNAL(loadFinished(bool))); - QUrl url = QUrl("qrc:///resources/iframe.html"); - webPage->load(url); - QTRY_COMPARE(loadSpy.count(), 1); - frameAtHelper(webPage, webPage->mainFrame(), webPage->mainFrame()->pos()); -#endif -} - -void tst_QWebEnginePage::inputMethods_data() -{ - QTest::addColumn("viewType"); - QTest::newRow("QWebEngineView") << "QWebEngineView"; - QTest::newRow("QGraphicsWebView") << "QGraphicsWebView"; -} - -static Qt::InputMethodHints inputMethodHints(QObject* object) -{ - if (QGraphicsObject* o = qobject_cast(object)) - return o->inputMethodHints(); - if (QWidget* w = qobject_cast(object)) - return w->inputMethodHints(); - return Qt::InputMethodHints(); -} - -static bool inputMethodEnabled(QObject* object) -{ - if (QGraphicsObject* o = qobject_cast(object)) - return o->flags() & QGraphicsItem::ItemAcceptsInputMethod; - if (QWidget* w = qobject_cast(object)) - return w->testAttribute(Qt::WA_InputMethodEnabled); - return false; -} - -static void clickOnPage(QWebEnginePage* page, const QPoint& position) -{ - QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); - page->event(&evpres); - QMouseEvent evrel(QEvent::MouseButtonRelease, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); - page->event(&evrel); -} - -void tst_QWebEnginePage::inputMethods() -{ -#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) - QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); -#else - QFETCH(QString, viewType); - QWebEnginePage* page = new QWebEnginePage; - QObject* view = 0; - QObject* container = 0; - if (viewType == "QWebEngineView") { - QWebEngineView* wv = new QWebEngineView; - wv->setPage(page); - view = wv; - container = view; - } else if (viewType == "QGraphicsWebView") { - QGraphicsWebView* wv = new QGraphicsWebView; - wv->setPage(page); - view = wv; - - QGraphicsView* gv = new QGraphicsView; - QGraphicsScene* scene = new QGraphicsScene(gv); - gv->setScene(scene); - scene->addItem(wv); - wv->setGeometry(QRect(0, 0, 500, 500)); - - container = gv; - } else - QVERIFY2(false, "Unknown view type"); - - page->settings()->setFontFamily(QWebEngineSettings::SerifFont, page->settings()->fontFamily(QWebEngineSettings::FixedFont)); - page->setHtml("" \ - "
" \ - "" \ - ""); - page->mainFrame()->setFocus(); - - TestInputContext testContext; - - QWebEngineElementCollection inputs = page->mainFrame()->documentElement().findAll("input"); - QPoint textInputCenter = inputs.at(0).geometry().center(); - - clickOnPage(page, textInputCenter); - - // This part of the test checks if the SIP (Software Input Panel) is triggered, - // which normally happens on mobile platforms, when a user input form receives - // a mouse click. - int inputPanel = 0; - if (viewType == "QWebEngineView") { - if (QWebEngineView* wv = qobject_cast(view)) - inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); - } else if (viewType == "QGraphicsWebView") { - if (QGraphicsWebView* wv = qobject_cast(view)) - inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); - } - - // For non-mobile platforms RequestSoftwareInputPanel event is not called - // because there is no SIP (Software Input Panel) triggered. In the case of a - // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked - // and the RequestSoftwareInputPanel event is called. For these two situations - // this part of the test can verified as the checks below. - if (inputPanel) - QVERIFY(testContext.isInputPanelVisible()); - else - QVERIFY(!testContext.isInputPanelVisible()); - testContext.hideInputPanel(); - - clickOnPage(page, textInputCenter); - QVERIFY(testContext.isInputPanelVisible()); - - //ImMicroFocus - QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); - - // We assigned the serif font famility to be the same as the fixef font family. - // Then test ImFont on a serif styled element, we should get our fixef font family. - variant = page->inputMethodQuery(Qt::ImFont); - QFont font = variant.value(); - QCOMPARE(page->settings()->fontFamily(QWebEngineSettings::FixedFont), font.family()); - - QList inputAttributes; - - //Insert text. - { - QInputMethodEvent eventText("QtWebEngine", inputAttributes); - QSignalSpy signalSpy(page, SIGNAL(microFocusChanged())); - page->event(&eventText); - QCOMPARE(signalSpy.count(), 0); - } - - { - QInputMethodEvent eventText("", inputAttributes); - eventText.setCommitString(QString("QtWebEngine"), 0, 0); - page->event(&eventText); - } - - //ImMaximumTextLength - variant = page->inputMethodQuery(Qt::ImMaximumTextLength); - QCOMPARE(20, variant.toInt()); - - //Set selection - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 3, 2, QVariant()); - QInputMethodEvent eventSelection("",inputAttributes); - page->event(&eventSelection); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - int anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 3); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - int cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 5); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - QString selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("eb")); - - //Set selection with negative length - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 6, -5, QVariant()); - QInputMethodEvent eventSelection3("",inputAttributes); - page->event(&eventSelection3); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 6); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("tWebK")); - - //ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - QString value = variant.value(); - QCOMPARE(value, QString("QtWebEngine")); - - { - QList attributes; - // Clear the selection, so the next test does not clear any contents. - QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); - attributes.append(newSelection); - QInputMethodEvent event("composition", attributes); - page->event(&event); - } - - // A ongoing composition should not change the surrounding text before it is committed. - variant = page->inputMethodQuery(Qt::ImSurroundingText); - value = variant.value(); - QCOMPARE(value, QString("QtWebEngine")); - - // Cancel current composition first - inputAttributes << QInputMethodEvent::Attribute(QInputMethodEvent::Selection, 0, 0, QVariant()); - QInputMethodEvent eventSelection4("", inputAttributes); - page->event(&eventSelection4); - - // START - Tests for Selection when the Editor is NOT in Composition mode - - // LEFT to RIGHT selection - // Deselect the selection by sending MouseButtonPress events - // This moves the current cursor to the end of the text - clickOnPage(page, textInputCenter); - - { - QList attributes; - QInputMethodEvent event(QString(), attributes); - event.setCommitString("XXX", 0, 0); - page->event(&event); - event.setCommitString(QString(), -2, 2); // Erase two characters. - page->event(&event); - event.setCommitString(QString(), -1, 1); // Erase one character. - page->event(&event); - variant = page->inputMethodQuery(Qt::ImSurroundingText); - value = variant.value(); - QCOMPARE(value, QString("QtWebEngine")); - } - - //Move to the start of the line - page->triggerAction(QWebEnginePage::MoveToStartOfLine); - - QKeyEvent keyRightEventPress(QEvent::KeyPress, Qt::Key_Right, Qt::NoModifier); - QKeyEvent keyRightEventRelease(QEvent::KeyRelease, Qt::Key_Right, Qt::NoModifier); - - //Move 2 characters RIGHT - for (int j = 0; j < 2; ++j) { - page->event(&keyRightEventPress); - page->event(&keyRightEventRelease); - } - - //Select to the end of the line - page->triggerAction(QWebEnginePage::SelectEndOfLine); - - //ImAnchorPosition QtWebEngine - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 2); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 8); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("WebKit")); - - //RIGHT to LEFT selection - //Deselect the selection (this moves the current cursor to the end of the text) - clickOnPage(page, textInputCenter); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 8); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 8); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - QKeyEvent keyLeftEventPress(QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); - QKeyEvent keyLeftEventRelease(QEvent::KeyRelease, Qt::Key_Left, Qt::NoModifier); - - //Move 2 characters LEFT - for (int i = 0; i < 2; ++i) { - page->event(&keyLeftEventPress); - page->event(&keyLeftEventRelease); - } - - //Select to the start of the line - page->triggerAction(QWebEnginePage::SelectStartOfLine); - - //ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 6); - - //ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - //ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("QtWebK")); - - //END - Tests for Selection when the Editor is not in Composition mode - - //ImhHiddenText - QPoint passwordInputCenter = inputs.at(1).geometry().center(); - clickOnPage(page, passwordInputCenter); - - QVERIFY(inputMethodEnabled(view)); - QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText); - - clickOnPage(page, textInputCenter); - QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText)); - - page->setHtml("

nothing to input here"); - testContext.hideInputPanel(); - - QWebEngineElement para = page->mainFrame()->findFirstElement("p"); - clickOnPage(page, para.geometry().center()); - - QVERIFY(!testContext.isInputPanelVisible()); - - //START - Test for sending empty QInputMethodEvent - page->setHtml("" \ - "" \ - ""); - page->evaluateJavaScript("var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();"); - - //Send empty QInputMethodEvent - QInputMethodEvent emptyEvent; - page->event(&emptyEvent); - - QString inputValue = page->evaluateJavaScript("document.getElementById('input3').value").toString(); - QCOMPARE(inputValue, QString("QtWebEngine2")); - //END - Test for sending empty QInputMethodEvent - - page->setHtml("" \ - "" \ - ""); - page->evaluateJavaScript("var inputEle = document.getElementById('input4'); inputEle.focus(); inputEle.select();"); - - // Clear the selection, also cancel the ongoing composition if there is one. - { - QList attributes; - QInputMethodEvent::Attribute newSelection(QInputMethodEvent::Selection, 0, 0, QVariant()); - attributes.append(newSelection); - QInputMethodEvent event("", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - variant = page->inputMethodQuery(Qt::ImSurroundingText); - QString surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // 1. Insert a character to the beginning of the line. - // Send temporary text, which makes the editor has composition 'm'. - { - QList attributes; - QInputMethodEvent event("m", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // Send temporary text, which makes the editor has composition 'n'. - { - QList attributes; - QInputMethodEvent event("n", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("QtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 0); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 0); - - // Send commit text, which makes the editor conforms composition. - { - QList attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("o"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 1); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - // 2. insert a character to the middle of the line. - // Send temporary text, which makes the editor has composition 'd'. - { - QList attributes; - QInputMethodEvent event("d", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 1); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 1); - - // Send commit text, which makes the editor conforms composition. - { - QList attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("e"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 2); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 2); - - // 3. Insert a character to the end of the line. - page->triggerAction(QWebEnginePage::MoveToEndOfLine); - - // Send temporary text, which makes the editor has composition 't'. - { - QList attributes; - QInputMethodEvent event("t", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethod")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 22); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 22); - - // Send commit text, which makes the editor conforms composition. - { - QList attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("t"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 23); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 23); - - // 4. Replace the selection. - page->triggerAction(QWebEnginePage::SelectPreviousWord); - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("inputMethodt")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine inputMethodt")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 11); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 23); - - // Send temporary text, which makes the editor has composition 'w'. - { - QList attributes; - QInputMethodEvent event("w", attributes); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine ")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 11); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 11); - - // Send commit text, which makes the editor conforms composition. - { - QList attributes; - QInputMethodEvent event("", attributes); - event.setCommitString("2"); - page->event(&event); - } - - // ImCurrentSelection - variant = page->inputMethodQuery(Qt::ImCurrentSelection); - selectionValue = variant.value(); - QCOMPARE(selectionValue, QString("")); - - // ImSurroundingText - variant = page->inputMethodQuery(Qt::ImSurroundingText); - surroundingValue = variant.value(); - QCOMPARE(surroundingValue, QString("oeQtWebEngine 2")); - - // ImCursorPosition - variant = page->inputMethodQuery(Qt::ImCursorPosition); - cursorPosition = variant.toInt(); - QCOMPARE(cursorPosition, 12); - - // ImAnchorPosition - variant = page->inputMethodQuery(Qt::ImAnchorPosition); - anchorPosition = variant.toInt(); - QCOMPARE(anchorPosition, 12); - - // Check sending RequestSoftwareInputPanel event - page->setHtml("" \ - "" \ - "

abc
"\ - ""); - QWebEngineElement inputElement = page->mainFrame()->findFirstElement("div"); - clickOnPage(page, inputElement.geometry().center()); - - QVERIFY(!testContext.isInputPanelVisible()); - - // START - Newline test for textarea - qApp->processEvents(); - page->setHtml("" \ - "
- diff --git a/tests/widgets/qwebengineview/resources/scrolltest_page.html b/tests/widgets/qwebengineview/resources/scrolltest_page.html deleted file mode 100644 index 18fcbbebe..000000000 --- a/tests/widgets/qwebengineview/resources/scrolltest_page.html +++ /dev/null @@ -1,6 +0,0 @@ - -Scrolling test - -
- - diff --git a/tests/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/widgets/qwebengineview/tst_qwebengineview.cpp deleted file mode 100644 index 352040bab..000000000 --- a/tests/widgets/qwebengineview/tst_qwebengineview.cpp +++ /dev/null @@ -1,552 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - Copyright (C) 2009 Torch Mobile Inc. - Copyright (C) 2009 Girish Ramakrishnan - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ - -#include -#include "../util.h" - -#include -#include -#include -#include -#include - -#define VERIFY_INPUTMETHOD_HINTS(actual, expect) \ - QVERIFY(actual == expect); - -class tst_QWebEngineView : public QObject -{ - Q_OBJECT - -public Q_SLOTS: - void initTestCase(); - void cleanupTestCase(); - void init(); - void cleanup(); - -private Q_SLOTS: - void renderingAfterMaxAndBack(); - void renderHints(); - void getWebKitVersion(); - - void reusePage_data(); - void reusePage(); - void microFocusCoordinates(); - void focusInputTypes(); - void horizontalScrollbarTest(); - - void crashTests(); -#if !(defined(WTF_USE_QT_MOBILE_THEME) && WTF_USE_QT_MOBILE_THEME) - void setPalette_data(); - void setPalette(); -#endif -}; - -// This will be called before the first test function is executed. -// It is only called once. -void tst_QWebEngineView::initTestCase() -{ -} - -// This will be called after the last test function is executed. -// It is only called once. -void tst_QWebEngineView::cleanupTestCase() -{ -} - -// This will be called before each test function is executed. -void tst_QWebEngineView::init() -{ -} - -// This will be called after every test function. -void tst_QWebEngineView::cleanup() -{ -} - -void tst_QWebEngineView::renderHints() -{ -#if !defined(QWEBENGINEVIEW_RENDERHINTS) - QSKIP("QWEBENGINEVIEW_RENDERHINTS"); -#else - QWebEngineView webView; - - // default is only text antialiasing + smooth pixmap transform - QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); - QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); - QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); - QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); - - webView.setRenderHint(QPainter::Antialiasing, true); - QVERIFY(webView.renderHints() & QPainter::Antialiasing); - QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); - QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); - QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); - - webView.setRenderHint(QPainter::Antialiasing, false); - QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); - QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); - QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); - QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); - - webView.setRenderHint(QPainter::SmoothPixmapTransform, true); - QVERIFY(!(webView.renderHints() & QPainter::Antialiasing)); - QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); - QVERIFY(webView.renderHints() & QPainter::SmoothPixmapTransform); - QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); - - webView.setRenderHint(QPainter::SmoothPixmapTransform, false); - QVERIFY(webView.renderHints() & QPainter::TextAntialiasing); - QVERIFY(!(webView.renderHints() & QPainter::SmoothPixmapTransform)); - QVERIFY(!(webView.renderHints() & QPainter::HighQualityAntialiasing)); -#endif -} - -void tst_QWebEngineView::getWebKitVersion() -{ -#if !defined(QWEBENGINEVERSION) - QSKIP("QWEBENGINEVERSION"); -#else - QVERIFY(qWebKitVersion().toDouble() > 0); -#endif -} - -void tst_QWebEngineView::reusePage_data() -{ - QTest::addColumn("html"); - QTest::newRow("WithoutPlugin") << "text"; - QTest::newRow("WindowedPlugin") << QString("text"); - QTest::newRow("WindowlessPlugin") << QString("text"); -} - -void tst_QWebEngineView::reusePage() -{ -#if !defined(QWEBENGINEPAGE_SETHTML) - QSKIP("QWEBENGINEPAGE_SETHTML"); -#else - if (!QDir(TESTS_SOURCE_DIR).exists()) - W_QSKIP(QString("This test requires access to resources found in '%1'").arg(TESTS_SOURCE_DIR).toLatin1().constData(), SkipAll); - - QDir::setCurrent(TESTS_SOURCE_DIR); - - QFETCH(QString, html); - QWebEngineView* view1 = new QWebEngineView; - QPointer page = new QWebEnginePage; - view1->setPage(page.data()); - page.data()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true); - page->setHtml(html, QUrl::fromLocalFile(TESTS_SOURCE_DIR)); - if (html.contains("")) { - // some reasonable time for the PluginStream to feed test.swf to flash and start painting - waitForSignal(view1, SIGNAL(loadFinished(bool)), 2000); - } - - view1->show(); - QTest::qWaitForWindowExposed(view1); - delete view1; - QVERIFY(page != 0); // deleting view must not have deleted the page, since it's not a child of view - - QWebEngineView *view2 = new QWebEngineView; - view2->setPage(page.data()); - view2->show(); // in Windowless mode, you should still be able to see the plugin here - QTest::qWaitForWindowExposed(view2); - delete view2; - - delete page.data(); // must not crash - - QDir::setCurrent(QApplication::applicationDirPath()); -#endif -} - -// Class used in crashTests -class WebViewCrashTest : public QObject { - Q_OBJECT - QWebEngineView* m_view; -public: - bool m_executed; - - - WebViewCrashTest(QWebEngineView* view) - : m_view(view) - , m_executed(false) - { - view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int))); - } - -private Q_SLOTS: - void loading(int progress) - { - if (progress >= 20 && progress < 90) { - QVERIFY(!m_executed); - m_view->stop(); - m_executed = true; - } - } -}; - - -// Should not crash. -void tst_QWebEngineView::crashTests() -{ - // Test if loading can be stopped in loadProgress handler without crash. - // Test page should have frames. - QWebEngineView view; - WebViewCrashTest tester(&view); - QUrl url("qrc:///resources/index.html"); - view.load(url); - QTRY_VERIFY(tester.m_executed); // If fail it means that the test wasn't executed. -} - -void tst_QWebEngineView::microFocusCoordinates() -{ -#if !defined(QWEBENGINEPAGE_INPUTMETHODQUERY) - QSKIP("QWEBENGINEPAGE_INPUTMETHODQUERY"); -#else - QWebEnginePage* page = new QWebEnginePage; - QWebEngineView* webView = new QWebEngineView; - webView->setPage( page ); - - page->setHtml("" \ - "
" \ - "" \ - "
" \ - "" \ - ""); - -#if defined(QWEBENGINEFRAME) - page->mainFrame()->setFocus(); -#endif - - QVariant initialMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(initialMicroFocus.isValid()); - - page->scroll(0,50); - - QVariant currentMicroFocus = page->inputMethodQuery(Qt::ImMicroFocus); - QVERIFY(currentMicroFocus.isValid()); - - QCOMPARE(initialMicroFocus.toRect().translated(QPoint(0,-50)), currentMicroFocus.toRect()); -#endif -} - -void tst_QWebEngineView::focusInputTypes() -{ -#if !defined(QWEBENGINEELEMENT) - QSKIP("QWEBENGINEELEMENT"); -#else - QWebEngineView webView; - webView.show(); - QTest::qWaitForWindowExposed(&webView); - - QUrl url("qrc:///resources/input_types.html"); - QWebEngineFrame* const mainFrame = webView.page()->mainFrame(); - webView.load(url); - mainFrame->setFocus(); - - QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); - - // 'text' type - QWebEngineElement inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'tel' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=tel]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDialableCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'number' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=number]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhDigitsOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'email' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=email]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhEmailCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'url' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=url]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhUrlCharactersOnly); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'text' type - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=text]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'password' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("input[type=password]")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - VERIFY_INPUTMETHOD_HINTS(webView.inputMethodHints(), Qt::ImhHiddenText); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); - - // 'text area' field - inputElement = mainFrame->documentElement().findFirst(QLatin1String("textarea")); - QTest::mouseClick(&webView, Qt::LeftButton, 0, inputElement.geometry().center()); - QVERIFY(webView.inputMethodHints() == Qt::ImhNone); - QVERIFY(webView.testAttribute(Qt::WA_InputMethodEnabled)); -#endif -} - -void tst_QWebEngineView::horizontalScrollbarTest() -{ -#if !defined(QWEBENGINEPAGE_SCROLL) - QSKIP("QWEBENGINEPAGE_SCROLL"); -#else - QWebEngineView webView; - webView.resize(600, 600); - webView.show(); - QTest::qWaitForWindowExposed(&webView); - - QUrl url("qrc:///resources/scrolltest_page.html"); - webView.page()->load(url); - webView.page()->setFocus(); - - QVERIFY(waitForSignal(&webView, SIGNAL(loadFinished(bool)))); - - QVERIFY(webView.page()->scrollPosition() == QPoint(0, 0)); - - // Note: The test below assumes that the layout direction is Qt::LeftToRight. - QTest::mouseClick(&webView, Qt::LeftButton, 0, QPoint(550, 595)); - QVERIFY(webView.page()->scrollPosition().x() > 0); - - // Note: The test below assumes that the layout direction is Qt::LeftToRight. - QTest::mouseClick(&webView, Qt::LeftButton, 0, QPoint(20, 595)); - QVERIFY(webView.page()->scrollPosition() == QPoint(0, 0)); -#endif -} - - -#if !(defined(WTF_USE_QT_MOBILE_THEME) && WTF_USE_QT_MOBILE_THEME) -void tst_QWebEngineView::setPalette_data() -{ - QTest::addColumn("active"); - QTest::addColumn("background"); - QTest::newRow("activeBG") << true << true; - QTest::newRow("activeFG") << true << false; - QTest::newRow("inactiveBG") << false << true; - QTest::newRow("inactiveFG") << false << false; -} - -// Render a QWebEngineView to a QImage twice, each time with a different palette set, -// verify that images rendered are not the same, confirming WebCore usage of -// custom palette on selections. -void tst_QWebEngineView::setPalette() -{ -#if !defined(QWEBCONTENTVIEW_SETPALETTE) - QSKIP("QWEBCONTENTVIEW_SETPALETTE"); -#else - QString html = "" - "" - "Some text here" - "" - ""; - - QFETCH(bool, active); - QFETCH(bool, background); - - QWidget* activeView = 0; - - // Use controlView to manage active/inactive state of test views by raising - // or lowering their position in the window stack. - QWebEngineView controlView; - controlView.setHtml(html); - - QWebEngineView view1; - - QPalette palette1; - QBrush brush1(Qt::red); - brush1.setStyle(Qt::SolidPattern); - if (active && background) { - // Rendered image must have red background on an active QWebEngineView. - palette1.setBrush(QPalette::Active, QPalette::Highlight, brush1); - } else if (active && !background) { - // Rendered image must have red foreground on an active QWebEngineView. - palette1.setBrush(QPalette::Active, QPalette::HighlightedText, brush1); - } else if (!active && background) { - // Rendered image must have red background on an inactive QWebEngineView. - palette1.setBrush(QPalette::Inactive, QPalette::Highlight, brush1); - } else if (!active && !background) { - // Rendered image must have red foreground on an inactive QWebEngineView. - palette1.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush1); - } - - view1.setPalette(palette1); - view1.setHtml(html); - view1.page()->setViewportSize(view1.page()->contentsSize()); - view1.show(); - - QTest::qWaitForWindowExposed(&view1); - - if (!active) { - controlView.show(); - QTest::qWaitForWindowExposed(&controlView); - activeView = &controlView; - controlView.activateWindow(); - } else { - view1.activateWindow(); - activeView = &view1; - } - - QTRY_COMPARE(QApplication::activeWindow(), activeView); - - view1.page()->triggerAction(QWebEnginePage::SelectAll); - - QImage img1(view1.page()->viewportSize(), QImage::Format_ARGB32); - QPainter painter1(&img1); - view1.page()->render(&painter1); - painter1.end(); - view1.close(); - controlView.close(); - - QWebEngineView view2; - - QPalette palette2; - QBrush brush2(Qt::blue); - brush2.setStyle(Qt::SolidPattern); - if (active && background) { - // Rendered image must have blue background on an active QWebEngineView. - palette2.setBrush(QPalette::Active, QPalette::Highlight, brush2); - } else if (active && !background) { - // Rendered image must have blue foreground on an active QWebEngineView. - palette2.setBrush(QPalette::Active, QPalette::HighlightedText, brush2); - } else if (!active && background) { - // Rendered image must have blue background on an inactive QWebEngineView. - palette2.setBrush(QPalette::Inactive, QPalette::Highlight, brush2); - } else if (!active && !background) { - // Rendered image must have blue foreground on an inactive QWebEngineView. - palette2.setBrush(QPalette::Inactive, QPalette::HighlightedText, brush2); - } - - view2.setPalette(palette2); - view2.setHtml(html); - view2.page()->setViewportSize(view2.page()->contentsSize()); - view2.show(); - - QTest::qWaitForWindowExposed(&view2); - - if (!active) { - controlView.show(); - QTest::qWaitForWindowExposed(&controlView); - activeView = &controlView; - controlView.activateWindow(); - } else { - view2.activateWindow(); - activeView = &view2; - } - - QTRY_COMPARE(QApplication::activeWindow(), activeView); - - view2.page()->triggerAction(QWebEnginePage::SelectAll); - - QImage img2(view2.page()->viewportSize(), QImage::Format_ARGB32); - QPainter painter2(&img2); - view2.page()->render(&painter2); - painter2.end(); - - view2.close(); - controlView.close(); - - QVERIFY(img1 != img2); -#endif -} -#endif - -void tst_QWebEngineView::renderingAfterMaxAndBack() -{ -#if !defined(QWEBENGINEPAGE_RENDER) - QSKIP("QWEBENGINEPAGE_RENDER"); -#else - QUrl url = QUrl("data:text/html," - "" - "" - ""); - - QWebEngineView view; - view.page()->load(url); - QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); - view.show(); - - view.page()->settings()->setMaximumPagesInCache(3); - - QTest::qWaitForWindowExposed(&view); - - QPixmap reference(view.page()->viewportSize()); - reference.fill(Qt::red); - - QPixmap image(view.page()->viewportSize()); - QPainter painter(&image); - view.page()->render(&painter); - - QCOMPARE(image, reference); - - QUrl url2 = QUrl("data:text/html," - "" - "" - ""); - view.page()->load(url2); - - QVERIFY(waitForSignal(&view, SIGNAL(loadFinished(bool)))); - - view.showMaximized(); - - QTest::qWaitForWindowExposed(&view); - - QPixmap reference2(view.page()->viewportSize()); - reference2.fill(Qt::blue); - - QPixmap image2(view.page()->viewportSize()); - QPainter painter2(&image2); - view.page()->render(&painter2); - - QCOMPARE(image2, reference2); - - view.back(); - - QPixmap reference3(view.page()->viewportSize()); - reference3.fill(Qt::red); - QPixmap image3(view.page()->viewportSize()); - QPainter painter3(&image3); - view.page()->render(&painter3); - - QCOMPARE(image3, reference3); -#endif -} - -QTEST_MAIN(tst_QWebEngineView) -#include "tst_qwebengineview.moc" diff --git a/tests/widgets/qwebengineview/tst_qwebengineview.qrc b/tests/widgets/qwebengineview/tst_qwebengineview.qrc deleted file mode 100644 index 6685a8086..000000000 --- a/tests/widgets/qwebengineview/tst_qwebengineview.qrc +++ /dev/null @@ -1,8 +0,0 @@ - - - resources/index.html - resources/frame_a.html - resources/input_types.html - resources/scrolltest_page.html - - diff --git a/tests/widgets/resources/image2.png b/tests/widgets/resources/image2.png deleted file mode 100644 index 8d703640c..000000000 Binary files a/tests/widgets/resources/image2.png and /dev/null differ diff --git a/tests/widgets/resources/test.swf b/tests/widgets/resources/test.swf deleted file mode 100644 index 895298271..000000000 Binary files a/tests/widgets/resources/test.swf and /dev/null differ diff --git a/tests/widgets/tests.pri b/tests/widgets/tests.pri deleted file mode 100644 index 0d0364c8d..000000000 --- a/tests/widgets/tests.pri +++ /dev/null @@ -1,23 +0,0 @@ -TEMPLATE = app - -VPATH += $$_PRO_FILE_PWD_ -TARGET = tst_$$TARGET - -# Load mobilityconfig if Qt Mobility is available -load(mobilityconfig, true) -contains(MOBILITY_CONFIG, multimedia) { - # This define is used by tests depending on Qt Multimedia - DEFINES -= WTF_USE_QT_MULTIMEDIA=0 - DEFINES += WTF_USE_QT_MULTIMEDIA=1 -} - -SOURCES += $${TARGET}.cpp -INCLUDEPATH += \ - $$PWD \ - $$PWD/../Api - -QT += testlib network webenginewidgets widgets -include($$QTWEBENGINE_ROOT/common.pri) - -# This define is used by some tests to look up resources in the source tree -DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" diff --git a/tests/widgets/util.h b/tests/widgets/util.h deleted file mode 100644 index 4925aa4c7..000000000 --- a/tests/widgets/util.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Library General Public License - along with this library; see the file COPYING.LIB. If not, write to - the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02110-1301, USA. -*/ -// Functions and macros that really need to be in QTestLib - -#if 0 -#pragma qt_no_master_include -#endif - -#include -#include -#include - -#if !defined(TESTS_SOURCE_DIR) -#define TESTS_SOURCE_DIR "" -#endif - -/** - * Starts an event loop that runs until the given signal is received. - * Optionally the event loop - * can return earlier on a timeout. - * - * \return \p true if the requested signal was received - * \p false on timeout - */ -static inline bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) -{ - QEventLoop loop; - QObject::connect(obj, signal, &loop, SLOT(quit())); - QTimer timer; - QSignalSpy timeoutSpy(&timer, SIGNAL(timeout())); - if (timeout > 0) { - QObject::connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); - timer.setSingleShot(true); - timer.start(timeout); - } - loop.exec(); - return timeoutSpy.isEmpty(); -} - -/** - * Just like QSignalSpy but facilitates sync and async - * signal emission. For example if you want to verify that - * page->foo() emitted a signal, it could be that the - * implementation decides to emit the signal asynchronously - * - in which case we want to spin a local event loop until - * emission - or that the call to foo() emits it right away. - */ -class SignalBarrier : private QSignalSpy -{ -public: - SignalBarrier(const QObject* obj, const char* aSignal) - : QSignalSpy(obj, aSignal) - { } - - bool ensureSignalEmitted() - { - bool result = count() > 0; - if (!result) - result = wait(); - clear(); - return result; - } -}; - -#define W_QSKIP(a, b) QSKIP(a) diff --git a/tests/widgets/widgets.pro b/tests/widgets/widgets.pro deleted file mode 100644 index 1dd9a01a9..000000000 --- a/tests/widgets/widgets.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = subdirs - -CONFIG += ordered - -SUBDIRS += \ - # FIXME: Move useful qwebengineframe tests to qwebenginepage - # qwebengineframe \ - qwebenginepage \ - qwebenginehistoryinterface \ - qwebengineview \ - qwebenginehistory \ - qwebengineinspector \ -- cgit v1.2.3