diff options
Diffstat (limited to 'tests')
18 files changed, 841 insertions, 37 deletions
diff --git a/tests/auto/quick/html/basic_page.html b/tests/auto/quick/html/basic_page.html new file mode 100644 index 000000000..53726e4a6 --- /dev/null +++ b/tests/auto/quick/html/basic_page.html @@ -0,0 +1,6 @@ +<html> +<head> +<title> Basic Page </title> +</head> +<h1>Basic page</h1> +</html> diff --git a/tests/auto/quick/html/basic_page2.html b/tests/auto/quick/html/basic_page2.html new file mode 100644 index 000000000..f8cff2969 --- /dev/null +++ b/tests/auto/quick/html/basic_page2.html @@ -0,0 +1 @@ +<h1>Basic page 2</h1> diff --git a/tests/auto/quick/html/direct-image-compositing.html b/tests/auto/quick/html/direct-image-compositing.html new file mode 100644 index 000000000..53a4ca137 --- /dev/null +++ b/tests/auto/quick/html/direct-image-compositing.html @@ -0,0 +1,66 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> + +<html lang="en"> +<head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>Testing direct image layer optimization</title> + <style type="text/css" media="screen"> + img { + float: left; + width: 150px; + height: 150px; + } + img { + -webkit-transform: rotate3d(0, 0, 1, 0); + } + .test { + float: left; + height: 200px; + width: 260px; + } + </style> +</head> +<body> + + <h1>Image optimization in layers</h1> + + <p> + This test exercises direct compositing of images with hardware acceleration. The visual results + using ACCELERATED_COMPOSITING and regular TOT should be identical. Running this test manually with + the correct debug options will show which elements are directly composited. See + <a href="https://bugs.webkit.org/show_bug.cgi?id=23361">https://bugs.webkit.org/show_bug.cgi?id=23361</a> + </p> + + <div class="test"> + <img src="resources/simple_image.png"> + Basic image - no style - can be directly composited + </div> + + <div class="test"> + <img src="resources/simple_image.png" style="border: 5px solid blue;"> + 5px blue border - can NOT be directly composited + </div> + + <div class="test"> + <img src="resources/simple_image.png" style="margin: 5px 5px;"> + margin - can NOT be directly composited + </div> + + <div class="test"> + <img src="resources/simple_image.png" style="background-color: grey;"> + solid background - can be directly composited + </div> + + <div class="test"> + <img src="resources/simple_image.png" style="background: orange url(resources/simple_image.png) -50px -50px;"> + background image - can NOT be directly composited + </div> + + <div class="test"> + <img src="resources/simple_image.png" style="-webkit-transform: rotate3d(0, 0, 1, 10deg);"> + rotated but otherwise no style - can be directly composited + </div> + +</body> +</html> diff --git a/tests/auto/quick/html/inputmethod.html b/tests/auto/quick/html/inputmethod.html new file mode 100644 index 000000000..dc9140f9d --- /dev/null +++ b/tests/auto/quick/html/inputmethod.html @@ -0,0 +1,11 @@ +<html> +<head> +<title>Basic Page For Input Method Testing</title> +</head> +<body> +<h1>Basic page</h1> +<input id="inputField" /> +<input id="emailInputField" type="email" /> +<div id="editableDiv" contenteditable></div> +</body> +</html> diff --git a/tests/auto/quick/html/resources/simple_image.png b/tests/auto/quick/html/resources/simple_image.png Binary files differnew file mode 100644 index 000000000..4685399ca --- /dev/null +++ b/tests/auto/quick/html/resources/simple_image.png diff --git a/tests/auto/quick/html/scroll.html b/tests/auto/quick/html/scroll.html new file mode 100644 index 000000000..ce2193b6c --- /dev/null +++ b/tests/auto/quick/html/scroll.html @@ -0,0 +1,29 @@ +<!DOCTYPE html> +<html> +<meta name="viewport" content="width=200, height=500, user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1"/> +<script type="text/javascript"> +function pageScroll() { + window.scrollBy(0,50); // horizontal and vertical scroll increments +} +</script> +<style> + body { + background-color: blue; + margin: 50 50 50 50; + } + div { + font-color: white; + background-color: green; + width: 300px; + height: 1000px; + } +</style> + +<head> +<title>Scroll test </title> +</head> +<body onload="pageScroll()"> +<div> +</div> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/tst_loadUrl.qml b/tests/auto/quick/qmltests/data/tst_loadUrl.qml index 41faa6bc3..5f51e9036 100644 --- a/tests/auto/quick/qmltests/data/tst_loadUrl.qml +++ b/tests/auto/quick/qmltests/data/tst_loadUrl.qml @@ -125,7 +125,9 @@ TestWebEngineView { var handleLoadFailed = function(loadRequest) { if (loadRequest.status == WebEngineView.LoadFailedStatus) { webEngineView.loadHtml("load failed", bogusSite) - compare(webEngineView.url, bogusSite) + // Since the load did not succeed the active url is the + // url of the previous successful load. + compare(webEngineView.url, "about:blank") compare(loadRequest.url, bogusSite) } } diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index b25878dc9..b40ef3b8c 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -4,8 +4,6 @@ QT += qmltest IMPORTPATH += $$PWD/data -INCLUDEPATH += $$PWD/../shared - OTHER_FILES += \ $$PWD/data/TestWebEngineView.qml \ $$PWD/data/favicon.html \ diff --git a/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro b/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro new file mode 100644 index 000000000..826b47de7 --- /dev/null +++ b/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro @@ -0,0 +1,6 @@ +include(../tests.pri) + +exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc +QT_PRIVATE += webengine-private + +HEADERS += ../shared/util.h diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp new file mode 100644 index 000000000..228a3e034 --- /dev/null +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -0,0 +1,422 @@ +/* + Copyright (C) 2011 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 "testwindow.h" +#include "util.h" + +#include <QScopedPointer> +#include <QtQml/QQmlEngine> +#include <QtTest/QtTest> +#include <private/qquickwebengineview_p.h> + +class tst_QQuickWebEngineView : public QObject { + Q_OBJECT +public: + tst_QQuickWebEngineView(); + +private Q_SLOTS: + void init(); + void cleanup(); + + void navigationStatusAtStartup(); + void stopEnabledAfterLoadStarted(); + void baseUrl(); + void loadEmptyUrl(); + void loadEmptyPageViewVisible(); + void loadEmptyPageViewHidden(); + void loadNonexistentFileUrl(); + void backAndForward(); + void reload(); + void stop(); + void loadProgress(); + + void show(); + void showWebEngineView(); + void removeFromCanvas(); + void multipleWebEngineViewWindows(); + void multipleWebEngineViews(); + void titleUpdate(); + void transparentWebEngineViews(); + + void inputMethod(); + void inputMethodHints(); + void basicRenderingSanity(); + +private: + inline QQuickWebEngineView *newWebEngineView(); + inline QQuickWebEngineView *webEngineView() const; + void runJavaScript(const QString &script); + QScopedPointer<TestWindow> m_window; + QScopedPointer<QQmlComponent> m_component; +}; + +tst_QQuickWebEngineView::tst_QQuickWebEngineView() +{ + QtWebEngine::initialize(); + + static QQmlEngine *engine = new QQmlEngine(this); + m_component.reset(new QQmlComponent(engine, this)); + m_component->setData(QByteArrayLiteral("import QtQuick 2.0\n" + "import QtWebEngine 1.0\n" + "WebEngineView {}") + , QUrl()); +} + +QQuickWebEngineView *tst_QQuickWebEngineView::newWebEngineView() +{ + QObject *viewInstance = m_component->create(); + QQuickWebEngineView *webEngineView = qobject_cast<QQuickWebEngineView*>(viewInstance); + return webEngineView; +} + +void tst_QQuickWebEngineView::init() +{ + m_window.reset(new TestWindow(newWebEngineView())); +} + +void tst_QQuickWebEngineView::cleanup() +{ + m_window.reset(); +} + +inline QQuickWebEngineView *tst_QQuickWebEngineView::webEngineView() const +{ + return static_cast<QQuickWebEngineView*>(m_window->webEngineView.data()); +} + +void tst_QQuickWebEngineView::runJavaScript(const QString &script) +{ + webEngineView()->runJavaScript(script); +} + +void tst_QQuickWebEngineView::navigationStatusAtStartup() +{ + QCOMPARE(webEngineView()->canGoBack(), false); + + QCOMPARE(webEngineView()->canGoForward(), false); + + QCOMPARE(webEngineView()->isLoading(), false); +} + +void tst_QQuickWebEngineView::stopEnabledAfterLoadStarted() +{ + QCOMPARE(webEngineView()->isLoading(), false); + + LoadStartedCatcher catcher(webEngineView()); + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "/html/basic_page.html"))); + waitForSignal(&catcher, SIGNAL(finished())); + + QCOMPARE(webEngineView()->isLoading(), true); + + QVERIFY(waitForLoadSucceeded(webEngineView())); +} + +void tst_QQuickWebEngineView::baseUrl() +{ + // Test the url is in a well defined state when instanciating the view, but before loading anything. + QVERIFY(webEngineView()->url().isEmpty()); +} + +void tst_QQuickWebEngineView::loadEmptyUrl() +{ + webEngineView()->setUrl(QUrl()); + webEngineView()->setUrl(QUrl(QLatin1String(""))); +} + +void tst_QQuickWebEngineView::loadEmptyPageViewVisible() +{ + m_window->show(); + loadEmptyPageViewHidden(); +} + +void tst_QQuickWebEngineView::loadEmptyPageViewHidden() +{ + QSignalSpy loadSpy(webEngineView(), SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*))); + + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(loadSpy.size(), 2); +} + +void tst_QQuickWebEngineView::loadNonexistentFileUrl() +{ + QSignalSpy loadSpy(webEngineView(), SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*))); + + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/file_that_does_not_exist.html"))); + QVERIFY(waitForLoadFailed(webEngineView())); + + QCOMPARE(loadSpy.size(), 2); +} + +void tst_QQuickWebEngineView::backAndForward() +{ + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html")); + + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page2.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page2.html")); + + webEngineView()->goBack(); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html")); + + webEngineView()->goForward(); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page2.html")); +} + +void tst_QQuickWebEngineView::reload() +{ + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html")); + + webEngineView()->reload(); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html")); +} + +void tst_QQuickWebEngineView::stop() +{ + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QCOMPARE(webEngineView()->url().path(), QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html")); + + webEngineView()->stop(); +} + +void tst_QQuickWebEngineView::loadProgress() +{ + QCOMPARE(webEngineView()->loadProgress(), 0); + + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QSignalSpy loadProgressChangedSpy(webEngineView(), SIGNAL(loadProgressChanged())); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + QVERIFY(loadProgressChangedSpy.count() >= 1); + + QCOMPARE(webEngineView()->loadProgress(), 100); +} + +void tst_QQuickWebEngineView::show() +{ + // This should not crash. + m_window->show(); + QTest::qWait(200); + m_window->hide(); +} + +void tst_QQuickWebEngineView::showWebEngineView() +{ + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/direct-image-compositing.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + m_window->show(); + // This should not crash. + webEngineView()->setVisible(true); + QTest::qWait(200); + webEngineView()->setVisible(false); + QTest::qWait(200); +} + +void tst_QQuickWebEngineView::removeFromCanvas() +{ + showWebEngineView(); + + // This should not crash. + QQuickItem *parent = webEngineView()->parentItem(); + QQuickItem noCanvasItem; + webEngineView()->setParentItem(&noCanvasItem); + QTest::qWait(200); + webEngineView()->setParentItem(parent); + webEngineView()->setVisible(true); + QTest::qWait(200); +} + +void tst_QQuickWebEngineView::multipleWebEngineViewWindows() +{ + showWebEngineView(); + + // This should not crash. + QQuickWebEngineView *webEngineView1 = newWebEngineView(); + QScopedPointer<TestWindow> window1(new TestWindow(webEngineView1)); + QQuickWebEngineView *webEngineView2 = newWebEngineView(); + QScopedPointer<TestWindow> window2(new TestWindow(webEngineView2)); + + webEngineView1->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/scroll.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView1)); + window1->show(); + webEngineView1->setVisible(true); + + webEngineView2->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView2)); + window2->show(); + webEngineView2->setVisible(true); + QTest::qWait(200); +} + +void tst_QQuickWebEngineView::multipleWebEngineViews() +{ + showWebEngineView(); + + // This should not crash. + QScopedPointer<QQuickWebEngineView> webEngineView1(newWebEngineView()); + webEngineView1->setParentItem(m_window->contentItem()); + QScopedPointer<QQuickWebEngineView> webEngineView2(newWebEngineView()); + webEngineView2->setParentItem(m_window->contentItem()); + + webEngineView1->setSize(QSizeF(300, 400)); + webEngineView1->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/scroll.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView1.data())); + webEngineView1->setVisible(true); + + webEngineView2->setSize(QSizeF(300, 400)); + webEngineView2->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView2.data())); + webEngineView2->setVisible(true); + QTest::qWait(200); +} + +void tst_QQuickWebEngineView::basicRenderingSanity() +{ + showWebEngineView(); + + webEngineView()->setUrl(QUrl(QString::fromUtf8("data:text/html,<html><body bgcolor=\"#00ff00\"></body></html>"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + + // This should not crash. + webEngineView()->setVisible(true); + QTest::qWait(200); + QImage grabbedWindow = m_window->grabWindow(); + QRgb testColor = qRgba(0, 0xff, 0, 0xff); + QVERIFY(grabbedWindow.pixel(10, 10) == testColor); + QVERIFY(grabbedWindow.pixel(100, 10) == testColor); + QVERIFY(grabbedWindow.pixel(10, 100) == testColor); + QVERIFY(grabbedWindow.pixel(100, 100) == testColor); +} + +void tst_QQuickWebEngineView::titleUpdate() +{ + QSignalSpy titleSpy(webEngineView(), SIGNAL(titleChanged())); + + // Load page with no title + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/basic_page2.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView())); + QCOMPARE(titleSpy.size(), 1); + + titleSpy.clear(); + + // No titleChanged signal for failed load + webEngineView()->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/file_that_does_not_exist.html"))); + QVERIFY(waitForLoadFailed(webEngineView())); + QCOMPARE(titleSpy.size(), 0); + +} + +void tst_QQuickWebEngineView::transparentWebEngineViews() +{ + + showWebEngineView(); + + // This should not crash. + QScopedPointer<QQuickWebEngineView> webEngineView1(newWebEngineView()); + webEngineView1->setParentItem(m_window->contentItem()); + QScopedPointer<QQuickWebEngineView> webEngineView2(newWebEngineView()); + webEngineView2->setParentItem(m_window->contentItem()); +#if !defined(QQUICKWEBENGINEVIEW_EXPERIMENTAL_TRANSPARENTBACKGROUND) + QWARN("QQUICKWEBENGINEVIEW_EXPERIMENTAL_TRANSPARENTBACKGROUND"); +#else + QVERIFY(!webEngineView1->experimental()->transparentBackground()); + webEngineView2->experimental()->setTransparentBackground(true); + QVERIFY(webEngineView2->experimental()->transparentBackground()); +#endif + + webEngineView1->setSize(QSizeF(300, 400)); + webEngineView1->loadHtml("<html><body bgcolor=\"red\"></body></html>"); + QVERIFY(waitForLoadSucceeded(webEngineView1.data())); + webEngineView1->setVisible(true); + + webEngineView2->setSize(QSizeF(300, 400)); + webEngineView2->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "/html/basic_page.html"))); + QVERIFY(waitForLoadSucceeded(webEngineView2.data())); + webEngineView2->setVisible(true); + + QTest::qWait(200); + // FIXME: test actual rendering results; https://bugs.webkit.org/show_bug.cgi?id=80609. +} + +void tst_QQuickWebEngineView::inputMethod() +{ +#if !defined(QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD) + QSKIP("QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD"); +#else + QQuickWebEngineView *view = webEngineView(); + view->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/inputmethod.html"))); + QVERIFY(waitForLoadSucceeded(view)); + + QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + runJavaScript("document.getElementById('inputField').focus();"); + QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + runJavaScript("document.getElementById('inputField').blur();"); + QVERIFY(!view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); +#endif +} + +void tst_QQuickWebEngineView::inputMethodHints() +{ +#if !defined(QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD) + QSKIP("QQUICKWEBENGINEVIEW_ITEMACCEPTSINPUTMETHOD"); +#else + QQuickWebEngineView *view = webEngineView(); + + view->setUrl(QUrl::fromLocalFile(QLatin1String(TESTS_SOURCE_DIR "html/inputmethod.html"))); + QVERIFY(waitForLoadSucceeded(view)); + + // Setting focus on an input element results in an element in its shadow tree becoming the focus node. + // Input hints should not be set from this shadow tree node but from the input element itself. + runJavaScript("document.getElementById('emailInputField').focus();"); + QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + QInputMethodQueryEvent query(Qt::ImHints); + QGuiApplication::sendEvent(view, &query); + Qt::InputMethodHints hints(query.value(Qt::ImHints).toUInt() & Qt::ImhExclusiveInputMask); + QCOMPARE(hints, Qt::ImhEmailCharactersOnly); + + // The focus of an editable DIV is given directly to it, so no shadow root element + // is necessary. This tests the WebPage::editorState() method ability to get the + // right element without breaking. + runJavaScript("document.getElementById('editableDiv').focus();"); + QVERIFY(view->flags().testFlag(QQuickItem::ItemAcceptsInputMethod)); + query = QInputMethodQueryEvent(Qt::ImHints); + QGuiApplication::sendEvent(view, &query); + hints = Qt::InputMethodHints(query.value(Qt::ImHints).toUInt()); + QCOMPARE(hints, Qt::ImhNone); +#endif +} + +QTEST_MAIN(tst_QQuickWebEngineView) +#include "tst_qquickwebengineview.moc" diff --git a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp index af57df7e0..b69cdd151 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp +++ b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp @@ -39,6 +39,8 @@ ** ****************************************************************************/ +#include "util.h" + #include <QtTest/QtTest> #include <QQmlContext> #include <QQuickView> @@ -99,21 +101,6 @@ static QImage get150x150GreenReferenceImage() return reference; } -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(); -} - tst_QQuickWebEngineViewGraphics::tst_QQuickWebEngineViewGraphics() { } diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index e9f83181e..5c9bb72b5 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -3,4 +3,5 @@ TEMPLATE = subdirs SUBDIRS += \ publicapi \ qmltests \ + qquickwebengineview \ qquickwebengineviewgraphics diff --git a/tests/auto/quick/shared/testwindow.h b/tests/auto/quick/shared/testwindow.h new file mode 100644 index 000000000..f5181ee97 --- /dev/null +++ b/tests/auto/quick/shared/testwindow.h @@ -0,0 +1,59 @@ +/* + Copyright (C) 2011 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. +*/ + +#ifndef TESTWINDOW_H +#define TESTWINDOW_H + +#if 0 +#pragma qt_no_master_include +#endif + +#include <QResizeEvent> +#include <QScopedPointer> +#include <QtQuick/qquickitem.h> +#include <QtQuick/qquickview.h> + +// TestWindow: Utility class to ignore QQuickView details. +class TestWindow : public QQuickView { +public: + inline TestWindow(QQuickItem *webEngineView); + QScopedPointer<QQuickItem> webEngineView; + +protected: + inline void resizeEvent(QResizeEvent*); +}; + +inline TestWindow::TestWindow(QQuickItem *webEngineView) + : webEngineView(webEngineView) +{ + Q_ASSERT(webEngineView); + webEngineView->setParentItem(contentItem()); + resize(300, 400); +} + +inline void TestWindow::resizeEvent(QResizeEvent *event) +{ + QQuickView::resizeEvent(event); + webEngineView->setX(0); + webEngineView->setY(0); + webEngineView->setWidth(event->size().width()); + webEngineView->setHeight(event->size().height()); +} + +#endif /* TESTWINDOW_H */ diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h new file mode 100644 index 000000000..8f7a85f68 --- /dev/null +++ b/tests/auto/quick/shared/util.h @@ -0,0 +1,125 @@ +/* + Copyright (C) 2011 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. +*/ + +#ifndef UTIL_H +#define UTIL_H + +#include <QEventLoop> +#include <QSignalSpy> +#include <QTimer> +#include <QtTest/QtTest> +#include <private/qquickwebengineview_p.h> +#include <private/qquickwebengineloadrequest_p.h> + +#if !defined(TESTS_SOURCE_DIR) +#define TESTS_SOURCE_DIR "" +#endif + +class LoadSpy : public QEventLoop { + Q_OBJECT + +public: + LoadSpy(QQuickWebEngineView *webEngineView) + { + connect(webEngineView, SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*)), SLOT(onLoadingChanged(QQuickWebEngineLoadRequest*))); + } + + ~LoadSpy() { } + +Q_SIGNALS: + void loadSucceeded(); + void loadFailed(); + +private Q_SLOTS: + void onLoadingChanged(QQuickWebEngineLoadRequest *loadRequest) + { + if (loadRequest->status() == QQuickWebEngineView::LoadSucceededStatus) + emit loadSucceeded(); + else if (loadRequest->status() == QQuickWebEngineView::LoadFailedStatus) + emit loadFailed(); + } +}; + +class LoadStartedCatcher : public QObject { + Q_OBJECT + +public: + LoadStartedCatcher(QQuickWebEngineView *webEngineView) + : m_webEngineView(webEngineView) + { + connect(m_webEngineView, SIGNAL(loadingChanged(QQuickWebEngineLoadRequest*)), this, SLOT(onLoadingChanged(QQuickWebEngineLoadRequest*))); + } + + virtual ~LoadStartedCatcher() { } + +public Q_SLOTS: + void onLoadingChanged(QQuickWebEngineLoadRequest *loadRequest) + { + if (loadRequest->status() == QQuickWebEngineView::LoadStartedStatus) + QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection); + } + +Q_SIGNALS: + void finished(); + +private: + QQuickWebEngineView *m_webEngineView; +}; + +/** + * 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 + */ +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(); +} + +inline bool waitForLoadSucceeded(QQuickWebEngineView *webEngineView, int timeout = 10000) +{ + LoadSpy loadSpy(webEngineView); + return waitForSignal(&loadSpy, SIGNAL(loadSucceeded()), timeout); +} + +inline bool waitForLoadFailed(QQuickWebEngineView *webEngineView, int timeout = 10000) +{ + LoadSpy loadSpy(webEngineView); + return waitForSignal(&loadSpy, SIGNAL(loadFailed()), timeout); +} + +inline bool waitForViewportReady(QQuickWebEngineView *webEngineView, int timeout = 10000) +{ + return waitForSignal(reinterpret_cast<QObject *>(webEngineView->experimental()), SIGNAL(loadVisuallyCommitted()), timeout); +} + +#endif /* UTIL_H */ diff --git a/tests/auto/quick/tests.pri b/tests/auto/quick/tests.pri index 932407e66..b637c29c1 100644 --- a/tests/auto/quick/tests.pri +++ b/tests/auto/quick/tests.pri @@ -7,7 +7,9 @@ VPATH += $$_PRO_FILE_PWD_ TARGET = tst_$$TARGET SOURCES += $${TARGET}.cpp -INCLUDEPATH += $$PWD +INCLUDEPATH += \ + $$PWD \ + ../shared QT += testlib network quick webengine diff --git a/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp b/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp index 4b18f8e7a..9901bcd76 100644 --- a/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp +++ b/tests/auto/widgets/qwebengineframe/tst_qwebengineframe.cpp @@ -32,6 +32,7 @@ #include <QNetworkRequest> #include <QNetworkReply> #include <QTextCodec> +#include <QWebEngineSettings> #ifndef QT_NO_OPENSSL #include <qsslerror.h> #endif @@ -124,6 +125,7 @@ void tst_QWebEngineFrame::init() { m_view = new QWebEngineView(); m_page = m_view->page(); + m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); } void tst_QWebEngineFrame::cleanup() @@ -347,7 +349,7 @@ void tst_QWebEngineFrame::requestedUrl() void tst_QWebEngineFrame::requestedUrlAfterSetAndLoadFailures() { QWebEnginePage page; - + page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); const QUrl first("http://abcdef.abcdef/"); @@ -365,7 +367,6 @@ void tst_QWebEngineFrame::requestedUrlAfterSetAndLoadFailures() ::waitForSignal(&page, SIGNAL(loadFinished(bool))); QCOMPARE(spy.count(), 2); QCOMPARE(page.url(), first); - QEXPECT_FAIL("", "Slight change: The requestedUrl() function catches the error page's entry here thus it results the error page's requested url.", Continue); QCOMPARE(page.requestedUrl(), second); QVERIFY(!spy.at(1).first().toBool()); } @@ -1369,15 +1370,19 @@ void tst_QWebEngineFrame::setUrlHistory() QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), aboutBlank); QCOMPARE(m_page->requestedUrl(), QUrl()); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList()); + // Chromium stores navigation entry for every successful loads. The load of the empty page is committed and stored as about:blank. + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << aboutBlank.toString()); url = QUrl("http://non.existent/"); m_page->setUrl(url); expectedLoadFinishedCount++; QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); - QCOMPARE(m_page->url(), url); - QCOMPARE(m_page->requestedUrl(), url); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList()); + // When error page is disabled in case of LoadFail the entry of the unavailable page is not stored. + // We expect the url of the previously loaded page here. + QCOMPARE(m_page->url(), aboutBlank); + QCOMPARE(m_page->requestedUrl(), QUrl()); + // Since the entry of the unavailable page is not stored it will not available in the history. + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << aboutBlank.toString()); url = QUrl("qrc:/test1.html"); m_page->setUrl(url); @@ -1385,25 +1390,31 @@ void tst_QWebEngineFrame::setUrlHistory() QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << QStringLiteral("qrc:/test1.html")); + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << aboutBlank.toString() << QStringLiteral("qrc:/test1.html")); m_page->setUrl(QUrl()); expectedLoadFinishedCount++; QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), aboutBlank); QCOMPARE(m_page->requestedUrl(), QUrl()); - QEXPECT_FAIL("", "Slight change: load(QUrl()) currently loads about:blank and nothing prevents it from being added to the history.", Continue); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << QStringLiteral("qrc:/test1.html")); + // Chromium stores navigation entry for every successful loads. The load of the empty page is committed and stored as about:blank. + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() + << aboutBlank.toString() + << QStringLiteral("qrc:/test1.html") + << aboutBlank.toString()); - // Loading same page as current in history, so history count doesn't change. url = QUrl("qrc:/test1.html"); m_page->setUrl(url); expectedLoadFinishedCount++; QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); - QEXPECT_FAIL("", "Slight change: load(QUrl()) currently loads about:blank and nothing prevents it from being added to the history.", Continue); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << QStringLiteral("qrc:/test1.html")); + // The history count DOES change since the about:blank is in the list. + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() + << aboutBlank.toString() + << QStringLiteral("qrc:/test1.html") + << aboutBlank.toString() + << QStringLiteral("qrc:/test1.html")); url = QUrl("qrc:/test2.html"); m_page->setUrl(url); @@ -1411,8 +1422,12 @@ void tst_QWebEngineFrame::setUrlHistory() QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); - QEXPECT_FAIL("", "Slight change: load(QUrl()) currently loads about:blank and nothing prevents it from being added to the history.", Continue); - QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << QStringLiteral("qrc:/test1.html") << QStringLiteral("qrc:/test2.html")); + QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() + << aboutBlank.toString() + << QStringLiteral("qrc:/test1.html") + << aboutBlank.toString() + << QStringLiteral("qrc:/test1.html") + << QStringLiteral("qrc:/test2.html")); } void tst_QWebEngineFrame::setUrlUsingStateObject() @@ -1534,7 +1549,6 @@ void tst_QWebEngineFrame::setUrlThenLoads() // Just after first load. URL didn't changed yet. m_page->load(urlToLoad1); - QEXPECT_FAIL("", "Slight change: url() will return the loaded URL immediately.", Continue); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), urlToLoad1); // baseUrlSync spins an event loop and this sometimes return the next result. @@ -1551,7 +1565,6 @@ void tst_QWebEngineFrame::setUrlThenLoads() // Just after second load. URL didn't changed yet. m_page->load(urlToLoad2); - QEXPECT_FAIL("", "Slight change: url() will return the loaded URL immediately.", Continue); QCOMPARE(m_page->url(), urlToLoad1); QCOMPARE(m_page->requestedUrl(), urlToLoad2); QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1)); diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index f0a89d9aa..85939a686 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -191,6 +191,8 @@ private Q_SLOTS: void macCopyUnicodeToClipboard(); #endif + void runJavaScript(); + private: QWebEngineView* m_view; QWebEnginePage* m_page; @@ -3563,14 +3565,14 @@ void tst_QWebEnginePage::getUserMediaRequest() QVERIFY(evaluateJavaScriptSync(page, QStringLiteral("!!navigator.webkitGetUserMedia")).toBool()); evaluateJavaScriptSync(page, QStringLiteral("navigator.webkitGetUserMedia({audio: true}, function() {}, function(){})")); - QTRY_VERIFY_WITH_TIMEOUT(page->gotFeatureRequest(QWebEnginePage::MediaAudioDevices), 100); + QTRY_VERIFY_WITH_TIMEOUT(page->gotFeatureRequest(QWebEnginePage::MediaAudioCapture), 100); // Might end up failing due to the lack of physical media devices deeper in the content layer, so the JS callback is not guaranteed to be called, // but at least we go through that code path, potentially uncovering failing assertions. page->acceptPendingRequest(); page->runJavaScript(QStringLiteral("errorCallbackCalled = false;")); evaluateJavaScriptSync(page, QStringLiteral("navigator.webkitGetUserMedia({audio: true, video: true}, function() {}, function(){errorCallbackCalled = true;})")); - QTRY_VERIFY_WITH_TIMEOUT(page->gotFeatureRequest(QWebEnginePage::MediaAudioVideoDevices), 100); + QTRY_VERIFY_WITH_TIMEOUT(page->gotFeatureRequest(QWebEnginePage::MediaAudioVideoCapture), 100); page->rejectPendingRequest(); // Should always end up calling the error callback in JS. QTRY_VERIFY_WITH_TIMEOUT(evaluateJavaScriptSync(page, QStringLiteral("errorCallbackCalled;")).toBool(), 100); delete page; @@ -3666,5 +3668,71 @@ void tst_QWebEnginePage::cssMediaTypePageSetting() #endif } +class JavaScriptCallback +{ +public: + JavaScriptCallback() { } + JavaScriptCallback(const QVariant& _expected) : expected(_expected) { } + virtual void operator() (const QVariant& result) { + QVERIFY(result.isValid()); + QCOMPARE(result, expected); + } +private: + QVariant expected; +}; + +class JavaScriptCallbackNull +{ +public: + virtual void operator() (const QVariant& result) { + QVERIFY(result.isNull()); +// FIXME: Returned null values are currently invalid QVariants. +// QVERIFY(result.isValid()); + } +}; + +class JavaScriptCallbackUndefined +{ +public: + virtual void operator() (const QVariant& result) { + QVERIFY(result.isNull()); + QVERIFY(!result.isValid()); + } +}; + +void tst_QWebEnginePage::runJavaScript() +{ + TestPage page; + + JavaScriptCallback callbackBool(QVariant(false)); + page.runJavaScript("false", QWebEngineCallback<const QVariant&>(callbackBool)); + + JavaScriptCallback callbackInt(QVariant(2)); + page.runJavaScript("2", QWebEngineCallback<const QVariant&>(callbackInt)); + + JavaScriptCallback callbackDouble(QVariant(2.5)); + page.runJavaScript("2.5", QWebEngineCallback<const QVariant&>(callbackDouble)); + + JavaScriptCallback callbackString(QVariant(QStringLiteral("Test"))); + page.runJavaScript("\"Test\"", QWebEngineCallback<const QVariant&>(callbackString)); + + QVariantList list; + JavaScriptCallback callbackList(list); + page.runJavaScript("[]", QWebEngineCallback<const QVariant&>(callbackList)); + + QVariantMap map; + map.insert(QStringLiteral("test"), QVariant(2)); + JavaScriptCallback callbackMap(map); + page.runJavaScript("var el = {\"test\": 2}; el", QWebEngineCallback<const QVariant&>(callbackMap)); + + JavaScriptCallbackNull callbackNull; + page.runJavaScript("null", QWebEngineCallback<const QVariant&>(callbackNull)); + + JavaScriptCallbackNull callbackUndefined; + page.runJavaScript("undefined", QWebEngineCallback<const QVariant&>(callbackUndefined)); + + QTest::qWait(100); +} + QTEST_MAIN(tst_QWebEnginePage) #include "tst_qwebenginepage.moc" diff --git a/tests/quicktestbrowser/quickwindow.qml b/tests/quicktestbrowser/quickwindow.qml index 36668fc6d..b1be6db3e 100644 --- a/tests/quicktestbrowser/quickwindow.qml +++ b/tests/quicktestbrowser/quickwindow.qml @@ -70,6 +70,7 @@ ApplicationWindow { Settings { property alias autoLoadImages: loadImages.checked; property alias javaScriptEnabled: javaScriptEnabled.checked; + property alias errorPageEnabled: errorPageEnabled.checked; } // Make sure the Qt.WindowFullscreenButtonHint is set on Mac. @@ -227,6 +228,13 @@ ApplicationWindow { checked: WebEngine.settings.javascriptEnabled onCheckedChanged: WebEngine.settings.javascriptEnabled = checked } + MenuItem { + id: errorPageEnabled + text: "ErrorPage On" + checkable: true + checked: WebEngine.settings.errorPageEnabled + onCheckedChanged: WebEngine.settings.errorPageEnabled = checked + } } } } |