diff options
Diffstat (limited to 'tests')
103 files changed, 2162 insertions, 465 deletions
diff --git a/tests/auto/quick/dialogs/WebView.qml b/tests/auto/quick/dialogs/WebView.qml new file mode 100644 index 000000000..6509071b8 --- /dev/null +++ b/tests/auto/quick/dialogs/WebView.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtWebEngine 1.4 +import QtQuick.Window 2.0 +import QtTest 1.0 +import io.qt.tester 1.0 + +Window { + width: 50 + height: 50 + visible: true + + TestHandler { + id: handler + onJavaScript: function(script) { + view.runJavaScript(script , function(result) { + handler.ready = true + }) + } + onLoadPage: function(url) { + if (view.url === url) { + handler.ready = true + return + } + view.url = url + } + } + + WebEngineView { + id: view + anchors.fill: parent + onLoadingChanged: function(reqeust) { + if (reqeust.status === WebEngineView.LoadSucceededStatus) { + handler.ready = true + } + } + + onContextMenuRequested: function(request) { + request.accepted = true; + handler.request = request; + } + + onAuthenticationDialogRequested: function(request) { + request.accepted = true; + handler.request = request; + } + + onJavaScriptDialogRequested: function(request) { + request.accepted = true; + handler.request = request; + } + + onColorDialogRequested: function(request) { + request.accepted = true; + handler.request = request; + } + + onFileDialogRequested: function(request) { + request.accepted = true; + handler.request = request; + } + } +} diff --git a/tests/auto/quick/dialogs/dialogs.pro b/tests/auto/quick/dialogs/dialogs.pro new file mode 100644 index 000000000..e262c3814 --- /dev/null +++ b/tests/auto/quick/dialogs/dialogs.pro @@ -0,0 +1,13 @@ +include(../tests.pri) +QT += webengine webengine-private + +HEADERS += \ + server.h \ + testhandler.h + +SOURCES += \ + server.cpp \ + testhandler.cpp + +RESOURCES += \ + dialogs.qrc diff --git a/tests/auto/quick/dialogs/dialogs.qrc b/tests/auto/quick/dialogs/dialogs.qrc new file mode 100644 index 000000000..a0715dbce --- /dev/null +++ b/tests/auto/quick/dialogs/dialogs.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>index.html</file> + <file>WebView.qml</file> + </qresource> +</RCC> diff --git a/tests/auto/quick/dialogs/index.html b/tests/auto/quick/dialogs/index.html new file mode 100644 index 000000000..8b0520a0e --- /dev/null +++ b/tests/auto/quick/dialogs/index.html @@ -0,0 +1,21 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <style type="text/css"> + .fullscreen + { + position:absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } + </style> + </head> + <body> + <button class="fullscreen" id="buttonOne">Click Me</button> + <input type="color" id="colorpicker" value="#ff0000" style="visibility:hidden"/> + <input type="file" id="filepicker" accept=".cpp, .html, .h, .png, .qdoc, .qml" style="visibility:hidden"/> + </body> +</html> diff --git a/tests/auto/quick/dialogs/server.cpp b/tests/auto/quick/dialogs/server.cpp new file mode 100644 index 000000000..dc9cfe582 --- /dev/null +++ b/tests/auto/quick/dialogs/server.cpp @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "server.h" +#include <QDataStream> +#include <QTcpSocket> +#include <QDebug> + +Server::Server(QObject *parent) : QObject(parent) +{ + m_data.clear(); + connect(&m_server, &QTcpServer::newConnection, this, &Server::handleNewConnection); +} + +bool Server::isListening() +{ + return m_server.isListening(); +} + +void Server::run() +{ + if (!m_server.listen(QHostAddress::LocalHost, 5555)) + qFatal("Could not start the test server"); +} + +void Server::handleNewConnection() +{ + // do one connection at the time + Q_ASSERT(m_data.isEmpty()); + QTcpSocket *socket = m_server.nextPendingConnection(); + Q_ASSERT(socket); + connect(socket, &QAbstractSocket::disconnected, socket, &QObject::deleteLater); + connect(socket, &QAbstractSocket::readyRead, this, &Server::handleReadReady); +} + +void Server::handleReadReady() +{ + QTcpSocket *socket = qobject_cast<QTcpSocket*>(sender()); + Q_ASSERT(socket); + + m_data.append(socket->readAll()); + + //simply wait for whole request + if (!m_data.endsWith("\r\n\r\n")) + return; + + if (m_data.contains(QByteArrayLiteral("OPEN_AUTH"))) + socket->write("HTTP/1.1 401 Unauthorized\nWWW-Authenticate: " + "Basic realm=\"Very Restricted Area\"\r\n\r\n"); + if (m_data.contains(QByteArrayLiteral("OPEN_PROXY"))) + socket->write("HTTP/1.1 407 Proxy Auth Required\nProxy-Authenticate: " + "Basic realm=\"Proxy requires authentication\"\r\n\r\n"); + m_data.clear(); + socket->disconnectFromHost(); +} diff --git a/tests/auto/quick/dialogs/server.h b/tests/auto/quick/dialogs/server.h new file mode 100644 index 000000000..24da47523 --- /dev/null +++ b/tests/auto/quick/dialogs/server.h @@ -0,0 +1,57 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef SERVER_H +#define SERVER_H + +#include <QObject> +#include <QTcpServer> + +class Server : public QObject +{ + Q_OBJECT + +public: + explicit Server(QObject *parent = nullptr); + + bool isListening(); + +public slots: + void run(); + +private slots: + void handleNewConnection(); + void handleReadReady(); + +private: + QByteArray m_data; + QTcpServer m_server; + +}; + +#endif // SERVER_H diff --git a/tests/auto/quick/dialogs/testhandler.cpp b/tests/auto/quick/dialogs/testhandler.cpp new file mode 100644 index 000000000..bdd63a547 --- /dev/null +++ b/tests/auto/quick/dialogs/testhandler.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testhandler.h" + +TestHandler::TestHandler(QObject *parent) : QObject(parent) +{ + setObjectName(QStringLiteral("TestListner")); +} + +QObject* TestHandler::request() const +{ + return m_request; +} + +void TestHandler::setRequest(QObject *request) +{ + if (m_request == request) + return; + + m_request = request; + emit requestChanged(m_request); +} + +void TestHandler::runJavaScript(const QString &script) +{ + m_ready = false; + emit javaScript(script); +} + +void TestHandler::load(const QUrl &page) +{ + m_ready = false; + emit loadPage(page); +} + +bool TestHandler::ready() const +{ + return m_ready; +} + +void TestHandler::setReady(bool ready) +{ + if (m_ready == ready) + return; + + m_ready = ready; + emit readyChanged(ready); +} diff --git a/tests/auto/quick/dialogs/testhandler.h b/tests/auto/quick/dialogs/testhandler.h new file mode 100644 index 000000000..93ecfcdcb --- /dev/null +++ b/tests/auto/quick/dialogs/testhandler.h @@ -0,0 +1,60 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef TESTHANDLER_H +#define TESTHANDLER_H + +#include <QObject> + +class TestHandler : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject* request READ request WRITE setRequest NOTIFY requestChanged) + Q_PROPERTY(bool ready READ ready WRITE setReady NOTIFY readyChanged) +public: + explicit TestHandler(QObject *parent = nullptr); + QObject* request() const; + + bool ready() const; + void setReady(bool ready); + void setRequest(QObject *request); + void runJavaScript(const QString &script); + void load(const QUrl &page); + +signals: + void loadPage(const QUrl &page); + void javaScript(const QString &script); + void requestChanged(QObject *request); + void readyChanged(bool ready); + +private: + QObject *m_request = nullptr; + bool m_ready = false; +}; + +#endif // TESTHANDLER_H diff --git a/tests/auto/quick/dialogs/tst_dialogs.cpp b/tests/auto/quick/dialogs/tst_dialogs.cpp new file mode 100644 index 000000000..e1032f16c --- /dev/null +++ b/tests/auto/quick/dialogs/tst_dialogs.cpp @@ -0,0 +1,225 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qtwebengineglobal.h" +#include "testhandler.h" +#include "server.h" +#include <QtWebEngine/private/qquickwebenginedialogrequests_p.h> +#include <QtWebEngine/private/qquickwebenginecontextmenurequest_p.h> +#include <QQuickWebEngineProfile> +#include <QQmlApplicationEngine> +#include <QQuickWindow> +#include <QTest> +#include <QSignalSpy> +#include <QNetworkProxy> + + +class tst_Dialogs : public QObject { + Q_OBJECT +public: + tst_Dialogs(){} + +private slots: + void initTestCase(); + void init(); + void contextMenuRequested(); + void javaScriptDialogRequested(); + void javaScriptDialogRequested_data(); + void colorDialogRequested(); + void fileDialogRequested(); + void authenticationDialogRequested_data(); + void authenticationDialogRequested(); + +private: + void createDialog(const QLatin1String& dialog, bool &ok); +private: + QScopedPointer<QQmlApplicationEngine> m_engine; + QQuickWindow *m_widnow; + TestHandler *m_listner; +}; + +void tst_Dialogs::initTestCase() +{ + QtWebEngine::initialize(); + QQuickWebEngineProfile::defaultProfile()->setOffTheRecord(true); + qmlRegisterType<TestHandler>("io.qt.tester", 1, 0, "TestHandler"); + m_engine.reset(new QQmlApplicationEngine()); + m_engine->load(QUrl(QStringLiteral("qrc:/WebView.qml"))); + m_widnow = qobject_cast<QQuickWindow*>(m_engine->rootObjects().first()); + Q_ASSERT(m_widnow); + m_listner = m_widnow->findChild<TestHandler*>(QStringLiteral("TestListner")); + Q_ASSERT(m_listner); + + QNetworkProxy proxy; + proxy.setType(QNetworkProxy::HttpProxy); + proxy.setHostName("localhost"); + proxy.setPort(5555); + QNetworkProxy::setApplicationProxy(proxy); +} + +void tst_Dialogs::init() +{ + m_listner->setRequest(nullptr); + m_listner->setReady(false); +} + +void tst_Dialogs::createDialog(const QLatin1String& dialog, bool &ok) +{ + QString trigger = QStringLiteral("document.getElementById('buttonOne').onclick = function() {document.getElementById('%1').click()}"); + QSignalSpy dialogSpy(m_listner, &TestHandler::requestChanged); + m_listner->runJavaScript(trigger.arg(dialog)); + QTRY_VERIFY(m_listner->ready()); + QTest::mouseClick(m_widnow, Qt::LeftButton); + QTRY_COMPARE(dialogSpy.count(), 1); + ok = true; +} + +void tst_Dialogs::colorDialogRequested() +{ + m_listner->load(QUrl("qrc:/index.html")); + QTRY_VERIFY(m_listner->ready()); + bool ok = false; + createDialog(QLatin1String("colorpicker"), ok); + if (ok) { + auto dialog = qobject_cast<QQuickWebEngineColorDialogRequest*>(m_listner->request()); + QVERIFY2(dialog, "Incorrect dialog requested"); + dialog->dialogReject(); + QVERIFY2(dialog->isAccepted(), "Dialog is not accepted"); + QCOMPARE(dialog->color(), QColor("#ff0000")); + } +} + +void tst_Dialogs::contextMenuRequested() +{ + m_listner->load(QUrl("qrc:/index.html")); + QTRY_VERIFY(m_listner->ready()); + QSignalSpy dialogSpy(m_listner, &TestHandler::requestChanged); + QTest::mouseClick(m_widnow, Qt::RightButton); + QTRY_COMPARE(dialogSpy.count(), 1); + auto dialog = qobject_cast<QQuickWebEngineContextMenuRequest*>(m_listner->request()); + QVERIFY2(dialog, "Incorrect dialog requested"); +} + +void tst_Dialogs::fileDialogRequested() +{ + m_listner->load(QUrl("qrc:/index.html")); + QTRY_VERIFY(m_listner->ready()); + bool ok = false; + createDialog(QLatin1String("filepicker"), ok); + if (ok) { + auto dialog = qobject_cast<QQuickWebEngineFileDialogRequest*>(m_listner->request()); + QVERIFY2(dialog, "Incorrect dialog requested"); + dialog->dialogReject(); + QVERIFY2(dialog->isAccepted(), "Dialog is not accepted"); + QStringList mimeTypes {".cpp", ".html", ".h" , ".png", ".qdoc", ".qml"}; + QCOMPARE(dialog->acceptedMimeTypes(), mimeTypes); + } +} + +void tst_Dialogs::authenticationDialogRequested_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<QQuickWebEngineAuthenticationDialogRequest::AuthenticationType>("type"); + QTest::addColumn<QString>("realm"); + QTest::newRow("Http Authentication Dialog") << QUrl("http://localhost:5555/OPEN_AUTH") + << QQuickWebEngineAuthenticationDialogRequest::AuthenticationTypeHTTP + << QStringLiteral("Very Restricted Area"); + QTest::newRow("Proxy Authentication Dialog") << QUrl("http://localhost.:5555/OPEN_PROXY") + << QQuickWebEngineAuthenticationDialogRequest::AuthenticationTypeProxy + << QStringLiteral("Proxy requires authentication"); +} + +void tst_Dialogs::authenticationDialogRequested() +{ + QFETCH(QUrl, url); + QFETCH(QQuickWebEngineAuthenticationDialogRequest::AuthenticationType, type); + QFETCH(QString, realm); + + Server server; + server.run(); + QTRY_VERIFY2(server.isListening(), "Could not setup authentication server"); + + QSignalSpy dialogSpy(m_listner, &TestHandler::requestChanged); + m_listner->load(url); + + QTRY_COMPARE(dialogSpy.count(), 1); + auto dialog = qobject_cast<QQuickWebEngineAuthenticationDialogRequest*>(m_listner->request()); + QVERIFY2(dialog, "Incorrect dialog requested"); + dialog->dialogReject(); + QVERIFY2(dialog->isAccepted(), "Dialog is not accepted"); + QCOMPARE(dialog->type(), type); + QCOMPARE(dialog->realm(),realm); + QCOMPARE(dialog->url(), url); + QCOMPARE(dialog->proxyHost(), "localhost"); +} + +void tst_Dialogs::javaScriptDialogRequested_data() +{ + QTest::addColumn<QString>("script"); + QTest::addColumn<QQuickWebEngineJavaScriptDialogRequest::DialogType>("type"); + QTest::addColumn<QString>("message"); + QTest::addColumn<QString>("defaultText"); + QTest::newRow("AlertDialog") << QStringLiteral("alert('This is the Alert Dialog !')") + << QQuickWebEngineJavaScriptDialogRequest::DialogTypeAlert + << QStringLiteral("This is the Alert Dialog !") + << QString(); + QTest::newRow("PromptDialog")<< QStringLiteral("prompt('Is this the Prompt Dialog ?', 'Yes')") + << QQuickWebEngineJavaScriptDialogRequest::DialogTypePrompt + << QStringLiteral("Is this the Prompt Dialog ?") + << QStringLiteral("Yes"); + QTest::newRow("ConfirmDialog")<< QStringLiteral("confirm('This is the Confirm Dialog.')") + << QQuickWebEngineJavaScriptDialogRequest::DialogTypeConfirm + << QStringLiteral("This is the Confirm Dialog.") + << QString(); +} + +void tst_Dialogs::javaScriptDialogRequested() +{ + QFETCH(QString, script); + QFETCH(QQuickWebEngineJavaScriptDialogRequest::DialogType, type); + QFETCH(QString, message); + QFETCH(QString, defaultText); + + m_listner->load(QUrl("qrc:/index.html")); + QTRY_VERIFY(m_listner->ready()); + + QSignalSpy dialogSpy(m_listner, &TestHandler::requestChanged); + m_listner->runJavaScript(script); + QTRY_COMPARE(dialogSpy.count(), 1); + auto dialog = qobject_cast<QQuickWebEngineJavaScriptDialogRequest*>(m_listner->request()); + QVERIFY2(dialog, "Incorrect dialog requested"); + dialog->dialogReject(); + QVERIFY2(dialog->isAccepted(), "Dialog is not accepted"); + QCOMPARE(dialog->type(), type); + QCOMPARE(dialog->message(), message); + QCOMPARE(dialog->defaultText(), defaultText); +} + +#include "tst_dialogs.moc" +QTEST_MAIN(tst_Dialogs) + diff --git a/tests/auto/quick/inspectorserver/inspectorserver.pro b/tests/auto/quick/inspectorserver/inspectorserver.pro index 1a2c2f053..fdc213f38 100644 --- a/tests/auto/quick/inspectorserver/inspectorserver.pro +++ b/tests/auto/quick/inspectorserver/inspectorserver.pro @@ -1,4 +1,4 @@ include(../tests.pri) QT += webengine -QT_PRIVATE += webengine-private +QT_PRIVATE += core-private webengine-private webenginecore-private DEFINES += IMPORT_DIR=\"\\\"$${ROOT_BUILD_DIR}$${QMAKE_DIR_SEP}imports\\\"\" diff --git a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp index e45b4466c..8e23e86e8 100644 --- a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp +++ b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp @@ -33,7 +33,7 @@ #include <QtQml/QQmlEngine> #include <QtTest/QtTest> #include <QQuickWebEngineProfile> -#include <private/qquickwebengineview_p.h> +#include <QtWebEngine/private/qquickwebengineview_p.h> #define INSPECTOR_SERVER_PORT "23654" static const QUrl s_inspectorServerHttpBaseUrl("http://localhost:" INSPECTOR_SERVER_PORT); @@ -167,7 +167,7 @@ void tst_InspectorServer::openRemoteDebuggingSession() // - The page list didn't return a valid inspector URL // - Or the front-end couldn't be loaded through the inspector HTTP server // - Or the web socket connection couldn't be established between the front-end and the page through the inspector server - QTRY_VERIFY(inspectorWebView->title().startsWith("Developer Tools -")); + QTRY_VERIFY(inspectorWebView->title().startsWith("DevTools -")); } QTEST_MAIN(tst_InspectorServer) diff --git a/tests/auto/quick/publicapi/publicapi.pro b/tests/auto/quick/publicapi/publicapi.pro index b178f56cd..c56fd2503 100644 --- a/tests/auto/quick/publicapi/publicapi.pro +++ b/tests/auto/quick/publicapi/publicapi.pro @@ -1,3 +1,3 @@ include(../tests.pri) QT += webengine -QT_PRIVATE += webengine-private +QT_PRIVATE += core-private webengine-private webenginecore-private diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index 27f1ec616..d8c1bd80c 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -38,6 +38,7 @@ #include <QtWebEngineCore/QWebEngineQuotaRequest> #include <QtWebEngineCore/QWebEngineRegisterProtocolHandlerRequest> #include <private/qquickwebengineview_p.h> +#include <private/qquickwebengineaction_p.h> #include <private/qquickwebenginecertificateerror_p.h> #include <private/qquickwebenginedialogrequests_p.h> #include <private/qquickwebenginedownloaditem_p.h> @@ -55,8 +56,9 @@ private Q_SLOTS: void publicAPI(); }; -static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>() +static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>() << &QQuickWebEngineView::staticMetaObject + << &QQuickWebEngineAction::staticMetaObject << &QQuickWebEngineCertificateError::staticMetaObject << &QQuickWebEngineDownloadItem::staticMetaObject << &QQuickWebEngineHistory::staticMetaObject @@ -81,7 +83,7 @@ static QList<const QMetaObject *> typesToCheck = QList<const QMetaObject *>() static QList<const char *> knownEnumNames = QList<const char *>(); -static QStringList hardcodedTypes = QStringList() +static const QStringList hardcodedTypes = QStringList() << "QJSValue" << "QQmlListProperty<QQuickWebEngineScript>" << "QQmlWebChannel*" @@ -92,7 +94,14 @@ static QStringList hardcodedTypes = QStringList() << "QWebEngineCookieStore*" ; -static QStringList expectedAPI = QStringList() +static const QStringList expectedAPI = QStringList() + << "QQuickWebEngineAction.text --> QString" + << "QQuickWebEngineAction.iconText --> QString" + << "QQuickWebEngineAction.enabled --> bool" + << "QQuickWebEngineAction.toggled() --> void" + << "QQuickWebEngineAction.triggered() --> void" + << "QQuickWebEngineAction.enabledChanged(bool) --> void" + << "QQuickWebEngineAction.trigger() --> void" << "QQuickWebEngineAuthenticationDialogRequest.AuthenticationTypeHTTP --> AuthenticationType" << "QQuickWebEngineAuthenticationDialogRequest.AuthenticationTypeProxy --> AuthenticationType" << "QQuickWebEngineAuthenticationDialogRequest.accepted --> bool" @@ -380,6 +389,7 @@ static QStringList expectedAPI = QStringList() << "QQuickWebEngineSettings.webRTCPublicInterfacesOnlyChanged() --> void" << "QQuickWebEngineSingleton.defaultProfile --> QQuickWebEngineProfile*" << "QQuickWebEngineSingleton.settings --> QQuickWebEngineSettings*" + << "QQuickWebEngineView.action(WebAction) --> QQuickWebEngineAction*" << "QQuickWebEngineView.A0 --> PrintedPageSizeId" << "QQuickWebEngineView.A1 --> PrintedPageSizeId" << "QQuickWebEngineView.A10 --> PrintedPageSizeId" @@ -697,7 +707,7 @@ static bool isCheckedEnum(const QByteArray &typeName) if (tokens.size() == 3) { QByteArray &enumClass = tokens[0]; QByteArray &enumName = tokens[2]; - foreach (const QMetaObject *mo, typesToCheck) { + for (const QMetaObject *mo : typesToCheck) { if (mo->className() != enumClass) continue; for (int i = mo->enumeratorOffset(); i < mo->enumeratorCount(); ++i) @@ -706,7 +716,7 @@ static bool isCheckedEnum(const QByteArray &typeName) } } else if (tokens.size() == 1) { QByteArray &enumName = tokens[0]; - foreach (const char *knownEnumName, knownEnumNames) { + for (const char *knownEnumName : qAsConst(knownEnumNames)) { if (enumName == knownEnumName) return true; } @@ -716,7 +726,7 @@ static bool isCheckedEnum(const QByteArray &typeName) static bool isCheckedClass(const QByteArray &typeName) { - foreach (const QMetaObject *mo, typesToCheck) { + for (const QMetaObject *mo : typesToCheck) { QByteArray moTypeName(mo->className()); if (moTypeName == typeName || moTypeName + "*" == typeName) return true; @@ -752,7 +762,8 @@ static void gatherAPI(const QString &prefix, const QMetaMethod &method, QStringL *output << QString::fromLatin1("%1%2 --> %3").arg(prefix).arg(QString::fromLatin1(method.methodSignature())).arg(QString::fromLatin1(methodTypeName)); checkKnownType(methodTypeName); - foreach (QByteArray paramType, method.parameterTypes()) + const QList<QByteArray> paramTypes = method.parameterTypes(); + for (const QByteArray ¶mType : paramTypes) checkKnownType(paramType); } } @@ -773,23 +784,23 @@ static void gatherAPI(const QString &prefix, const QMetaObject *meta, QStringLis void tst_publicapi::publicAPI() { QStringList actualAPI; - foreach (const QMetaObject *meta, typesToCheck) + for (const QMetaObject *meta : typesToCheck) gatherAPI(QString::fromLatin1(meta->className()) + ".", meta, &actualAPI); // Uncomment to print the actual API. // QStringList sortedAPI(actualAPI); // std::sort(sortedAPI.begin(), sortedAPI.end()); - // foreach (QString actual, sortedAPI) + // for (const QString &actual : qAsConst(sortedAPI)) // printf(" << \"%s\"\n", qPrintable(actual)); // Make sure that nothing slips in the public API unintentionally. - foreach (QString actual, actualAPI) { + for (const QString &actual : qAsConst(actualAPI)) { if (!expectedAPI.contains(actual)) QEXPECT_FAIL("", qPrintable("Expected list is not up-to-date: " + actual), Continue); QVERIFY2(expectedAPI.contains(actual), qPrintable(actual)); } // Make sure that the expected list is up-to-date with intentionally added APIs. - foreach (QString expected, expectedAPI) { + for (const QString &expected : expectedAPI) { if (!actualAPI.contains(expected)) QEXPECT_FAIL("", qPrintable("Not implemented: " + expected), Continue); QVERIFY2(actualAPI.contains(expected), qPrintable(expected)); diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml new file mode 100644 index 000000000..b27e7d821 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_action.qml @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtTest 1.0 +import QtWebEngine 1.8 + +TestWebEngineView { + id: webEngineView + width: 400 + height: 400 + + Component { + id: signalSpy + SignalSpy { } + } + + TestCase { + id: actionTests + name: "WebEngineAction" + when: windowShown + + function test_actions_data() { + return [ + { webAction: WebEngineView.Back, text: "Back", iconText: "go-previous", enabled: false }, + { webAction: WebEngineView.Forward, text: "Forward", iconText: "go-next", enabled: false }, + { webAction: WebEngineView.Stop, text: "Stop", iconText: "", enabled: false }, + { webAction: WebEngineView.Reload, text: "Reload", iconText: "view-refresh", enabled: true }, + { webAction: WebEngineView.Cut, text: "Cut", iconText: "Cut", enabled: true }, + { webAction: WebEngineView.Copy, text: "Copy", iconText: "", enabled: true }, + { webAction: WebEngineView.Paste, text: "Paste", iconText: "", enabled: true }, + { webAction: WebEngineView.Undo, text: "Undo", iconText: "", enabled: true }, + { webAction: WebEngineView.Redo, text: "Redo", iconText: "", enabled: true }, + { webAction: WebEngineView.SelectAll, text: "Select all", iconText: "", enabled: true }, + { webAction: WebEngineView.ReloadAndBypassCache, text: "Reload and Bypass Cache", iconText: "", enabled: true }, + { webAction: WebEngineView.PasteAndMatchStyle, text: "Paste and match style", iconText: "", enabled: true }, + { webAction: WebEngineView.OpenLinkInThisWindow, text: "Open link in this window", iconText: "", enabled: true }, + { webAction: WebEngineView.OpenLinkInNewWindow, text: "Open link in new window", iconText: "", enabled: true }, + { webAction: WebEngineView.OpenLinkInNewTab, text: "Open link in new tab", iconText: "", enabled: true }, + { webAction: WebEngineView.CopyLinkToClipboard, text: "Copy link address", iconText: "", enabled: true }, + { webAction: WebEngineView.DownloadLinkToDisk, text: "Save link", iconText: "", enabled: true }, + { webAction: WebEngineView.CopyImageToClipboard, text: "Copy image", iconText: "", enabled: true }, + { webAction: WebEngineView.CopyImageUrlToClipboard, text: "Copy image address", iconText: "", enabled: true }, + { webAction: WebEngineView.DownloadImageToDisk, text: "Save image", iconText: "", enabled: true }, + { webAction: WebEngineView.CopyMediaUrlToClipboard, text: "Copy media address", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleMediaControls, text: "Show controls", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleMediaLoop, text: "Loop", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleMediaPlayPause, text: "Toggle Play/Pause", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleMediaMute, text: "Toggle Mute", iconText: "", enabled: true }, + { webAction: WebEngineView.DownloadMediaToDisk, text: "Save media", iconText: "", enabled: true }, + { webAction: WebEngineView.InspectElement, text: "Inspect", iconText: "", enabled: true }, + { webAction: WebEngineView.ExitFullScreen, text: "Exit full screen", iconText: "", enabled: true }, + { webAction: WebEngineView.RequestClose, text: "Close Page", iconText: "", enabled: true }, + { webAction: WebEngineView.Unselect, text: "Unselect", iconText: "", enabled: true }, + { webAction: WebEngineView.SavePage, text: "Save page", iconText: "", enabled: true }, + { webAction: WebEngineView.ViewSource, text: "View page source", iconText: "view-source", enabled: true }, + { webAction: WebEngineView.ToggleBold, text: "&Bold", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleItalic, text: "&Italic", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleUnderline, text: "&Underline", iconText: "", enabled: true }, + { webAction: WebEngineView.ToggleStrikethrough, text: "&Strikethrough", iconText: "", enabled: true }, + { webAction: WebEngineView.AlignLeft, text: "Align &Left", iconText: "", enabled: true }, + { webAction: WebEngineView.AlignCenter, text: "Align &Center", iconText: "", enabled: true }, + { webAction: WebEngineView.AlignRight, text: "Align &Right", iconText: "", enabled: true }, + { webAction: WebEngineView.AlignJustified, text: "Align &Justified", iconText: "", enabled: true }, + { webAction: WebEngineView.Indent, text: "&Indent", iconText: "", enabled: true }, + { webAction: WebEngineView.Outdent, text: "&Outdent", iconText: "", enabled: true }, + { webAction: WebEngineView.InsertOrderedList, text: "Insert &Ordered List", iconText: "", enabled: true }, + { webAction: WebEngineView.InsertUnorderedList, text: "Insert &Unordered List", iconText: "", enabled: true } + ]; + } + + function test_actions(row) { + webEngineView.url = Qt.resolvedUrl("test1.html"); + verify(webEngineView.waitForLoadSucceeded()); + + var action = webEngineView.action(row.webAction); + verify(action); + + compare(action.text, row.text); + compare(action.iconText, row.iconText); + compare(action.enabled, row.enabled); + } + + function test_trigger() { + webEngineView.url = Qt.resolvedUrl("test1.html"); + verify(webEngineView.waitForLoadSucceeded()); + + var copyAction = webEngineView.action(WebEngineView.Copy); + verify(copyAction); + + var stopAction = webEngineView.action(WebEngineView.Stop); + verify(stopAction); + + var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: copyAction, signalName: "triggered"}); + var stopTriggerSpy = createTemporaryObject(signalSpy, actionTests, {target: stopAction, signalName: "triggered"}); + + verify(copyAction.enabled); + copyAction.trigger(); + compare(triggerSpy.count, 1); + + verify(!stopAction.enabled); + stopAction.trigger(); + compare(stopTriggerSpy.count, 0); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_contextMenu.qml b/tests/auto/quick/qmltests/data/tst_contextMenu.qml index 4b6ba2bee..99450a159 100644 --- a/tests/auto/quick/qmltests/data/tst_contextMenu.qml +++ b/tests/auto/quick/qmltests/data/tst_contextMenu.qml @@ -144,6 +144,11 @@ TestWebEngineView { compare(mediaType, ContextMenuRequest.MediaTypeNone); compare(selectedText, ""); + verify(webEngineView.action(WebEngineView.OpenLinkInNewTab).enabled); + verify(webEngineView.action(WebEngineView.OpenLinkInNewWindow).enabled); + verify(webEngineView.action(WebEngineView.DownloadLinkToDisk).enabled); + verify(webEngineView.action(WebEngineView.CopyLinkToClipboard).enabled); + contextMenuRequestedSpy.clear(); // FIXME: Sometimes the keyPress(Qt.Key_Escape) event isn't caught so we keep trying tryVerify(destroyContextMenu); diff --git a/tests/auto/quick/qmltests/data/tst_favicon.qml b/tests/auto/quick/qmltests/data/tst_favicon.qml index 6f8adeb67..563a87c83 100644 --- a/tests/auto/quick/qmltests/data/tst_favicon.qml +++ b/tests/auto/quick/qmltests/data/tst_favicon.qml @@ -30,6 +30,7 @@ import QtQuick 2.0 import QtTest 1.0 import QtWebEngine 1.3 import QtWebEngine.testsupport 1.0 +import QtQuick.Window 2.0 TestWebEngineView { id: webEngineView @@ -181,7 +182,7 @@ TestWebEngineView { var url = Qt.resolvedUrl("http://url.invalid") webEngineView.url = url - verify(webEngineView.waitForLoadFailed()) + verify(webEngineView.waitForLoadFailed(20000)) verify(webEngineView.testSupport.waitForErrorPageLoadSucceeded()) compare(iconChangedSpy.count, 0) @@ -197,7 +198,7 @@ TestWebEngineView { var url = Qt.resolvedUrl("http://url.invalid") webEngineView.url = url - verify(webEngineView.waitForLoadFailed()) + verify(webEngineView.waitForLoadFailed(20000)) compare(iconChangedSpy.count, 0) @@ -323,8 +324,8 @@ TestWebEngineView { iconChangedSpy.wait() compare(iconChangedSpy.count, 1) - faviconImage.width = row.size - faviconImage.height = row.size + faviconImage.width = row.size / Screen.devicePixelRatio + faviconImage.height = row.size / Screen.devicePixelRatio faviconImage.source = webEngineView.icon var pixel = getFaviconPixel(faviconImage); diff --git a/tests/auto/quick/qmltests/data/tst_geopermission.qml b/tests/auto/quick/qmltests/data/tst_geopermission.qml index 642cf2016..c935ac0b4 100644 --- a/tests/auto/quick/qmltests/data/tst_geopermission.qml +++ b/tests/auto/quick/qmltests/data/tst_geopermission.qml @@ -70,6 +70,7 @@ TestWebEngineView { TestCase { name: "WebViewGeopermission" + when: windowShown function init() { deniedGeolocation = false diff --git a/tests/auto/quick/qmltests/data/tst_getUserMedia.qml b/tests/auto/quick/qmltests/data/tst_getUserMedia.qml index b497542e3..d1c894699 100644 --- a/tests/auto/quick/qmltests/data/tst_getUserMedia.qml +++ b/tests/auto/quick/qmltests/data/tst_getUserMedia.qml @@ -32,11 +32,14 @@ import QtWebEngine 1.6 TestWebEngineView { id: webEngineView + width: 400 + height: 400 settings.screenCaptureEnabled: true TestCase { name: "GetUserMedia" + when: windowShown function init_data() { return [ diff --git a/tests/auto/quick/qmltests/data/tst_loadUrl.qml b/tests/auto/quick/qmltests/data/tst_loadUrl.qml index d1b6d6099..ec5c965ea 100644 --- a/tests/auto/quick/qmltests/data/tst_loadUrl.qml +++ b/tests/auto/quick/qmltests/data/tst_loadUrl.qml @@ -204,7 +204,7 @@ TestWebEngineView { // Test loadHtml after a failed load var aboutBlank = "about:blank"; webEngineView.url = aboutBlank; // Reset from previous test - verify(webEngineView.waitForLoadSucceeded()); + tryCompare(loadRequestArray, "length", 2); webEngineView.clear(); var bogusSite = "http://www.somesitethatdoesnotexist.abc/"; @@ -217,7 +217,7 @@ TestWebEngineView { } webEngineView.loadingChanged.connect(handleLoadFailed); webEngineView.url = bogusSite - tryCompare(loadRequestArray, "length", 4, 12000); + tryCompare(loadRequestArray, "length", 4, 30000); webEngineView.loadingChanged.disconnect(handleLoadFailed); loadRequest = loadRequestArray[0]; diff --git a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml index 55b71189d..24b352dde 100644 --- a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml +++ b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml @@ -27,6 +27,7 @@ ****************************************************************************/ import QtQuick 2.2 +import QtQuick.Window 2.0 import QtTest 1.0 import QtWebEngine 1.3 @@ -60,7 +61,7 @@ TestWebEngineView { tryCompare(scrollPositionSpy, "count", 1); compare(webEngineView.scrollPosition.x, 0); - compare(webEngineView.scrollPosition.y, 600); + compare(webEngineView.scrollPosition.y, 600 * Screen.devicePixelRatio); } function test_scrollPositionAfterReload() { @@ -73,13 +74,13 @@ TestWebEngineView { // Wait for proper scroll position change otherwise we cannot expect // the new y position after reload. tryCompare(webEngineView.scrollPosition, "x", 0); - tryCompare(webEngineView.scrollPosition, "y", 600); + tryCompare(webEngineView.scrollPosition, "y", 600 * Screen.devicePixelRatio); webEngineView.reload(); verify(webEngineView.waitForLoadSucceeded()); tryCompare(webEngineView.scrollPosition, "x", 0); - tryCompare(webEngineView.scrollPosition, "y", 600); + tryCompare(webEngineView.scrollPosition, "y", 600 * Screen.devicePixelRatio); } } } diff --git a/tests/auto/quick/qmltests/data/tst_viewSource.qml b/tests/auto/quick/qmltests/data/tst_viewSource.qml index b21d72eb2..4966a052a 100644 --- a/tests/auto/quick/qmltests/data/tst_viewSource.qml +++ b/tests/auto/quick/qmltests/data/tst_viewSource.qml @@ -77,8 +77,7 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("test1.html"); verify(webEngineView.waitForLoadSucceeded()); tryCompare(webEngineView, "title", "Test page 1"); - // FIXME(pvarga): Reintroduce this check in the fix for QTBUG-56117 - //verify(webEngineView.canViewSource, true); + verify(webEngineView.action(WebEngineView.ViewSource).enabled); titleChangedSpy.clear(); webEngineView.triggerWebAction(WebEngineView.ViewSource); @@ -89,8 +88,7 @@ TestWebEngineView { compare(viewRequest.destination, WebEngineView.NewViewInTab); verify(viewRequest.userInitiated); - // FIXME(pvarga): Reintroduce this check in the fix for QTBUG-56117 - //verify(!webEngineView.canViewSource); + verify(!webEngineView.action(WebEngineView.ViewSource).enabled); tryCompare(webEngineView, "title", "test1.html"); compare(webEngineView.url, "view-source:" + Qt.resolvedUrl("test1.html")); @@ -123,8 +121,7 @@ TestWebEngineView { compare(webEngineView.url, row.url); tryCompare(webEngineView, "title", row.title); - // FIXME(pvarga): Reintroduce this check in the fix for QTBUG-56117 - //verify(!webEngineView.canViewSource); + verify(!webEngineView.action(WebEngineView.ViewSource).enabled); } function test_viewSourceCredentials() { diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 5395da0b5..a2b05e091 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -42,6 +42,7 @@ OTHER_FILES += \ $$PWD/data/keyboardModifierMapping.html \ $$PWD/data/keyboardEvents.html \ $$PWD/data/titleupdate.js \ + $$PWD/data/tst_action.qml \ $$PWD/data/tst_activeFocusOnPress.qml \ $$PWD/data/tst_contextMenu.qml \ $$PWD/data/tst_desktopBehaviorLoadHtml.qml \ diff --git a/tests/auto/quick/qmltests/tst_qmltests.cpp b/tests/auto/quick/qmltests/tst_qmltests.cpp index 2aa24b76c..ba7a992db 100644 --- a/tests/auto/quick/qmltests/tst_qmltests.cpp +++ b/tests/auto/quick/qmltests/tst_qmltests.cpp @@ -128,7 +128,6 @@ int main(int argc, char **argv) QtWebEngine::initialize(); QQuickWebEngineProfile::defaultProfile()->setOffTheRecord(true); - QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS QTEST_SET_MAIN_SOURCE_PATH int i = quick_test_main(argc, argv, "qmltests", QUICK_TEST_SOURCE_DIR); diff --git a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro index 826b47de7..699186741 100644 --- a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro +++ b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/qquickwebenginedefaultsurfaceformat.pro @@ -1,6 +1,6 @@ include(../tests.pri) exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc -QT_PRIVATE += webengine-private +QT_PRIVATE += core-private webengine-private webenginecore-private HEADERS += ../shared/util.h diff --git a/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro b/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro index 25bf44597..c253bc2a6 100644 --- a/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro +++ b/tests/auto/quick/qquickwebengineview/qquickwebengineview.pro @@ -1,11 +1,6 @@ include(../tests.pri) exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc -QT_PRIVATE += webengine-private gui-private +QT_PRIVATE += webengine-private gui-private webenginecore-private HEADERS += ../shared/util.h - -qtConfig(webengine-printing-and-pdf) { - DEFINES += ENABLE_PDF -} - diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index b252fa763..cf695228c 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -37,9 +37,9 @@ #include <QtQml/QQmlEngine> #include <QtTest/QtTest> #include <QtWebEngine/QQuickWebEngineProfile> -#include <private/qinputmethod_p.h> -#include <private/qquickwebengineview_p.h> -#include <private/qquickwebenginesettings_p.h> +#include <QtGui/private/qinputmethod_p.h> +#include <QtWebEngine/private/qquickwebengineview_p.h> +#include <QtWebEngine/private/qquickwebenginesettings_p.h> #include <qpa/qplatforminputcontext.h> #include <functional> @@ -364,7 +364,7 @@ void tst_QQuickWebEngineView::basicRenderingSanity() { showWebEngineView(); - webEngineView()->setUrl(QUrl(QString::fromUtf8("data:text/html,<html><body bgcolor=\"#00ff00\"></body></html>"))); + webEngineView()->setUrl(QUrl(QString::fromUtf8("data:text/html,<html><body bgcolor=\"%2300ff00\"></body></html>"))); QVERIFY(waitForLoadSucceeded(webEngineView())); // This should not crash. @@ -623,8 +623,8 @@ void tst_QQuickWebEngineView::setZoomFactor() void tst_QQuickWebEngineView::printToPdf() { -#if !defined(ENABLE_PDF) - QSKIP("ENABLE_PDF"); +#if !QT_CONFIG(webengine_printing_and_pdf) + QSKIP("no webengine-printing-and-pdf"); #else QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); QVERIFY(tempDir.isValid()); @@ -650,7 +650,7 @@ void tst_QQuickWebEngineView::printToPdf() QList<QVariant> failedArguments = savePdfSpy.takeFirst(); QVERIFY2(failedArguments.at(0).toString() == path, "File path for second saved PDF does not match arguments"); QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail"); -#endif // !defined(ENABLE_PDF) +#endif // !QT_CONFIG(webengine_printing_and_pdf) } void tst_QQuickWebEngineView::stopSettingFocusWhenDisabled() diff --git a/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro b/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro index 2a2155e44..a0ee3fd89 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro +++ b/tests/auto/quick/qquickwebengineviewgraphics/qquickwebengineviewgraphics.pro @@ -1,4 +1,4 @@ include(../tests.pri) CONFIG -= testcase # remove, once this passes in the CI exists($${TARGET}.qrc):RESOURCES += $${TARGET}.qrc -QT_PRIVATE += webengine-private gui-private +QT_PRIVATE += webengine-private gui-private webenginecore-private diff --git a/tests/auto/quick/quick.pro b/tests/auto/quick/quick.pro index 56c7d02aa..02ce59f17 100644 --- a/tests/auto/quick/quick.pro +++ b/tests/auto/quick/quick.pro @@ -1,8 +1,10 @@ -QT_FOR_CONFIG += webengine-private +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 +QT_FOR_CONFIG += webenginecore-private TEMPLATE = subdirs SUBDIRS += \ + dialogs \ inspectorserver \ publicapi \ qquickwebenginedefaultsurfaceformat \ @@ -15,4 +17,4 @@ qtConfig(webengine-testsupport) { } # QTBUG-66055 -boot2qt: SUBDIRS -= inspectorserver qquickwebenginedefaultsurfaceformat qquickwebengineview qmltests +boot2qt: SUBDIRS -= inspectorserver qquickwebenginedefaultsurfaceformat qquickwebengineview qmltests dialogs diff --git a/tests/auto/quick/shared/util.h b/tests/auto/quick/shared/util.h index bfe3ff9c6..c2e7d3e19 100644 --- a/tests/auto/quick/shared/util.h +++ b/tests/auto/quick/shared/util.h @@ -34,8 +34,8 @@ #include <QSignalSpy> #include <QTimer> #include <QtTest/QtTest> -#include <private/qquickwebengineview_p.h> -#include <private/qquickwebengineloadrequest_p.h> +#include <QtWebEngine/private/qquickwebengineview_p.h> +#include <QtWebEngine/private/qquickwebengineloadrequest_p.h> #if !defined(TESTS_SOURCE_DIR) #define TESTS_SOURCE_DIR "" @@ -108,7 +108,7 @@ inline bool waitForLoadFailed(QQuickWebEngineView *webEngineView, int timeout = inline bool waitForViewportReady(QQuickWebEngineView *webEngineView, int timeout = 10000) { -#ifdef ENABLE_QML_TESTSUPPORT_API +#if QT_CONFIG(webengine_testsupport) QSignalSpy spy(reinterpret_cast<QObject *>(webEngineView->testSupport()), SIGNAL(loadVisuallyCommitted())); return spy.wait(timeout); #else diff --git a/tests/auto/quick/tests.pri b/tests/auto/quick/tests.pri index 7983a248f..f809ebd68 100644 --- a/tests/auto/quick/tests.pri +++ b/tests/auto/quick/tests.pri @@ -1,5 +1,5 @@ -include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) -QT_FOR_CONFIG += webengine-private +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 +QT_FOR_CONFIG += webenginecore-private TEMPLATE = app @@ -18,9 +18,4 @@ QT += testlib network quick webengine # This define is used by some tests to look up resources in the source tree DEFINES += TESTS_SOURCE_DIR=\\\"$$PWD/\\\" - -qtConfig(webengine-testsupport) { - DEFINES += ENABLE_QML_TESTSUPPORT_API -} - include(../embed_info_plist.pri) diff --git a/tests/auto/widgets/qwebengineaccessibility/qwebengineaccessibility.pro b/tests/auto/widgets/accessibility/accessibility.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/qwebengineaccessibility/qwebengineaccessibility.pro +++ b/tests/auto/widgets/accessibility/accessibility.pro diff --git a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp b/tests/auto/widgets/accessibility/tst_accessibility.cpp index c2a15218c..6efbf53ed 100644 --- a/tests/auto/widgets/qwebengineaccessibility/tst_qwebengineaccessibility.cpp +++ b/tests/auto/widgets/accessibility/tst_accessibility.cpp @@ -25,7 +25,7 @@ #include <qwebenginepage.h> #include <qwidget.h> -class tst_QWebEngineAccessibility : public QObject +class tst_Accessibility : public QObject { Q_OBJECT @@ -46,27 +46,27 @@ private Q_SLOTS: // This will be called before the first test function is executed. // It is only called once. -void tst_QWebEngineAccessibility::initTestCase() +void tst_Accessibility::initTestCase() { } // This will be called after the last test function is executed. // It is only called once. -void tst_QWebEngineAccessibility::cleanupTestCase() +void tst_Accessibility::cleanupTestCase() { } // This will be called before each test function is executed. -void tst_QWebEngineAccessibility::init() +void tst_Accessibility::init() { } // This will be called after every test function. -void tst_QWebEngineAccessibility::cleanup() +void tst_Accessibility::cleanup() { } -void tst_QWebEngineAccessibility::noPage() +void tst_Accessibility::noPage() { QWebEngineView webView; webView.show(); @@ -82,7 +82,7 @@ void tst_QWebEngineAccessibility::noPage() QCOMPARE(document->childCount(), 0); } -void tst_QWebEngineAccessibility::hierarchy() +void tst_Accessibility::hierarchy() { QWebEngineView webView; webView.setHtml("<html><body>" \ @@ -142,7 +142,7 @@ void tst_QWebEngineAccessibility::hierarchy() QCOMPARE(input, child); } -void tst_QWebEngineAccessibility::text() +void tst_Accessibility::text() { QWebEngineView webView; webView.setHtml("<html><body>" \ @@ -211,7 +211,7 @@ void tst_QWebEngineAccessibility::text() QCOMPARE(input3->text(QAccessible::Value), QStringLiteral("Good day!")); } -void tst_QWebEngineAccessibility::value() +void tst_Accessibility::value() { QWebEngineView webView; webView.setHtml("<html><body>" \ @@ -250,7 +250,7 @@ void tst_QWebEngineAccessibility::value() QCOMPARE(progressBarValueInterface->maximumValue().toInt(), 99); } -void tst_QWebEngineAccessibility::roles_data() +void tst_Accessibility::roles_data() { QTest::addColumn<QString>("html"); QTest::addColumn<bool>("isSection"); @@ -381,7 +381,7 @@ void tst_QWebEngineAccessibility::roles_data() //QTest::newRow("AX_ROLE_WINDOW"); // No mapping to ARIA role } -void tst_QWebEngineAccessibility::roles() +void tst_Accessibility::roles() { QFETCH(QString, html); QFETCH(bool, isSection); @@ -417,5 +417,5 @@ void tst_QWebEngineAccessibility::roles() static QByteArrayList params = QByteArrayList() << "--force-renderer-accessibility"; -W_QTEST_MAIN(tst_QWebEngineAccessibility, params) -#include "tst_qwebengineaccessibility.moc" +W_QTEST_MAIN(tst_Accessibility, params) +#include "tst_accessibility.moc" diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro b/tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/qwebenginedefaultsurfaceformat/qwebenginedefaultsurfaceformat.pro +++ b/tests/auto/widgets/defaultsurfaceformat/defaultsurfaceformat.pro diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html b/tests/auto/widgets/defaultsurfaceformat/resources/index.html index 53726e4a6..53726e4a6 100644 --- a/tests/auto/widgets/qwebenginedefaultsurfaceformat/resources/index.html +++ b/tests/auto/widgets/defaultsurfaceformat/resources/index.html diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp index 3ac8943a5..697ed3d08 100644 --- a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.cpp +++ b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.cpp @@ -69,4 +69,4 @@ void tst_QWebEngineDefaultSurfaceFormat::customDefaultSurfaceFormat() } QTEST_APPLESS_MAIN(tst_QWebEngineDefaultSurfaceFormat) -#include "tst_qwebenginedefaultsurfaceformat.moc" +#include "tst_defaultsurfaceformat.moc" diff --git a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc index 3d5f1b3b2..3d5f1b3b2 100644 --- a/tests/auto/widgets/qwebenginedefaultsurfaceformat/tst_qwebenginedefaultsurfaceformat.qrc +++ b/tests/auto/widgets/defaultsurfaceformat/tst_defaultsurfaceformat.qrc diff --git a/tests/auto/widgets/qwebenginefaviconmanager/qwebenginefaviconmanager.pro b/tests/auto/widgets/devtools/devtools.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/qwebenginefaviconmanager.pro +++ b/tests/auto/widgets/devtools/devtools.pro diff --git a/tests/auto/widgets/qwebengineinspector/tst_qwebengineinspector.cpp b/tests/auto/widgets/devtools/tst_devtools.cpp index 000214b9a..8f3b90a14 100644 --- a/tests/auto/widgets/qwebengineinspector/tst_qwebengineinspector.cpp +++ b/tests/auto/widgets/devtools/tst_devtools.cpp @@ -28,73 +28,60 @@ #include <QtTest/QtTest> -#include <qdir.h> -#if defined(QWEBENGINEINSPECTOR) -#include <qwebengineinspector.h> -#endif #include <qwebenginepage.h> -#if defined(QWEBENGINESETTINGS) -#include <qwebenginesettings.h> -#endif -class tst_QWebEngineInspector : public QObject { +class tst_DevTools : public QObject { Q_OBJECT private Q_SLOTS: void attachAndDestroyPageFirst(); void attachAndDestroyInspectorFirst(); - void attachAndDestroyInternalInspector(); }; -void tst_QWebEngineInspector::attachAndDestroyPageFirst() +void tst_DevTools::attachAndDestroyPageFirst() { -#if !defined(QWEBENGINEINSPECTOR) - QSKIP("QWEBENGINEINSPECTOR"); -#else // External inspector + manual destruction of page first QWebEnginePage* page = new QWebEnginePage(); - page->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); - QWebEngineInspector* inspector = new QWebEngineInspector(); - inspector->setPage(page); - page->updatePositionDependentActions(QPoint(0, 0)); + QWebEnginePage* inspector = new QWebEnginePage(); + + QSignalSpy spy(page, &QWebEnginePage::loadFinished); + page->load(QUrl("data:text/plain,foobarbaz")); + QTRY_COMPARE(spy.count(), 1); + + inspector->setInspectedPage(page); page->triggerAction(QWebEnginePage::InspectElement); + // This is deliberately racy: + QTest::qWait(10); + delete page; delete inspector; -#endif } -void tst_QWebEngineInspector::attachAndDestroyInspectorFirst() +void tst_DevTools::attachAndDestroyInspectorFirst() { -#if !defined(QWEBENGINEINSPECTOR) - QSKIP("QWEBENGINEINSPECTOR"); -#else // External inspector + manual destruction of inspector first QWebEnginePage* page = new QWebEnginePage(); - page->settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); - QWebEngineInspector* inspector = new QWebEngineInspector(); - inspector->setPage(page); - page->updatePositionDependentActions(QPoint(0, 0)); + QWebEnginePage* inspector = new QWebEnginePage(); + inspector->setInspectedPage(page); + + QSignalSpy spy(page, &QWebEnginePage::loadFinished); + page->setHtml(QStringLiteral("<body><h1>FOO BAR!</h1></body>")); + QTRY_COMPARE(spy.count(), 1); + page->triggerAction(QWebEnginePage::InspectElement); delete inspector; + + page->triggerAction(QWebEnginePage::InspectElement); + + // This is deliberately racy: + QTest::qWait(10); + delete page; -#endif } -void tst_QWebEngineInspector::attachAndDestroyInternalInspector() -{ -#if !defined(QWEBENGINEINSPECTOR) - QSKIP("QWEBENGINEINSPECTOR"); -#else - // Internal inspector - QWebEnginePage page; - page.settings()->setAttribute(QWebEngineSettings::DeveloperExtrasEnabled, true); - page.updatePositionDependentActions(QPoint(0, 0)); - page.triggerAction(QWebEnginePage::InspectElement); -#endif -} -QTEST_MAIN(tst_QWebEngineInspector) +QTEST_MAIN(tst_DevTools) -#include "tst_qwebengineinspector.moc" +#include "tst_devtools.moc" diff --git a/tests/auto/widgets/qwebengineinspector/qwebengineinspector.pro b/tests/auto/widgets/faviconmanager/faviconmanager.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/qwebengineinspector/qwebengineinspector.pro +++ b/tests/auto/widgets/faviconmanager/faviconmanager.pro diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-misc.html b/tests/auto/widgets/faviconmanager/resources/favicon-misc.html index 9e788bdf4..9e788bdf4 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-misc.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-misc.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-multi.html b/tests/auto/widgets/faviconmanager/resources/favicon-multi.html index cc5f3fd66..cc5f3fd66 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-multi.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-multi.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-shortcut.html b/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html index 786cdb816..786cdb816 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-shortcut.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-shortcut.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-single.html b/tests/auto/widgets/faviconmanager/resources/favicon-single.html index eb4675c75..eb4675c75 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-single.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-single.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-touch.html b/tests/auto/widgets/faviconmanager/resources/favicon-touch.html index 271783434..271783434 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-touch.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-touch.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-unavailable.html b/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html index c45664294..c45664294 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/favicon-unavailable.html +++ b/tests/auto/widgets/faviconmanager/resources/favicon-unavailable.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qt144.png b/tests/auto/widgets/faviconmanager/resources/icons/qt144.png Binary files differindex 050b1e066..050b1e066 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qt144.png +++ b/tests/auto/widgets/faviconmanager/resources/icons/qt144.png diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qt32.ico b/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico Binary files differindex 2f6fcb5bc..2f6fcb5bc 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qt32.ico +++ b/tests/auto/widgets/faviconmanager/resources/icons/qt32.ico diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qtmulti.ico b/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico Binary files differindex 81e5a22e8..81e5a22e8 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/icons/qtmulti.ico +++ b/tests/auto/widgets/faviconmanager/resources/icons/qtmulti.ico diff --git a/tests/auto/widgets/qwebenginefaviconmanager/resources/test1.html b/tests/auto/widgets/faviconmanager/resources/test1.html index b323f966e..b323f966e 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/resources/test1.html +++ b/tests/auto/widgets/faviconmanager/resources/test1.html diff --git a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp index e9dc0f205..606d05d9e 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.cpp +++ b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp @@ -35,7 +35,7 @@ #include <qwebengineview.h> -class tst_QWebEngineFaviconManager : public QObject { +class tst_FaviconManager : public QObject { Q_OBJECT public Q_SLOTS: @@ -70,7 +70,7 @@ private: }; -void tst_QWebEngineFaviconManager::init() +void tst_FaviconManager::init() { m_profile = new QWebEngineProfile(this); m_view = new QWebEngineView(); @@ -79,22 +79,22 @@ void tst_QWebEngineFaviconManager::init() } -void tst_QWebEngineFaviconManager::initTestCase() +void tst_FaviconManager::initTestCase() { } -void tst_QWebEngineFaviconManager::cleanupTestCase() +void tst_FaviconManager::cleanupTestCase() { } -void tst_QWebEngineFaviconManager::cleanup() +void tst_FaviconManager::cleanup() { delete m_view; delete m_profile; } -void tst_QWebEngineFaviconManager::faviconLoad() +void tst_FaviconManager::faviconLoad() { 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); @@ -103,7 +103,7 @@ void tst_QWebEngineFaviconManager::faviconLoad() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-single.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-single.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -112,7 +112,7 @@ void tst_QWebEngineFaviconManager::faviconLoad() QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(iconUrl, m_page->iconUrl()); - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt32.ico"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico"))); const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -122,7 +122,7 @@ void tst_QWebEngineFaviconManager::faviconLoad() QCOMPARE(iconSize, QSize(32, 32)); } -void tst_QWebEngineFaviconManager::faviconLoadFromResources() +void tst_FaviconManager::faviconLoadFromResources() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); @@ -147,7 +147,7 @@ void tst_QWebEngineFaviconManager::faviconLoadFromResources() QCOMPARE(iconSize, QSize(32, 32)); } -void tst_QWebEngineFaviconManager::faviconLoadEncodedUrl() +void tst_FaviconManager::faviconLoadEncodedUrl() { 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); @@ -156,7 +156,7 @@ void tst_QWebEngineFaviconManager::faviconLoadEncodedUrl() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QString urlString = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-single.html")).toString(); + QString urlString = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-single.html")).toString(); QUrl url(urlString + QLatin1String("?favicon=load should work with#whitespace!")); m_page->load(url); @@ -166,7 +166,7 @@ void tst_QWebEngineFaviconManager::faviconLoadEncodedUrl() QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(m_page->iconUrl(), iconUrl); - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt32.ico"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico"))); const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -176,7 +176,7 @@ void tst_QWebEngineFaviconManager::faviconLoadEncodedUrl() QCOMPARE(iconSize, QSize(32, 32)); } -void tst_QWebEngineFaviconManager::noFavicon() +void tst_FaviconManager::noFavicon() { 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); @@ -185,7 +185,7 @@ void tst_QWebEngineFaviconManager::noFavicon() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/test1.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/test1.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -196,7 +196,7 @@ void tst_QWebEngineFaviconManager::noFavicon() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::aboutBlank() +void tst_FaviconManager::aboutBlank() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); @@ -213,7 +213,7 @@ void tst_QWebEngineFaviconManager::aboutBlank() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::unavailableFavicon() +void tst_FaviconManager::unavailableFavicon() { 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); @@ -222,7 +222,7 @@ void tst_QWebEngineFaviconManager::unavailableFavicon() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-unavailable.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-unavailable.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -233,7 +233,7 @@ void tst_QWebEngineFaviconManager::unavailableFavicon() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::errorPageEnabled() +void tst_FaviconManager::errorPageEnabled() { m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); @@ -244,7 +244,7 @@ void tst_QWebEngineFaviconManager::errorPageEnabled() QUrl url("http://url.invalid"); m_page->load(url); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 14000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 20000); QCOMPARE(iconUrlChangedSpy.count(), 0); QCOMPARE(iconChangedSpy.count(), 0); @@ -252,7 +252,7 @@ void tst_QWebEngineFaviconManager::errorPageEnabled() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::errorPageDisabled() +void tst_FaviconManager::errorPageDisabled() { m_page->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); @@ -271,7 +271,7 @@ void tst_QWebEngineFaviconManager::errorPageDisabled() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::bestFavicon() +void tst_FaviconManager::bestFavicon() { 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); @@ -284,7 +284,7 @@ void tst_QWebEngineFaviconManager::bestFavicon() QIcon icon; QSize iconSize; - url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-misc.html")); + url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-misc.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -294,7 +294,7 @@ void tst_QWebEngineFaviconManager::bestFavicon() iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(iconUrl, m_page->iconUrl()); // Touch icon is ignored - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt32.ico"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt32.ico"))); icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -307,7 +307,7 @@ void tst_QWebEngineFaviconManager::bestFavicon() iconUrlChangedSpy.clear(); iconChangedSpy.clear(); - url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-shortcut.html")); + url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-shortcut.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -325,7 +325,7 @@ void tst_QWebEngineFaviconManager::bestFavicon() } QCOMPARE(iconUrl, m_page->iconUrl()); - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt144.png"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt144.png"))); icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -334,7 +334,7 @@ void tst_QWebEngineFaviconManager::bestFavicon() QVERIFY(icon.availableSizes().contains(QSize(144, 144))); } -void tst_QWebEngineFaviconManager::touchIcon() +void tst_FaviconManager::touchIcon() { 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); @@ -343,7 +343,7 @@ void tst_QWebEngineFaviconManager::touchIcon() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-touch.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-touch.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -354,7 +354,7 @@ void tst_QWebEngineFaviconManager::touchIcon() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::multiIcon() +void tst_FaviconManager::multiIcon() { 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); @@ -363,7 +363,7 @@ void tst_QWebEngineFaviconManager::multiIcon() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-multi.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-multi.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -372,7 +372,7 @@ void tst_QWebEngineFaviconManager::multiIcon() QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(m_page->iconUrl(), iconUrl); - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qtmulti.ico"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qtmulti.ico"))); const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -382,7 +382,7 @@ void tst_QWebEngineFaviconManager::multiIcon() QVERIFY(icon.availableSizes().contains(QSize(64, 64))); } -void tst_QWebEngineFaviconManager::candidateIcon() +void tst_FaviconManager::candidateIcon() { 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); @@ -391,7 +391,7 @@ void tst_QWebEngineFaviconManager::candidateIcon() QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); QSignalSpy iconChangedSpy(m_page, SIGNAL(iconChanged(QIcon))); - QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/favicon-shortcut.html")); + QUrl url = QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/favicon-shortcut.html")); m_page->load(url); QTRY_COMPARE(loadFinishedSpy.count(), 1); @@ -400,7 +400,7 @@ void tst_QWebEngineFaviconManager::candidateIcon() QUrl iconUrl = iconUrlChangedSpy.at(0).at(0).toString(); QCOMPARE(m_page->iconUrl(), iconUrl); - QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("qwebenginefaviconmanager/resources/icons/qt144.png"))); + QCOMPARE(iconUrl, QUrl::fromLocalFile(TESTS_SOURCE_DIR + QLatin1String("faviconmanager/resources/icons/qt144.png"))); const QIcon &icon = m_page->icon(); QVERIFY(!icon.isNull()); @@ -409,7 +409,7 @@ void tst_QWebEngineFaviconManager::candidateIcon() QVERIFY(icon.availableSizes().contains(QSize(144, 144))); } -void tst_QWebEngineFaviconManager::downloadIconsDisabled_data() +void tst_FaviconManager::downloadIconsDisabled_data() { QTest::addColumn<QUrl>("url"); QTest::newRow("misc") << QUrl("qrc:/resources/favicon-misc.html"); @@ -419,7 +419,7 @@ void tst_QWebEngineFaviconManager::downloadIconsDisabled_data() QTest::newRow("unavailable") << QUrl("qrc:/resources/favicon-unavailable.html"); } -void tst_QWebEngineFaviconManager::downloadIconsDisabled() +void tst_FaviconManager::downloadIconsDisabled() { QFETCH(QUrl, url); @@ -439,7 +439,7 @@ void tst_QWebEngineFaviconManager::downloadIconsDisabled() QVERIFY(m_page->icon().isNull()); } -void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled_data() +void tst_FaviconManager::downloadTouchIconsEnabled_data() { QTest::addColumn<QUrl>("url"); QTest::addColumn<QUrl>("expectedIconUrl"); @@ -450,7 +450,7 @@ void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled_data() QTest::newRow("touch") << QUrl("qrc:/resources/favicon-touch.html") << QUrl("qrc:/resources/icons/qt144.png") << QSize(144, 144); } -void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled() +void tst_FaviconManager::downloadTouchIconsEnabled() { QFETCH(QUrl, url); QFETCH(QUrl, expectedIconUrl); @@ -479,7 +479,7 @@ void tst_QWebEngineFaviconManager::downloadTouchIconsEnabled() QVERIFY(icon.availableSizes().contains(expectedIconSize)); } -void tst_QWebEngineFaviconManager::dynamicFavicon() +void tst_FaviconManager::dynamicFavicon() { QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); QSignalSpy iconUrlChangedSpy(m_page, SIGNAL(iconUrlChanged(QUrl))); @@ -508,6 +508,6 @@ void tst_QWebEngineFaviconManager::dynamicFavicon() } } -QTEST_MAIN(tst_QWebEngineFaviconManager) +QTEST_MAIN(tst_FaviconManager) -#include "tst_qwebenginefaviconmanager.moc" +#include "tst_faviconmanager.moc" diff --git a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.qrc b/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc index a352f8a83..a352f8a83 100644 --- a/tests/auto/widgets/qwebenginefaviconmanager/tst_qwebenginefaviconmanager.qrc +++ b/tests/auto/widgets/faviconmanager/tst_faviconmanager.qrc diff --git a/tests/auto/widgets/loadsignals/BLACKLIST b/tests/auto/widgets/loadsignals/BLACKLIST new file mode 100644 index 000000000..570666a83 --- /dev/null +++ b/tests/auto/widgets/loadsignals/BLACKLIST @@ -0,0 +1,14 @@ +[secondLoadForError_WhenErrorPageEnabled:ErrorPageEnabled] +* + +# QTBUG-65223 +[loadStartedAndFinishedCount:WithAnchorClickedFromJS] +* + +# QTBUG-66869 (https://codereview.qt-project.org/#/c/222112/ is only a workaround) +[loadAfterInPageNavigation_qtbug66869] +* + +# QTBUG-66661 +[fileDownloadDoesNotTriggerLoadSignals_qtbug66661] +* diff --git a/tests/auto/widgets/qwebengineshutdown/qwebengineshutdown.pro b/tests/auto/widgets/loadsignals/loadsignals.pro index e99c7f493..e99c7f493 100644 --- a/tests/auto/widgets/qwebengineshutdown/qwebengineshutdown.pro +++ b/tests/auto/widgets/loadsignals/loadsignals.pro diff --git a/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz b/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz Binary files differnew file mode 100644 index 000000000..741cb8ca6 --- /dev/null +++ b/tests/auto/widgets/loadsignals/resources/downloadable.tar.gz diff --git a/tests/auto/widgets/loadsignals/resources/page1.html b/tests/auto/widgets/loadsignals/resources/page1.html new file mode 100644 index 000000000..5cd479ab6 --- /dev/null +++ b/tests/auto/widgets/loadsignals/resources/page1.html @@ -0,0 +1,8 @@ +<html> + <head> + <title>page1</title> + </head> + <body> + <h1>page1</h1> + </body> +</html> diff --git a/tests/auto/widgets/loadsignals/resources/page2.html b/tests/auto/widgets/loadsignals/resources/page2.html new file mode 100644 index 000000000..e3031f56a --- /dev/null +++ b/tests/auto/widgets/loadsignals/resources/page2.html @@ -0,0 +1,14 @@ +<html> + <head> + <title>page2</title> + </head> + <style> + .fardown { + position: absolute; + top: 2500px; + } + </style> + <body> + <div class="fardown" id="anchor">page2 anchor</div> + </body> +</html> diff --git a/tests/auto/widgets/loadsignals/resources/page3.html b/tests/auto/widgets/loadsignals/resources/page3.html new file mode 100644 index 000000000..d38ca31f0 --- /dev/null +++ b/tests/auto/widgets/loadsignals/resources/page3.html @@ -0,0 +1,20 @@ +<html> + <head> + <title>page3</title> + </head> + <script> + setTimeout(function(){ + document.getElementById('anchorLink').click(); + },500); + </script> + <style> + .fardown { + position: absolute; + top: 2500px; + } + </style> + <body> + <div><a id="anchorLink" href="#anchor">page3</a></div> + <div class="fardown" id="anchor">page3 anchor</div> + </body> +</html> diff --git a/tests/auto/widgets/loadsignals/resources/page4.html b/tests/auto/widgets/loadsignals/resources/page4.html new file mode 100644 index 000000000..61976b4fb --- /dev/null +++ b/tests/auto/widgets/loadsignals/resources/page4.html @@ -0,0 +1,8 @@ +<html> + <head> + <title>page4</title> + </head> + <body onload="document.getElementById('downloadLink').focus();"> + <a id="downloadLink" href="downloadable.tar.gz">download</a> + </body> +</html> diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp new file mode 100644 index 000000000..e614f3751 --- /dev/null +++ b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp @@ -0,0 +1,264 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QtTest> + +#include "../util.h" +#include "qdebug.h" +#include "qwebenginepage.h" +#include "qwebengineprofile.h" +#include "qwebenginesettings.h" +#include "qwebengineview.h" + +class tst_LoadSignals : public QObject +{ + Q_OBJECT + +public: + tst_LoadSignals(); + virtual ~tst_LoadSignals(); + +public Q_SLOTS: + void initTestCase(); + void init(); + void cleanup(); + +private Q_SLOTS: + void monotonicity(); + void loadStartedAndFinishedCount_data(); + void loadStartedAndFinishedCount(); + void secondLoadForError_WhenErrorPageEnabled_data(); + void secondLoadForError_WhenErrorPageEnabled(); + void loadAfterInPageNavigation_qtbug66869(); + void fileDownloadDoesNotTriggerLoadSignals_qtbug66661(); + +private: + QWebEngineView* view; + QScopedPointer<QSignalSpy> loadStartedSpy; + QScopedPointer<QSignalSpy> loadProgressSpy; + QScopedPointer<QSignalSpy> loadFinishedSpy; +}; + +tst_LoadSignals::tst_LoadSignals() +{ +} + +tst_LoadSignals::~tst_LoadSignals() +{ +} + +void tst_LoadSignals::initTestCase() +{ +} + +void tst_LoadSignals::init() +{ + view = new QWebEngineView(); + view->resize(1024,768); + view->show(); + loadStartedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadStarted)); + loadProgressSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadProgress)); + loadFinishedSpy.reset(new QSignalSpy(view->page(), &QWebEnginePage::loadFinished)); +} + +void tst_LoadSignals::cleanup() +{ + loadFinishedSpy.reset(); + loadProgressSpy.reset(); + loadStartedSpy.reset(); + delete view; +} + +/** + * Test that we get the expected number of loadStarted and loadFinished signals + */ +void tst_LoadSignals::loadStartedAndFinishedCount_data() +{ + QTest::addColumn<QUrl>("url"); + QTest::addColumn<int>("expectedLoadCount"); + QTest::newRow("Normal") << QUrl("qrc:///resources/page1.html") << 1; + QTest::newRow("WithAnchor") << QUrl("qrc:///resources/page2.html#anchor") << 1; + + // In this case, we get an unexpected additional loadStarted, but no corresponding + // loadFinished, so expectedLoadCount=2 would also not work. See also QTBUG-65223 + QTest::newRow("WithAnchorClickedFromJS") << QUrl("qrc:///resources/page3.html") << 1; +} + +void tst_LoadSignals::loadStartedAndFinishedCount() +{ + QFETCH(QUrl, url); + QFETCH(int, expectedLoadCount); + + view->load(url); + QTRY_COMPARE(loadFinishedSpy->size(), expectedLoadCount); + bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(loadSucceeded); + + // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs) + QTRY_LOOP_IMPL((loadStartedSpy->size() != expectedLoadCount) + || (loadFinishedSpy->size() != expectedLoadCount), 10000, 100); + + // No further loadStarted should have occurred within this time + QCOMPARE(loadStartedSpy->size(), expectedLoadCount); + QCOMPARE(loadFinishedSpy->size(), expectedLoadCount); +} + +/** + * Test monotonicity of loadProgress signals + */ +void tst_LoadSignals::monotonicity() +{ + view->load(QUrl("qrc:///resources/page1.html")); + QTRY_COMPARE(loadFinishedSpy->size(), 1); + bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(loadSucceeded); + + // first loadProgress should have 0% progress + QCOMPARE(loadProgressSpy->first()[0].toInt(), 0); + + // every loadProgress should have at least as much progress as the one before + int progress = 0; + for (auto item : *loadProgressSpy) { + QVERIFY(item[0].toInt() >= progress); + progress = item[0].toInt(); + } + + // last loadProgress should have 100% progress + QCOMPARE(loadProgressSpy->last()[0].toInt(), 100); +} + +/** + * Test that we get a second loadStarted and loadFinished signal + * for error-pages (unless error-pages are disabled) + */ +void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled_data() +{ + QTest::addColumn<bool>("enabled"); + // in this case, we get no second loadStarted and loadFinished, although we had + // agreed on making the navigation to an error page an individual load + QTest::newRow("ErrorPageEnabled") << true; + QTest::newRow("ErrorPageDisabled") << false; +} + +void tst_LoadSignals::secondLoadForError_WhenErrorPageEnabled() +{ + QFETCH(bool, enabled); + view->settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, enabled); + int expectedLoadCount = (enabled ? 2 : 1); + + // RFC 2606 guarantees that this will never become a valid domain + view->load(QUrl("http://nonexistent.invalid")); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy->size(), expectedLoadCount, 10000); + bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(!loadSucceeded); + if (enabled) { + bool errorPageLoadSucceeded = (*loadFinishedSpy)[1][0].toBool(); + QVERIFY(errorPageLoadSucceeded); + } + + // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs) + QTRY_LOOP_IMPL((loadStartedSpy->size() != expectedLoadCount) + || (loadFinishedSpy->size() != expectedLoadCount), 10000, 100); + + // No further loadStarted should have occurred within this time + QCOMPARE(loadStartedSpy->size(), expectedLoadCount); + QCOMPARE(loadFinishedSpy->size(), expectedLoadCount); +} + +/** + * Test that a second load after an in-page navigation receives its expected loadStarted and + * loadFinished signal. + */ +void tst_LoadSignals::loadAfterInPageNavigation_qtbug66869() +{ + view->load(QUrl("qrc:///resources/page3.html")); + QTRY_COMPARE(loadFinishedSpy->size(), 1); + bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(loadSucceeded); + + // page3 does an in-page navigation after 500ms + QTest::qWait(2000); + loadFinishedSpy->clear(); + loadProgressSpy->clear(); + loadStartedSpy->clear(); + + // second load + view->load(QUrl("qrc:///resources/page1.html")); + QTRY_COMPARE(loadFinishedSpy->size(), 1); + loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(loadSucceeded); + // loadStarted and loadFinished should have been signalled + QCOMPARE(loadStartedSpy->size(), 1); + + // reminder that we still need to solve the core issue + QFAIL("https://codereview.qt-project.org/#/c/222112/ only hides the symptom, the core issue still needs to be solved"); +} + +/** + * Test that file-downloads don't trigger loadStarted or loadFinished signals. + * See QTBUG-66661 + */ +void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661() +{ + view->load(QUrl("qrc:///resources/page4.html")); + QTRY_COMPARE(loadFinishedSpy->size(), 1); + bool loadSucceeded = (*loadFinishedSpy)[0][0].toBool(); + QVERIFY(loadSucceeded); + + // allow the download + QTemporaryDir tempDir; + QWebEngineDownloadItem::DownloadState downloadState = QWebEngineDownloadItem::DownloadRequested; + connect(view->page()->profile(), &QWebEngineProfile::downloadRequested, + [this, &downloadState, &tempDir](QWebEngineDownloadItem* item){ + connect(item, &QWebEngineDownloadItem::stateChanged, [&downloadState](QWebEngineDownloadItem::DownloadState newState){ + downloadState = newState; + }); + item->setPath(tempDir.filePath(QFileInfo(item->path()).fileName())); + item->accept(); + }); + + // trigger the download link that becomes focused on page4 + QTest::qWait(1000); + QTest::sendKeyEvent(QTest::Press, view->focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, view->focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + + // Wait for 10 seconds (abort waiting if another loadStarted or loadFinished occurs) + QTRY_LOOP_IMPL((loadStartedSpy->size() != 1) + || (loadFinishedSpy->size() != 1), 10000, 100); + + // Download must have occurred + QTRY_COMPARE(downloadState, QWebEngineDownloadItem::DownloadCompleted); + + // No further loadStarted should have occurred within this time + QCOMPARE(loadStartedSpy->size(), 1); + QCOMPARE(loadFinishedSpy->size(), 1); +} + + +QTEST_MAIN(tst_LoadSignals) +#include "tst_loadsignals.moc" diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.qrc b/tests/auto/widgets/loadsignals/tst_loadsignals.qrc new file mode 100644 index 000000000..316deecb8 --- /dev/null +++ b/tests/auto/widgets/loadsignals/tst_loadsignals.qrc @@ -0,0 +1,9 @@ +<RCC> + <qresource prefix="/"> + <file>resources/page1.html</file> + <file>resources/page2.html</file> + <file>resources/page3.html</file> + <file>resources/page4.html</file> + <file>resources/downloadable.tar.gz</file> + </qresource> +</RCC> diff --git a/tests/auto/widgets/origins/origins.pro b/tests/auto/widgets/origins/origins.pro index 566666e0a..7498354de 100644 --- a/tests/auto/widgets/origins/origins.pro +++ b/tests/auto/widgets/origins/origins.pro @@ -1,2 +1,7 @@ include(../tests.pri) CONFIG += c++14 +qtConfig(webengine-webchannel):qtHaveModule(websockets) { + QT += websockets + DEFINES += WEBSOCKETS +} + diff --git a/tests/auto/widgets/origins/resources/mixedSchemes.html b/tests/auto/widgets/origins/resources/mixedSchemes.html new file mode 100644 index 000000000..c73e9ecdc --- /dev/null +++ b/tests/auto/widgets/origins/resources/mixedSchemes.html @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html> + <head> + <title>Mixed</title> + <script> + var result; + var canary; + + function setIFrameUrl(url) { + result = undefined; + canary = undefined; + document.getElementById("iframe").setAttribute("src", url); + // Early fire is OK unless the test is expecting cannotLoad. + // If timeout is too short then a false positive is possible. + setTimeout(() => { result = result || "cannotLoad"; }, 500); + } + + addEventListener("load", function() { + document.getElementById("iframe").addEventListener("load", function() { + if (canary && window[0].canary) + result = "canLoadAndAccess"; + else + result = "canLoadButNotAccess"; + }); + }); + </script> + </head> + <body> + <iframe id="iframe"></iframe> + </body> +</html> diff --git a/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html b/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html new file mode 100644 index 000000000..ad7cbeeb7 --- /dev/null +++ b/tests/auto/widgets/origins/resources/mixedSchemesWithCsp.html @@ -0,0 +1,32 @@ +<!DOCTYPE html> +<html> + <head> + <meta http-equiv="Content-Security-Policy" content="frame-src 'none'"> + <title>Mixed</title> + <script> + var result; + var canary; + + function setIFrameUrl(url) { + result = undefined; + canary = undefined; + document.getElementById("iframe").setAttribute("src", url); + // Early fire is OK unless the test is expecting cannotLoad. + // If timeout is too short then a false positive is possible. + setTimeout(() => { result = result || "cannotLoad"; }, 500); + } + + addEventListener("load", function() { + document.getElementById("iframe").addEventListener("load", function() { + if (canary && window[0].canary) + result = "canLoadAndAccess"; + else + result = "canLoadButNotAccess"; + }); + }); + </script> + </head> + <body> + <iframe id="iframe"></iframe> + </body> +</html> diff --git a/tests/auto/widgets/origins/resources/mixed_frame.html b/tests/auto/widgets/origins/resources/mixedSchemes_frame.html index 53d341b93..00c20ba37 100644 --- a/tests/auto/widgets/origins/resources/mixed_frame.html +++ b/tests/auto/widgets/origins/resources/mixedSchemes_frame.html @@ -3,7 +3,8 @@ <head> <title>Mixed - Frame</title> <script> - parent.msg = "mixed"; + var canary = true; + parent.canary = true; </script> </head> <body></body> diff --git a/tests/auto/widgets/origins/resources/mixed_qrc.html b/tests/auto/widgets/origins/resources/mixed_qrc.html deleted file mode 100644 index 664f7af6f..000000000 --- a/tests/auto/widgets/origins/resources/mixed_qrc.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Mixed</title> - <script> - var msg; - </script> - </head> - <body> - <iframe src="qrc:///resources/mixed_frame.html"></iframe> - </body> -</html> diff --git a/tests/auto/widgets/origins/resources/mixed_tst.html b/tests/auto/widgets/origins/resources/mixed_tst.html deleted file mode 100644 index 627e58098..000000000 --- a/tests/auto/widgets/origins/resources/mixed_tst.html +++ /dev/null @@ -1,12 +0,0 @@ -<!DOCTYPE html> -<html> - <head> - <title>Mixed</title> - <script> - var msg; - </script> - </head> - <body> - <iframe src="tst:///resources/mixed_frame.html"></iframe> - </body> -</html> diff --git a/tests/auto/widgets/origins/resources/serviceWorker.html b/tests/auto/widgets/origins/resources/serviceWorker.html index b2bdc8c60..27890c98f 100644 --- a/tests/auto/widgets/origins/resources/serviceWorker.html +++ b/tests/auto/widgets/origins/resources/serviceWorker.html @@ -5,9 +5,13 @@ <script> var done = false; var error; - navigator.serviceWorker.register("serviceWorker.js") - .then((r) => { done = true; }) - .catch((e) => { done = true; error = e.message; }); + try { + navigator.serviceWorker.register("serviceWorker.js") + .then((r) => { done = true; }) + .catch((e) => { done = true; error = e.message; }); + } catch (e) { + done = true; error = e.message; + } </script> </head> <body></body> diff --git a/tests/auto/widgets/origins/resources/viewSource.html b/tests/auto/widgets/origins/resources/viewSource.html new file mode 100644 index 000000000..977074c74 --- /dev/null +++ b/tests/auto/widgets/origins/resources/viewSource.html @@ -0,0 +1,9 @@ +<!DOCTYPE html> +<html> + <head> + <title>viewSource</title> + </head> + <body> + <p>viewSource</p> + </body> +</html> diff --git a/tests/auto/widgets/origins/resources/websocket.html b/tests/auto/widgets/origins/resources/websocket.html index 949596d1c..31db66571 100644 --- a/tests/auto/widgets/origins/resources/websocket.html +++ b/tests/auto/widgets/origins/resources/websocket.html @@ -2,10 +2,21 @@ <html> <head> <title>WebSocket</title> + <script src="qrc:/qtwebchannel/qwebchannel.js"></script> <script> - var err; - const ws = new WebSocket("ws://example.invalid"); - ws.addEventListener("close", () => err = event.code); + var result; + new QWebChannel(qt.webChannelTransport, channel => { + const ws = new WebSocket(channel.objects.echoServer.url); + ws.addEventListener("open", event => { + ws.send("ok"); + }); + ws.addEventListener("message", event => { + result = event.data; + }); + ws.addEventListener("close", event => { + result = event.code; + }); + }) </script> </head> <body></body> diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp index 61d54e6de..364c83c3e 100644 --- a/tests/auto/widgets/origins/tst_origins.cpp +++ b/tests/auto/widgets/origins/tst_origins.cpp @@ -31,15 +31,100 @@ #include <QtCore/qfile.h> #include <QtTest/QtTest> #include <QtWebEngineCore/qwebengineurlrequestjob.h> +#include <QtWebEngineCore/qwebengineurlscheme.h> #include <QtWebEngineCore/qwebengineurlschemehandler.h> #include <QtWebEngineWidgets/qwebenginepage.h> #include <QtWebEngineWidgets/qwebengineprofile.h> #include <QtWebEngineWidgets/qwebenginesettings.h> +#if defined(WEBSOCKETS) +#include <QtWebSockets/qwebsocket.h> +#include <QtWebSockets/qwebsocketserver.h> +#include <QtWebChannel/qwebchannel.h> +#endif +#include <QtWidgets/qaction.h> #define QSL QStringLiteral #define QBAL QByteArrayLiteral #define THIS_DIR TESTS_SOURCE_DIR "origins/" +void registerSchemes() +{ + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax")); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure")); + scheme.setFlags(QWebEngineUrlScheme::Secure); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Secure-ServiceWorkersAllowed")); + scheme.setFlags(QWebEngineUrlScheme::Secure | QWebEngineUrlScheme::ServiceWorkersAllowed); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-Local")); + scheme.setFlags(QWebEngineUrlScheme::Local); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-LocalAccessAllowed")); + scheme.setFlags(QWebEngineUrlScheme::LocalAccessAllowed); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-NoAccessAllowed")); + scheme.setFlags(QWebEngineUrlScheme::NoAccessAllowed); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-ServiceWorkersAllowed")); + scheme.setFlags(QWebEngineUrlScheme::ServiceWorkersAllowed); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("PathSyntax-ViewSourceAllowed")); + scheme.setFlags(QWebEngineUrlScheme::ViewSourceAllowed); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::HostSyntax); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostSyntax-ContentSecurityPolicyIgnored")); + scheme.setSyntax(QWebEngineUrlScheme::HostSyntax); + scheme.setFlags(QWebEngineUrlScheme::ContentSecurityPolicyIgnored); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostAndPortSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::HostAndPortSyntax); + scheme.setDefaultPort(42); + QWebEngineUrlScheme::addScheme(scheme); + } + + { + QWebEngineUrlScheme scheme(QBAL("HostPortAndUserInformationSyntax")); + scheme.setSyntax(QWebEngineUrlScheme::HostPortAndUserInformationSyntax); + scheme.setDefaultPort(42); + QWebEngineUrlScheme::addScheme(scheme); + } +} +Q_CONSTRUCTOR_FUNCTION(registerSchemes) + class TstUrlSchemeHandler final : public QWebEngineUrlSchemeHandler { Q_OBJECT @@ -47,6 +132,19 @@ public: TstUrlSchemeHandler(QWebEngineProfile *profile) { profile->installUrlSchemeHandler(QBAL("tst"), this); + + profile->installUrlSchemeHandler(QBAL("PathSyntax"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Secure-ServiceWorkersAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-Local"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-LocalAccessAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-NoAccessAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-ServiceWorkersAllowed"), this); + profile->installUrlSchemeHandler(QBAL("PathSyntax-ViewSourceAllowed"), this); + profile->installUrlSchemeHandler(QBAL("HostSyntax"), this); + profile->installUrlSchemeHandler(QBAL("HostSyntax-ContentSecurityPolicyIgnored"), this); + profile->installUrlSchemeHandler(QBAL("HostAndPortSyntax"), this); + profile->installUrlSchemeHandler(QBAL("HostPortAndUserInformationSyntax"), this); } private: @@ -59,7 +157,10 @@ private: job->fail(QWebEngineUrlRequestJob::RequestFailed); return; } - job->reply(QBAL("text/html"), file); + QByteArray mimeType = QBAL("text/html"); + if (pathSuffix.endsWith(QSL(".js"))) + mimeType = QBAL("application/javascript"); + job->reply(mimeType, file); } }; @@ -67,35 +168,54 @@ class tst_Origins final : public QObject { Q_OBJECT private Q_SLOTS: + void initTestCase(); + void cleanupTestCase(); + void jsUrlCanon(); void jsUrlOrigin(); void subdirWithAccess(); void subdirWithoutAccess(); void mixedSchemes(); + void mixedSchemesWithCsp(); +#if defined(WEBSOCKETS) void webSocket(); +#endif void dedicatedWorker(); void sharedWorker(); void serviceWorker(); + void viewSource(); private: bool load(const QUrl &url) { - QSignalSpy spy(&m_page, &QWebEnginePage::loadFinished); - m_page.load(url); - return (!spy.empty() || spy.wait()) + QSignalSpy spy(m_page, &QWebEnginePage::loadFinished); + m_page->load(url); + return (!spy.empty() || spy.wait(20000)) && spy.front().value(0).toBool(); } QVariant eval(const QString &code) { - return evaluateJavaScriptSync(&m_page, code); + return evaluateJavaScriptSync(m_page, code); } QWebEngineProfile m_profile; - QWebEnginePage m_page{&m_profile}; - TstUrlSchemeHandler m_handler{&m_profile}; + QWebEnginePage *m_page = nullptr; + TstUrlSchemeHandler *m_handler = nullptr; }; +void tst_Origins::initTestCase() +{ + m_page = new QWebEnginePage(&m_profile, nullptr); + m_handler = new TstUrlSchemeHandler(&m_profile); +} + +void tst_Origins::cleanupTestCase() +{ + delete m_handler; + delete m_page; +} + // Test URL parsing and canonicalization in Blink. The implementation of this // part is mostly shared between Blink and Chromium proper. void tst_Origins::jsUrlCanon() @@ -121,17 +241,42 @@ void tst_Origins::jsUrlCanon() QCOMPARE(eval(QSL("new URL(\"file:///foo/bar\").href")), QVariant(QSL("file:///foo/bar"))); #endif - // The qrc scheme is a 'dumb' URL, having only a path and nothing else. + // The qrc scheme is a PathSyntax scheme, having only a path and nothing else. QCOMPARE(eval(QSL("new URL(\"qrc:foo/bar\").href")), QVariant(QSL("qrc:foo/bar"))); QCOMPARE(eval(QSL("new URL(\"qrc:/foo/bar\").href")), QVariant(QSL("qrc:/foo/bar"))); QCOMPARE(eval(QSL("new URL(\"qrc://foo/bar\").href")), QVariant(QSL("qrc://foo/bar"))); QCOMPARE(eval(QSL("new URL(\"qrc:///foo/bar\").href")), QVariant(QSL("qrc:///foo/bar"))); - // Same for custom schemes. + // Same for unregistered schemes. QCOMPARE(eval(QSL("new URL(\"tst:foo/bar\").href")), QVariant(QSL("tst:foo/bar"))); QCOMPARE(eval(QSL("new URL(\"tst:/foo/bar\").href")), QVariant(QSL("tst:/foo/bar"))); QCOMPARE(eval(QSL("new URL(\"tst://foo/bar\").href")), QVariant(QSL("tst://foo/bar"))); QCOMPARE(eval(QSL("new URL(\"tst:///foo/bar\").href")), QVariant(QSL("tst:///foo/bar"))); + + // A HostSyntax scheme is like http without the port & user information. + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:42/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostSyntax:a:b@foo/bar\").href")), QVariant(QSL("hostsyntax://foo/bar"))); + + // A HostAndPortSyntax scheme is like http without the user information. + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").href")), + QVariant(QSL("hostandportsyntax://foo:41/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:a:b@foo/bar\").href")), + QVariant(QSL("hostandportsyntax://foo/bar"))); + + // A HostPortAndUserInformationSyntax scheme is exactly like http. + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo:41/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://foo/bar"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:a:b@foo/bar\").href")), + QVariant(QSL("hostportanduserinformationsyntax://a:b@foo/bar"))); } // Test origin serialization in Blink, implemented by blink::KURL and @@ -154,9 +299,29 @@ void tst_Origins::jsUrlOrigin() QCOMPARE(eval(QSL("new URL(\"qrc:/crysis.css\").origin")), QVariant(QSL("qrc://"))); QCOMPARE(eval(QSL("new URL(\"qrc://foo.com/crysis.css\").origin")), QVariant(QSL("qrc://"))); - // Same with custom schemes. + // Same with unregistered schemes. QCOMPARE(eval(QSL("new URL(\"tst:/banana\").origin")), QVariant(QSL("tst://"))); QCOMPARE(eval(QSL("new URL(\"tst://foo.com/banana\").origin")), QVariant(QSL("tst://"))); + + // The non-PathSyntax schemes should have hosts and potentially ports. + QCOMPARE(eval(QSL("new URL(\"HostSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostsyntax://foo"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostandportsyntax://foo:41"))); + QCOMPARE(eval(QSL("new URL(\"HostAndPortSyntax:foo:42/bar\").origin")), + QVariant(QSL("hostandportsyntax://foo"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:41/bar\").origin")), + QVariant(QSL("hostportanduserinformationsyntax://foo:41"))); + QCOMPARE(eval(QSL("new URL(\"HostPortAndUserInformationSyntax:foo:42/bar\").origin")), + QVariant(QSL("hostportanduserinformationsyntax://foo"))); + + // A PathSyntax scheme should have a 'universal' origin. + QCOMPARE(eval(QSL("new URL(\"PathSyntax:foo\").origin")), + QVariant(QSL("pathsyntax://"))); + + // The NoAccessAllowed flag forces opaque origins. + QCOMPARE(eval(QSL("new URL(\"PathSyntax-NoAccessAllowed:foo\").origin")), + QVariant(QSL("null"))); } class ScopedAttribute { @@ -185,7 +350,7 @@ private: // demonstrate the difference with Firefox where such access is not allowed. void tst_Origins::subdirWithAccess() { - ScopedAttribute sa(m_page.settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); QVERIFY(load(QSL("file:" THIS_DIR "resources/subdir/index.html"))); QCOMPARE(eval(QSL("msg[0]")), QVariant(QSL("hello"))); @@ -211,7 +376,7 @@ void tst_Origins::subdirWithAccess() // - the blink::SecurityOrigin::BlockLocalAccessFromLocalOrigin() method. void tst_Origins::subdirWithoutAccess() { - ScopedAttribute sa(m_page.settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); QVERIFY(load(QSL("file:" THIS_DIR "resources/subdir/index.html"))); QCOMPARE(eval(QSL("msg[0]")), QVariant()); @@ -226,46 +391,163 @@ void tst_Origins::subdirWithoutAccess() QCOMPARE(eval(QSL("msg[1]")), QVariant(QSL("world"))); } -// Try to mix schemes, for example by loading the main page over file with an -// iframe over qrc. This should be forbidden. +// Load the main page over one scheme with an iframe over another scheme. +// +// For file and qrc schemes, the iframe should load but it should not be +// possible for scripts in different frames to interact. +// +// Additionally for unregistered custom schemes and custom schemes without +// LocalAccessAllowed it should not be possible to load an iframe over the +// file: scheme. void tst_Origins::mixedSchemes() { - QVERIFY(load(QSL("file:" THIS_DIR "resources/mixed_qrc.html"))); - QCOMPARE(eval(QSL("msg")), QVariant()); - QVERIFY(load(QSL("file:" THIS_DIR "resources/mixed_tst.html"))); - QCOMPARE(eval(QSL("msg")), QVariant()); - - QVERIFY(load(QSL("qrc:/resources/mixed_qrc.html"))); - QCOMPARE(eval(QSL("msg")), QVariant(QSL("mixed"))); - QVERIFY(load(QSL("qrc:/resources/mixed_tst.html"))); - QCOMPARE(eval(QSL("msg")), QVariant()); - - QVERIFY(load(QSL("tst:/resources/mixed_qrc.html"))); - QCOMPARE(eval(QSL("msg")), QVariant()); - QVERIFY(load(QSL("tst:/resources/mixed_tst.html"))); - QCOMPARE(eval(QSL("msg")), QVariant(QSL("mixed"))); + QVERIFY(load(QSL("file:" THIS_DIR "resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("qrc:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("tst:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + + QVERIFY(load(QSL("PathSyntax:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("PathSyntax-LocalAccessAllowed:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("PathSyntax-NoAccessAllowed:/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("HostSyntax://a/resources/mixedSchemes.html"))); + eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); } +// Like mixedSchemes but adds a Content-Security-Policy: frame-src 'none' header. +void tst_Origins::mixedSchemesWithCsp() +{ + QVERIFY(load(QSL("HostSyntax://a/resources/mixedSchemesWithCsp.html"))); + eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + + QVERIFY(load(QSL("HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemesWithCsp.html"))); + eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://b/resources/mixedSchemes_frame.html')")); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); +} + +#if defined(WEBSOCKETS) +class EchoServer : public QObject { + Q_OBJECT + Q_PROPERTY(QUrl url READ url NOTIFY urlChanged) +public: + EchoServer() : webSocketServer(QSL("EchoServer"), QWebSocketServer::NonSecureMode) + { + connect(&webSocketServer, &QWebSocketServer::newConnection, this, &EchoServer::onNewConnection); + } + + bool listen() + { + if (webSocketServer.listen(QHostAddress::Any)) { + Q_EMIT urlChanged(); + return true; + } + return false; + } + + QUrl url() const + { + return webSocketServer.serverUrl(); + } + +Q_SIGNALS: + void urlChanged(); + +private: + void onNewConnection() + { + QWebSocket *socket = webSocketServer.nextPendingConnection(); + connect(socket, &QWebSocket::textMessageReceived, this, &EchoServer::onTextMessageReceived); + connect(socket, &QWebSocket::disconnected, socket, &QObject::deleteLater); + } + + void onTextMessageReceived(const QString &message) + { + QWebSocket *socket = qobject_cast<QWebSocket *>(sender()); + socket->sendTextMessage(message); + } + + QWebSocketServer webSocketServer; +}; + // Try opening a WebSocket from pages loaded over various URL schemes. void tst_Origins::webSocket() { - // 1006 indicates 'Abnormal Closure'. - // - // The example page is passing a URL with a non-existent domain to the - // WebSocket constructor, so we expect the connection to fail. This is - // enough though to trigger the origin checks. - const int expected = 1006; + const int kAbnormalClosure = 1006; + + EchoServer echoServer; + QWebChannel channel; + channel.registerObject(QSL("echoServer"), &echoServer); + m_page->setWebChannel(&channel); + QVERIFY(echoServer.listen()); QVERIFY(load(QSL("file:" THIS_DIR "resources/websocket.html"))); - QTRY_VERIFY(eval(QSL("err")) == QVariant(expected)); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); QVERIFY(load(QSL("qrc:/resources/websocket.html"))); - QTRY_VERIFY(eval(QSL("err")) == QVariant(expected)); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); + // Only registered schemes can open WebSockets. QVERIFY(load(QSL("tst:/resources/websocket.html"))); - QTRY_VERIFY(eval(QSL("err")) == QVariant(expected)); -} + QTRY_COMPARE(eval(QSL("result")), QVariant(kAbnormalClosure)); + // Even an insecure registered scheme can open WebSockets. + QVERIFY(load(QSL("PathSyntax:/resources/websocket.html"))); + QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("ok"))); +} +#endif // Create a (Dedicated)Worker. Since dedicated workers can only be accessed from // one page, there is not much need for security restrictions. void tst_Origins::dedicatedWorker() @@ -278,11 +560,22 @@ void tst_Origins::dedicatedWorker() QTRY_VERIFY(eval(QSL("done")).toBool()); QCOMPARE(eval(QSL("result")), QVariant(42)); - // FIXME(juvaldma): QTBUG-62536 + // Unregistered schemes cannot create Workers. QVERIFY(load(QSL("tst:/resources/dedicatedWorker.html"))); QTRY_VERIFY(eval(QSL("done")).toBool()); QVERIFY(eval(QSL("error")).toString() .contains(QSL("Access to dedicated workers is denied to origin 'tst://'"))); + + // Even an insecure registered scheme can create Workers. + QVERIFY(load(QSL("PathSyntax:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + // But not if the NoAccessAllowed flag is set. + QVERIFY(load(QSL("PathSyntax-NoAccessAllowed:/resources/dedicatedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("cannot be accessed from origin 'null'"))); } // Create a SharedWorker. Shared workers can be accessed from multiple pages, @@ -290,7 +583,7 @@ void tst_Origins::dedicatedWorker() void tst_Origins::sharedWorker() { { - ScopedAttribute sa(m_page.settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); QVERIFY(load(QSL("file:" THIS_DIR "resources/sharedWorker.html"))); QTRY_VERIFY(eval(QSL("done")).toBool()); QVERIFY(eval(QSL("error")).toString() @@ -298,7 +591,7 @@ void tst_Origins::sharedWorker() } { - ScopedAttribute sa(m_page.settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); + ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, true); QVERIFY(load(QSL("file:" THIS_DIR "resources/sharedWorker.html"))); QTRY_VERIFY(eval(QSL("done")).toBool()); QCOMPARE(eval(QSL("result")), QVariant(42)); @@ -308,12 +601,22 @@ void tst_Origins::sharedWorker() QTRY_VERIFY(eval(QSL("done")).toBool()); QCOMPARE(eval(QSL("result")), QVariant(42)); + // Even unregistered schemes can create SharedWorkers. QVERIFY(load(QSL("tst:/resources/sharedWorker.html"))); QTRY_VERIFY(eval(QSL("done")).toBool()); QCOMPARE(eval(QSL("result")), QVariant(42)); + + QVERIFY(load(QSL("PathSyntax:/resources/sharedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("result")), QVariant(42)); + + QVERIFY(load(QSL("PathSyntax-NoAccessAllowed:/resources/sharedWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("denied to origin 'null'"))); } -// Service workers don't work. +// Service workers have to be explicitly enabled for a scheme. void tst_Origins::serviceWorker() { QVERIFY(load(QSL("file:" THIS_DIR "resources/serviceWorker.html"))); @@ -330,6 +633,53 @@ void tst_Origins::serviceWorker() QTRY_VERIFY(eval(QSL("done")).toBool()); QVERIFY(eval(QSL("error")).toString() .contains(QSL("Only secure origins are allowed"))); + + QVERIFY(load(QSL("PathSyntax:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Only secure origins are allowed"))); + + QVERIFY(load(QSL("PathSyntax-Secure:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("The URL protocol of the current origin ('pathsyntax-secure://') is not supported."))); + + QVERIFY(load(QSL("PathSyntax-ServiceWorkersAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("Only secure origins are allowed"))); + + QVERIFY(load(QSL("PathSyntax-Secure-ServiceWorkersAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QCOMPARE(eval(QSL("error")), QVariant()); + + QVERIFY(load(QSL("PathSyntax-NoAccessAllowed:/resources/serviceWorker.html"))); + QTRY_VERIFY(eval(QSL("done")).toBool()); + QVERIFY(eval(QSL("error")).toString() + .contains(QSL("denied in this document origin"))); +} + +// Support for view-source must be enabled explicitly. +void tst_Origins::viewSource() +{ + QVERIFY(load(QSL("view-source:file:" THIS_DIR "resources/viewSource.html"))); +#ifdef Q_OS_WIN + QCOMPARE(m_page->requestedUrl(), QSL("file:///" THIS_DIR "resources/viewSource.html")); +#else + QCOMPARE(m_page->requestedUrl(), QSL("file:" THIS_DIR "resources/viewSource.html")); +#endif + + QVERIFY(load(QSL("view-source:qrc:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl(), QSL("qrc:/resources/viewSource.html")); + + QVERIFY(load(QSL("view-source:tst:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl(), QSL("about:blank")); + + QVERIFY(load(QSL("view-source:PathSyntax:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl(), QSL("about:blank")); + + QVERIFY(load(QSL("view-source:PathSyntax-ViewSourceAllowed:/resources/viewSource.html"))); + QCOMPARE(m_page->requestedUrl(), QSL("pathsyntax-viewsourceallowed:/resources/viewSource.html")); } QTEST_MAIN(tst_Origins) diff --git a/tests/auto/widgets/origins/tst_origins.qrc b/tests/auto/widgets/origins/tst_origins.qrc index fbbbef139..438fd10ee 100644 --- a/tests/auto/widgets/origins/tst_origins.qrc +++ b/tests/auto/widgets/origins/tst_origins.qrc @@ -3,9 +3,9 @@ <qresource> <file>resources/dedicatedWorker.html</file> <file>resources/dedicatedWorker.js</file> - <file>resources/mixed_frame.html</file> - <file>resources/mixed_qrc.html</file> - <file>resources/mixed_tst.html</file> + <file>resources/mixedSchemes.html</file> + <file>resources/mixedSchemesWithCsp.html</file> + <file>resources/mixedSchemes_frame.html</file> <file>resources/serviceWorker.html</file> <file>resources/serviceWorker.js</file> <file>resources/sharedWorker.html</file> @@ -13,6 +13,7 @@ <file>resources/subdir/frame2.html</file> <file>resources/subdir/index.html</file> <file>resources/subdir_frame1.html</file> + <file>resources/viewSource.html</file> <file>resources/websocket.html</file> </qresource> </RCC> diff --git a/tests/auto/widgets/printing/printing.pro b/tests/auto/widgets/printing/printing.pro new file mode 100644 index 000000000..92f5d611c --- /dev/null +++ b/tests/auto/widgets/printing/printing.pro @@ -0,0 +1,10 @@ +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 +QT_FOR_CONFIG += webenginecore-private + +include(../tests.pri) +QT *= core-private webenginecore-private + +qtConfig(webengine-poppler-cpp) { + CONFIG += link_pkgconfig + PKGCONFIG += poppler-cpp +} diff --git a/tests/auto/widgets/qwebenginepage/resources/basic_printing_page.html b/tests/auto/widgets/printing/resources/basic_printing_page.html index 0c6ff379f..0c6ff379f 100644 --- a/tests/auto/widgets/qwebenginepage/resources/basic_printing_page.html +++ b/tests/auto/widgets/printing/resources/basic_printing_page.html diff --git a/tests/auto/widgets/printing/tst_printing.cpp b/tests/auto/widgets/printing/tst_printing.cpp new file mode 100644 index 000000000..2fd12b8ec --- /dev/null +++ b/tests/auto/widgets/printing/tst_printing.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtWebEngine module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> +#include <QWebEnginePage> +#include <QTemporaryDir> +#include <QTest> +#include <QSignalSpy> +#include <util.h> + +#if QT_CONFIG(webengine_poppler_cpp) +#include <poppler-document.h> +#include <poppler-page.h> +#endif + +class tst_Printing : public QObject +{ + Q_OBJECT +private slots: + void printToPdfBasic(); + void printRequest(); +#if QT_CONFIG(webengine_poppler_cpp) + void printToPdfPoppler(); +#endif +}; + +void tst_Printing::printToPdfBasic() +{ + QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); + QVERIFY(tempDir.isValid()); + QWebEnginePage page; + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + page.load(QUrl("qrc:///resources/basic_printing_page.html")); + QTRY_VERIFY(spy.count() == 1); + + QSignalSpy savePdfSpy(&page, &QWebEnginePage::pdfPrintingFinished); + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); + QString path = tempDir.path() + "/print_1_success.pdf"; + page.printToPdf(path, layout); + QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); + + QList<QVariant> successArguments = savePdfSpy.takeFirst(); + QVERIFY2(successArguments.at(0).toString() == path, "File path for first saved PDF does not match arguments"); + QVERIFY2(successArguments.at(1).toBool() == true, "Printing to PDF file failed though it should succeed"); + +#if !defined(Q_OS_WIN) + path = tempDir.path() + "/print_//2_failed.pdf"; +#else + path = tempDir.path() + "/print_|2_failed.pdf"; +#endif + page.printToPdf(path, QPageLayout()); + QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); + + QList<QVariant> failedArguments = savePdfSpy.takeFirst(); + QVERIFY2(failedArguments.at(0).toString() == path, "File path for second saved PDF does not match arguments"); + QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail"); + + CallbackSpy<QByteArray> successfulSpy; + page.printToPdf(successfulSpy.ref(), layout); + QVERIFY(successfulSpy.waitForResult().length() > 0); + + CallbackSpy<QByteArray> failedInvalidLayoutSpy; + page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); + QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0); +} + +void tst_Printing::printRequest() +{ + QWebEnginePage webPage; + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); + QSignalSpy loadFinishedSpy(&webPage, &QWebEnginePage::loadFinished); + QSignalSpy printRequestedSpy(&webPage, &QWebEnginePage::printRequested); + QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished); + CallbackSpy<QByteArray> resultSpy; + + webPage.load(QUrl("qrc:///resources/basic_printing_page.html")); + QTRY_VERIFY(loadFinishedSpy.count() == 1); + webPage.runJavaScript("window.print()"); + QTRY_VERIFY(printRequestedSpy.count() == 1); + //check if printing still works + webPage.printToPdf(resultSpy.ref(), layout); + const QByteArray data = resultSpy.waitForResult(); + QVERIFY(data.length() > 0); +} + +#if QT_CONFIG(webengine_poppler_cpp) +void tst_Printing::printToPdfPoppler() +{ + // check if generated pdf is correct by searching for a know string on the page + using namespace poppler; + QWebEnginePage webPage; + QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); + + QSignalSpy spy(&webPage, &QWebEnginePage::loadFinished); + QSignalSpy savePdfSpy(&webPage, &QWebEnginePage::pdfPrintingFinished); + CallbackSpy<QByteArray> resultSpy; + + webPage.load(QUrl("qrc:///resources/basic_printing_page.html")); + QTRY_VERIFY(spy.count() == 1); + webPage.printToPdf(resultSpy.ref(), layout); + const QByteArray data = resultSpy.waitForResult(); + QVERIFY(data.length() > 0); + + QScopedPointer<document> pdf(document::load_from_raw_data(data.constData(), data.length())); + QVERIFY(pdf); + + const int pages = pdf->pages(); + QVERIFY(pages == 1); + + QScopedPointer<page> pdfPage(pdf->create_page(0)); + rectf rect; + QVERIFY2(pdfPage->search(ustring::from_latin1("Hello Paper World"), rect, page::search_from_top, + case_sensitive ), "Could not find text"); +} +#endif + + +QTEST_MAIN(tst_Printing) +#include "tst_printing.moc" diff --git a/tests/auto/widgets/printing/tst_printing.qrc b/tests/auto/widgets/printing/tst_printing.qrc new file mode 100644 index 000000000..b1795ef8a --- /dev/null +++ b/tests/auto/widgets/printing/tst_printing.qrc @@ -0,0 +1,5 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resources/basic_printing_page.html</file> +</qresource> +</RCC> diff --git a/tests/auto/widgets/qwebenginedownloads/qwebenginedownloads.pro b/tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro index 18a66c466..18a66c466 100644 --- a/tests/auto/widgets/qwebenginedownloads/qwebenginedownloads.pro +++ b/tests/auto/widgets/qwebenginedownloaditem/qwebenginedownloaditem.pro diff --git a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index f932d50c3..68c549540 100644 --- a/tests/auto/widgets/qwebenginedownloads/tst_qwebenginedownloads.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -37,7 +37,7 @@ #include <QWebEngineView> #include <httpserver.h> -class tst_QWebEngineDownloads : public QObject +class tst_QWebEngineDownloadItem : public QObject { Q_OBJECT @@ -92,10 +92,10 @@ private: QMetaObject::Connection m_connection; }; -Q_DECLARE_METATYPE(tst_QWebEngineDownloads::UserAction) -Q_DECLARE_METATYPE(tst_QWebEngineDownloads::FileAction) +Q_DECLARE_METATYPE(tst_QWebEngineDownloadItem::UserAction) +Q_DECLARE_METATYPE(tst_QWebEngineDownloadItem::FileAction) -void tst_QWebEngineDownloads::initTestCase() +void tst_QWebEngineDownloadItem::initTestCase() { m_server = new HttpServer(); m_profile = new QWebEngineProfile; @@ -116,18 +116,18 @@ void tst_QWebEngineDownloads::initTestCase() m_view->show(); } -void tst_QWebEngineDownloads::init() +void tst_QWebEngineDownloadItem::init() { QVERIFY(m_server->start()); } -void tst_QWebEngineDownloads::cleanup() +void tst_QWebEngineDownloadItem::cleanup() { QCOMPARE(m_downloads.count(), 0); QVERIFY(m_server->stop()); } -void tst_QWebEngineDownloads::cleanupTestCase() +void tst_QWebEngineDownloadItem::cleanupTestCase() { delete m_view; delete m_page; @@ -135,7 +135,7 @@ void tst_QWebEngineDownloads::cleanupTestCase() delete m_server; } -void tst_QWebEngineDownloads::saveLink(QPoint linkPos) +void tst_QWebEngineDownloadItem::saveLink(QPoint linkPos) { // Simulate right-clicking on link and choosing "save link as" from menu. QSignalSpy menuSpy(m_view, &QWebEngineView::customContextMenuRequested); @@ -152,7 +152,7 @@ void tst_QWebEngineDownloads::saveLink(QPoint linkPos) m_page->triggerAction(QWebEnginePage::DownloadLinkToDisk); } -void tst_QWebEngineDownloads::clickLink(QPoint linkPos) +void tst_QWebEngineDownloadItem::clickLink(QPoint linkPos) { // Simulate left-clicking on link. QTRY_VERIFY(m_view->focusWidget()); @@ -160,7 +160,7 @@ void tst_QWebEngineDownloads::clickLink(QPoint linkPos) QTest::mouseClick(renderWidget, Qt::LeftButton, {}, linkPos); } -void tst_QWebEngineDownloads::simulateUserAction(QPoint linkPos, UserAction action) +void tst_QWebEngineDownloadItem::simulateUserAction(QPoint linkPos, UserAction action) { switch (action) { case SaveLink: return saveLink(linkPos); @@ -168,7 +168,7 @@ void tst_QWebEngineDownloads::simulateUserAction(QPoint linkPos, UserAction acti } } -QWebEngineDownloadItem::DownloadType tst_QWebEngineDownloads::expectedDownloadType( +QWebEngineDownloadItem::DownloadType tst_QWebEngineDownloadItem::expectedDownloadType( UserAction userAction, const QByteArray &contentDisposition) { if (userAction == SaveLink) @@ -178,7 +178,7 @@ QWebEngineDownloadItem::DownloadType tst_QWebEngineDownloads::expectedDownloadTy return QWebEngineDownloadItem::DownloadAttribute; } -void tst_QWebEngineDownloads::downloadLink_data() +void tst_QWebEngineDownloadItem::downloadLink_data() { QTest::addColumn<UserAction>("userAction"); QTest::addColumn<bool>("anchorHasDownloadAttribute"); @@ -284,7 +284,7 @@ void tst_QWebEngineDownloads::downloadLink_data() /* fileMimeTypeDeclared */ << QByteArrayLiteral("text/plain") /* fileMimeTypeDetected */ << QByteArrayLiteral("text/plain") /* fileDisposition */ << QByteArrayLiteral("") - /* fileHasReferer */ << true + /* fileHasReferer */ << false // crbug.com/455987 /* fileAction */ << FileIsDownloaded; // ... same with the content disposition header save for the download type. @@ -308,7 +308,7 @@ void tst_QWebEngineDownloads::downloadLink_data() /* fileMimeTypeDeclared */ << QByteArrayLiteral("text/plain") /* fileMimeTypeDetected */ << QByteArrayLiteral("text/plain") /* fileDisposition */ << QByteArrayLiteral("attachment") - /* fileHasReferer */ << true + /* fileHasReferer */ << false // crbug.com/455987 /* fileAction */ << FileIsDownloaded; // The file's extension has no effect. @@ -375,7 +375,7 @@ void tst_QWebEngineDownloads::downloadLink_data() /* fileAction */ << FileIsDownloaded; } -void tst_QWebEngineDownloads::downloadLink() +void tst_QWebEngineDownloadItem::downloadLink() { QFETCH(UserAction, userAction); QFETCH(bool, anchorHasDownloadAttribute); @@ -443,6 +443,7 @@ void tst_QWebEngineDownloads::downloadLink() QCOMPARE(item->path(), suggestedPath); QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat); QCOMPARE(item->url(), downloadUrl); + QCOMPARE(item->page(), m_page); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -456,6 +457,7 @@ void tst_QWebEngineDownloads::downloadLink() QCOMPARE(item->path(), downloadPath); QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat); QCOMPARE(item->url(), downloadUrl); + QCOMPARE(item->page(), m_page); finishedCount++; }); @@ -498,7 +500,7 @@ void tst_QWebEngineDownloads::downloadLink() QCOMPARE(file.readAll(), fileContents); } -void tst_QWebEngineDownloads::downloadTwoLinks_data() +void tst_QWebEngineDownloadItem::downloadTwoLinks_data() { QTest::addColumn<UserAction>("action1"); QTest::addColumn<UserAction>("action2"); @@ -508,7 +510,7 @@ void tst_QWebEngineDownloads::downloadTwoLinks_data() QTest::newRow("Click+Click") << ClickLink << ClickLink; } -void tst_QWebEngineDownloads::downloadTwoLinks() +void tst_QWebEngineDownloadItem::downloadTwoLinks() { QFETCH(UserAction, action1); QFETCH(UserAction, action2); @@ -584,29 +586,13 @@ void tst_QWebEngineDownloads::downloadTwoLinks() simulateUserAction(QPoint(10, 30), action2); // Wait for downloads - if (action1 == action2 && action1 == ClickLink) { - // With two clicks, sometimes both files get downloaded, sometimes only - // the second file, depending on the timing. This is expected and - // follows Chromium's behavior. We check here only that the second file - // is downloaded correctly (and that we do not crash). - // - // The first download may be aborted before or after the HTTP request is - // made. In the latter case we will have both a file1 and a file2 - // request, but still only one accepted download. - QTRY_COMPARE(file2RequestCount, 1); - QTRY_VERIFY(acceptedCount >= 1); - QTRY_VERIFY(finishedCount >= 1); - QTRY_COMPARE(m_downloads.count(), 0); - } else { - // Otherwise both files should always be downloaded correctly. - QTRY_COMPARE(file1RequestCount, 1); - QTRY_COMPARE(file2RequestCount, 1); - QTRY_COMPARE(acceptedCount, 2); - QTRY_COMPARE(finishedCount, 2); - } + QTRY_COMPARE(file1RequestCount, 1); + QTRY_COMPARE(file2RequestCount, 1); + QTRY_COMPARE(acceptedCount, 2); + QTRY_COMPARE(finishedCount, 2); } -void tst_QWebEngineDownloads::downloadPage_data() +void tst_QWebEngineDownloadItem::downloadPage_data() { QTest::addColumn<QWebEngineDownloadItem::SavePageFormat>("savePageFormat"); QTest::newRow("SingleHtmlSaveFormat") << QWebEngineDownloadItem::SingleHtmlSaveFormat; @@ -614,7 +600,7 @@ void tst_QWebEngineDownloads::downloadPage_data() QTest::newRow("MimeHtmlSaveFormat") << QWebEngineDownloadItem::MimeHtmlSaveFormat; } -void tst_QWebEngineDownloads::downloadPage() +void tst_QWebEngineDownloadItem::downloadPage() { QFETCH(QWebEngineDownloadItem::SavePageFormat, savePageFormat); @@ -652,6 +638,7 @@ void tst_QWebEngineDownloads::downloadPage() QCOMPARE(item->path(), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); + QCOMPARE(item->page(), m_page); // no need to call item->accept() connect(item, &QWebEngineDownloadItem::finished, [&, item]() { @@ -666,6 +653,7 @@ void tst_QWebEngineDownloads::downloadPage() QCOMPARE(item->path(), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); + QCOMPARE(item->page(), m_page); finishedCount++; }); @@ -688,7 +676,7 @@ void tst_QWebEngineDownloads::downloadPage() QVERIFY(file.exists()); } -void tst_QWebEngineDownloads::downloadViaSetUrl() +void tst_QWebEngineDownloadItem::downloadViaSetUrl() { // Reproduce the scenario described in QTBUG-63388 by triggering downloads // of the same file multiple times via QWebEnginePage::setUrl @@ -742,7 +730,7 @@ void tst_QWebEngineDownloads::downloadViaSetUrl() } } -void tst_QWebEngineDownloads::downloadFileNot1() +void tst_QWebEngineDownloadItem::downloadFileNot1() { // Trigger file download via download() but don't accept(). @@ -765,7 +753,7 @@ void tst_QWebEngineDownloads::downloadFileNot1() QVERIFY(!downloadItem); } -void tst_QWebEngineDownloads::downloadFileNot2() +void tst_QWebEngineDownloadItem::downloadFileNot2() { // Trigger file download via download() but call cancel() instead of accept(). @@ -790,5 +778,5 @@ void tst_QWebEngineDownloads::downloadFileNot2() QCOMPARE(downloadItem->state(), QWebEngineDownloadItem::DownloadCancelled); } -QTEST_MAIN(tst_QWebEngineDownloads) -#include "tst_qwebenginedownloads.moc" +QTEST_MAIN(tst_QWebEngineDownloadItem) +#include "tst_qwebenginedownloaditem.moc" diff --git a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp index 3c8025672..6209401cb 100644 --- a/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp +++ b/tests/auto/widgets/qwebenginehistory/tst_qwebenginehistory.cpp @@ -485,11 +485,11 @@ void tst_QWebEngineHistory::clear() void tst_QWebEngineHistory::historyItemFromDeletedPage() { - QList<QWebEngineHistoryItem> items = page->history()->items(); + const QList<QWebEngineHistoryItem> items = page->history()->items(); delete page; page = 0; - foreach (QWebEngineHistoryItem item, items) { + for (const QWebEngineHistoryItem &item : items) { QVERIFY(!item.isValid()); QTRY_COMPARE(item.originalUrl(), QUrl()); QTRY_COMPARE(item.url(), QUrl()); diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro index 8e7453827..18a66c466 100644 --- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro +++ b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro @@ -1,5 +1,3 @@ include(../tests.pri) include(../../shared/http.pri) QT *= core-private - -qtConfig(webengine-printing-and-pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED diff --git a/tests/auto/widgets/qwebenginepage/resources/dynamicFrame.html b/tests/auto/widgets/qwebenginepage/resources/dynamicFrame.html new file mode 100644 index 000000000..731387b37 --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/dynamicFrame.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <head> + <title>Dynamic iframe</title> + </head> + <body> + <script> + const ifr = document.createElement("iframe"); + ifr.setAttribute("src", "invalid"); + document.body.appendChild(ifr); + ifr.contentWindow.document.open("text/html", "replace"); + ifr.contentWindow.document.write("foo"); + ifr.contentWindow.document.close(); + </script> + </body> +</html> diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 7bdad1bda..8b36d5a6f 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -20,6 +20,7 @@ */ #include "../util.h" +#include <QtWebEngineCore/qtwebenginecore-config.h> #include <QByteArray> #include <QClipboard> #include <QDir> @@ -39,7 +40,9 @@ #include <QtGui/QClipboard> #include <QtTest/QtTest> #include <QTextCharFormat> +#if QT_CONFIG(webengine_webchannel) #include <QWebChannel> +#endif #include <httpserver.h> #include <qnetworkcookiejar.h> #include <qnetworkreply.h> @@ -161,6 +164,7 @@ private Q_SLOTS: #endif void runJavaScript(); + void runJavaScriptDisabled(); void fullScreenRequested(); void quotaRequested(); @@ -201,15 +205,15 @@ private Q_SLOTS: void loadInSignalHandlers_data(); void loadInSignalHandlers(); void loadFromQrc(); - +#if QT_CONFIG(webengine_webchannel) void restoreHistory(); +#endif void toPlainTextLoadFinishedRace_data(); void toPlainTextLoadFinishedRace(); void setZoomFactor(); void mouseButtonTranslation(); void mouseMovementProperties(); - void printToPdf(); void viewSource(); void viewSourceURL_data(); void viewSourceURL(); @@ -221,6 +225,7 @@ private Q_SLOTS: void devTools(); void openLinkInDifferentProfile(); void triggerActionWithoutMenu(); + void dynamicFrame(); private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); @@ -398,6 +403,11 @@ void tst_QWebEnginePage::geolocationRequestJS() QSignalSpy spyLoadFinished(newPage, SIGNAL(loadFinished(bool))); newPage->setHtml(QString("<html><body>test</body></html>"), QUrl("qrc://secure/origin")); QTRY_COMPARE(spyLoadFinished.count(), 1); + + // Geolocation is only enabled for visible WebContents. + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + if (evaluateJavaScriptSync(newPage, QLatin1String("!navigator.geolocation")).toBool()) W_QSKIP("Geolocation is not supported.", SkipSingle); @@ -773,7 +783,8 @@ void tst_QWebEnginePage::updatePositionDependentActionsCrash() QPoint pos(0, 0); view.page()->updatePositionDependentActions(pos); QMenu* contextMenu = 0; - foreach (QObject* child, view.children()) { + const QList<QObject *> children = view.children(); + for (QObject *child : children) { contextMenu = qobject_cast<QMenu*>(child); if (contextMenu) break; @@ -795,7 +806,8 @@ void tst_QWebEnginePage::contextMenuCrash() view.page()->swallowContextMenuEvent(&event); view.page()->updatePositionDependentActions(pos); QMenu* contextMenu = 0; - foreach (QObject* child, view.children()) { + const QList<QObject *> children = view.children(); + for (QObject *child : children) { contextMenu = qobject_cast<QMenu*>(child); if (contextMenu) break; @@ -1839,8 +1851,8 @@ void tst_QWebEnginePage::findTextResult() QCOMPARE(findTextSync(m_page, ""), false); - QStringList words = (QStringList() << "foo" << "bar"); - foreach (QString subString, words) { + const QStringList words = { "foo", "bar" }; + for (const QString &subString : words) { QCOMPARE(findTextSync(m_page, subString), true); QCOMPARE(findTextSync(m_page, ""), false); } @@ -1900,7 +1912,8 @@ void tst_QWebEnginePage::supportedContentType() #endif // Add supported image types... - Q_FOREACH (const QByteArray& imageType, QImageWriter::supportedImageFormats()) { + const QList<QByteArray> supportedImageFormats = QImageWriter::supportedImageFormats(); + for (const QByteArray &imageType : supportedImageFormats) { const QString mimeType = getMimeTypeForExtension(imageType); if (!mimeType.isEmpty()) contentTypes << mimeType; @@ -1909,10 +1922,10 @@ void tst_QWebEnginePage::supportedContentType() // Get the mime types supported by webengine... const QStringList supportedContentTypes = m_page->supportedContentTypes(); - Q_FOREACH (const QString& mimeType, contentTypes) + for (const QString &mimeType : qAsConst(contentTypes)) QVERIFY2(supportedContentTypes.contains(mimeType), QString("'%1' is not a supported content type!").arg(mimeType).toLatin1()); - Q_FOREACH (const QString& mimeType, contentTypes) + for (const QString &mimeType : qAsConst(contentTypes)) QVERIFY2(m_page->supportsContentType(mimeType), QString("Cannot handle content types '%1'!").arg(mimeType).toLatin1()); #endif } @@ -2283,7 +2296,8 @@ void tst_QWebEnginePage::renderWidgetHostViewNotShowTopLevel() // Make sure that RenderWidgetHostViewQtDelegateWidgets are not shown as top-level. // They should only be made visible when parented to a QWebEngineView. - foreach (QWidget *widget, QApplication::topLevelWidgets()) + const QList<QWidget *> widgets = QApplication::topLevelWidgets(); + for (QWidget *widget : widgets) QCOMPARE(widget->isVisible(), false); } @@ -2392,6 +2406,15 @@ void tst_QWebEnginePage::getUserMediaRequest() QFETCH(QWebEnginePage::Feature, feature); GetUserMediaTestPage page; + if (feature == QWebEnginePage::DesktopVideoCapture || feature == QWebEnginePage::DesktopAudioVideoCapture) { + // Desktop capture needs to be on a desktop. + QWebEngineView view; + view.setPage(&page); + view.resize(640, 480); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + } + QTRY_VERIFY_WITH_TIMEOUT(page.loadSucceeded(), 20000); page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true); @@ -2755,6 +2778,21 @@ void tst_QWebEnginePage::runJavaScript() QVERIFY(watcher.wait()); } +void tst_QWebEnginePage::runJavaScriptDisabled() +{ + QWebEnginePage page; + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + page.settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, false); + // Settings changes take effect asynchronously. The load and wait ensure + // that the settings are applied by the time we start to execute JavaScript. + page.load(QStringLiteral("about:blank")); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(evaluateJavaScriptSyncInWorld(&page, QStringLiteral("1+1"), QWebEngineScript::MainWorld), + QVariant()); + QCOMPARE(evaluateJavaScriptSyncInWorld(&page, QStringLiteral("1+1"), QWebEngineScript::ApplicationWorld), + QVariant(2)); +} + void tst_QWebEnginePage::fullScreenRequested() { JavaScriptCallbackWatcher watcher; @@ -3025,7 +3063,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() const QUrl first("http://abcdef.abcdef/"); page.setUrl(first); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); QCOMPARE(page.url(), first); QCOMPARE(page.requestedUrl(), first); QVERIFY(!spy.at(0).first().toBool()); @@ -3034,7 +3072,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() QVERIFY(first != second); page.load(second); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000); QCOMPARE(page.url(), second); QCOMPARE(page.requestedUrl(), second); QVERIFY(!spy.at(1).first().toBool()); @@ -3284,8 +3322,8 @@ void tst_QWebEnginePage::scrollPosition() // try to set the scroll offset programmatically view.page()->runJavaScript("window.scrollTo(23, 29);"); - QTRY_COMPARE(view.page()->scrollPosition().x(), qreal(23)); - QCOMPARE(view.page()->scrollPosition().y(), qreal(29)); + QTRY_COMPARE(view.page()->scrollPosition().x(), 23 * view.windowHandle()->devicePixelRatio()); + QCOMPARE(view.page()->scrollPosition().y(), 29 * view.windowHandle()->devicePixelRatio()); int x = evaluateJavaScriptSync(view.page(), "window.scrollX").toInt(); int y = evaluateJavaScriptSync(view.page(), "window.scrollY").toInt(); @@ -3568,7 +3606,7 @@ void tst_QWebEnginePage::setUrlToBadDomain() page.setUrl(url1); QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 20000); QTRY_COMPARE(loadSpy.count(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url1); @@ -3581,7 +3619,7 @@ void tst_QWebEnginePage::setUrlToBadDomain() page.setUrl(url2); QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 20000); QTRY_COMPARE(loadSpy.count(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url2); @@ -3636,7 +3674,8 @@ void tst_QWebEnginePage::setUrlToBadPort() static QStringList collectHistoryUrls(QWebEngineHistory *history) { QStringList urls; - foreach (const QWebEngineHistoryItem &i, history->items()) + const QList<QWebEngineHistoryItem> items = history->items(); + for (const QWebEngineHistoryItem &i : items) urls << i.url().toString(); return urls; } @@ -3824,11 +3863,11 @@ void tst_QWebEnginePage::loadFinishedAfterNotFoundError() page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); page.setUrl(QUrl("http://non.existent/url")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); page.setUrl(QUrl("http://another.non.existent/url")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000); } class URLSetter : public QObject { @@ -3955,6 +3994,7 @@ void tst_QWebEnginePage::loadFromQrc() QCOMPARE(spy.takeFirst().value(0).toBool(), false); } +#if QT_CONFIG(webengine_webchannel) void tst_QWebEnginePage::restoreHistory() { QWebChannel channel; @@ -3982,6 +4022,7 @@ void tst_QWebEnginePage::restoreHistory() QCOMPARE(page.webChannel(), &channel); QVERIFY(page.scripts().contains(script)); } +#endif void tst_QWebEnginePage::toPlainTextLoadFinishedRace_data() { @@ -4003,7 +4044,7 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace() QCOMPARE(toPlainTextSync(page.data()), QString("foobarbaz")); page->load(QUrl("http://fail.invalid/")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000); QString s = toPlainTextSync(page.data()); QVERIFY(s.contains("foobarbaz") == !enableErrorPage); @@ -4037,50 +4078,6 @@ void tst_QWebEnginePage::setZoomFactor() QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); } -void tst_QWebEnginePage::printToPdf() -{ -#if !defined(QWEBENGINEPAGE_PDFPRINTINGENABLED) - QSKIP("QWEBENGINEPAGE_PDFPRINTINGENABLED"); -#else - QTemporaryDir tempDir(QDir::tempPath() + "/tst_qwebengineview-XXXXXX"); - QVERIFY(tempDir.isValid()); - QWebEnginePage page; - QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); - page.load(QUrl("qrc:///resources/basic_printing_page.html")); - QTRY_VERIFY(spy.count() == 1); - - QSignalSpy savePdfSpy(&page, SIGNAL(pdfPrintingFinished(const QString&, bool))); - QPageLayout layout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF(0.0, 0.0, 0.0, 0.0)); - QString path = tempDir.path() + "/print_1_success.pdf"; - page.printToPdf(path, layout); - QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); - - QList<QVariant> successArguments = savePdfSpy.takeFirst(); - QVERIFY2(successArguments.at(0).toString() == path, "File path for first saved PDF does not match arguments"); - QVERIFY2(successArguments.at(1).toBool() == true, "Printing to PDF file failed though it should succeed"); - -#if !defined(Q_OS_WIN) - path = tempDir.path() + "/print_//2_failed.pdf"; -#else - path = tempDir.path() + "/print_|2_failed.pdf"; -#endif - page.printToPdf(path, QPageLayout()); - QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); - - QList<QVariant> failedArguments = savePdfSpy.takeFirst(); - QVERIFY2(failedArguments.at(0).toString() == path, "File path for second saved PDF does not match arguments"); - QVERIFY2(failedArguments.at(1).toBool() == false, "Printing to PDF file succeeded though it should fail"); - - CallbackSpy<QByteArray> successfulSpy; - page.printToPdf(successfulSpy.ref(), layout); - QVERIFY(successfulSpy.waitForResult().length() > 0); - - CallbackSpy<QByteArray> failedInvalidLayoutSpy; - page.printToPdf(failedInvalidLayoutSpy.ref(), QPageLayout()); - QCOMPARE(failedInvalidLayoutSpy.waitForResult().length(), 0); -#endif -} - void tst_QWebEnginePage::mouseButtonTranslation() { QWebEngineView view; @@ -4453,6 +4450,15 @@ void tst_QWebEnginePage::triggerActionWithoutMenu() page.triggerAction(QWebEnginePage::DownloadLinkToDisk); } +void tst_QWebEnginePage::dynamicFrame() +{ + QWebEnginePage page; + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + page.load(QStringLiteral("qrc:/resources/dynamicFrame.html")); + QVERIFY(spy.wait()); + QCOMPARE(toPlainTextSync(&page).trimmed(), QStringLiteral("foo")); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc index fc83aefa5..3bb88cbe1 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc @@ -1,7 +1,7 @@ <!DOCTYPE RCC><RCC version="1.0"> <qresource> - <file>resources/basic_printing_page.html</file> <file>resources/content.html</file> + <file>resources/dynamicFrame.html</file> <file>resources/index.html</file> <file>resources/frame_a.html</file> <file>resources/frame_c.html</file> diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index 3415b06c5..1fe0f0304 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -227,12 +227,6 @@ public: setOpenMode(QIODevice::ReadOnly); m_timer.start(100, this); } - void close() override - { - QMutexLocker lock(&m_mutex); - QIODevice::close(); - deleteLater(); - } bool isSequential() const override { return true; } qint64 bytesAvailable() const override { @@ -293,7 +287,7 @@ public: void requestStarted(QWebEngineUrlRequestJob *job) { - job->reply("text/plain;charset=utf-8", new StreamingIODevice(this)); + job->reply("text/plain;charset=utf-8", new StreamingIODevice(job)); } }; diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index 23d31a478..f4e1baa33 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -18,14 +18,16 @@ */ #include <QtTest/QtTest> - +#include <QtWebEngineCore/qtwebenginecore-config.h> #include <qwebenginepage.h> #include <qwebengineprofile.h> #include <qwebenginescript.h> #include <qwebenginescriptcollection.h> #include <qwebengineview.h> #include "../util.h" +#if QT_CONFIG(webengine_webchannel) #include <QWebChannel> +#endif class tst_QWebEngineScript: public QObject { Q_OBJECT @@ -35,14 +37,16 @@ private Q_SLOTS: void loadEvents(); void scriptWorld(); void scriptModifications(); +#if QT_CONFIG(webengine_webchannel) void webChannel_data(); void webChannel(); - void noTransportWithoutWebChannel(); - void scriptsInNestedIframes(); void webChannelResettingAndUnsetting(); void webChannelWithExistingQtObject(); void navigation(); void webChannelWithBadString(); +#endif + void noTransportWithoutWebChannel(); + void scriptsInNestedIframes(); }; void tst_QWebEngineScript::domEditing() @@ -273,7 +277,7 @@ static QWebEngineScript webChannelScript() script.setWorldId(QWebEngineScript::MainWorld); return script; } - +#if QT_CONFIG(webengine_webchannel) void tst_QWebEngineScript::webChannel_data() { QTest::addColumn<int>("worldId"); @@ -318,7 +322,7 @@ void tst_QWebEngineScript::webChannel() if (worldId != QWebEngineScript::MainWorld) QCOMPARE(evaluateJavaScriptSync(&page, "qt.webChannelTransport"), QVariant(QVariant::Invalid)); } - +#endif void tst_QWebEngineScript::noTransportWithoutWebChannel() { QWebEnginePage page; @@ -382,7 +386,7 @@ void tst_QWebEngineScript::scriptsInNestedIframes() QWebEngineScript::ApplicationWorld), QVariant::fromValue(QStringLiteral("Modified Inner text"))); } - +#if QT_CONFIG(webengine_webchannel) void tst_QWebEngineScript::webChannelResettingAndUnsetting() { QWebEnginePage page; @@ -485,7 +489,7 @@ void tst_QWebEngineScript::webChannelWithBadString() QVERIFY(hostSpy.wait(20000)); QCOMPARE(host.text(), QString(QChar(QChar::ReplacementCharacter))); } - +#endif QTEST_MAIN(tst_QWebEngineScript) #include "tst_qwebenginescript.moc" diff --git a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp index 150b3c554..0704cf383 100644 --- a/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp +++ b/tests/auto/widgets/qwebenginesettings/tst_qwebenginesettings.cpp @@ -42,8 +42,6 @@ private Q_SLOTS: void tst_QWebEngineSettings::resetAttributes() { - // QT_TODO_FIXME_ADAPT - QSKIP("The application deadlocks and hangs without exiting."); QWebEngineProfile profile; QWebEngineSettings *settings = profile.settings(); @@ -85,8 +83,6 @@ void tst_QWebEngineSettings::defaultFontFamily_data() void tst_QWebEngineSettings::defaultFontFamily() { - // QT_TODO_FIXME_ADAPT - QSKIP("The application deadlocks and hangs without exiting."); QWebEngineProfile profile; QWebEngineSettings *settings = profile.settings(); @@ -151,8 +147,8 @@ void tst_QWebEngineSettings::javascriptClipboard() QCOMPARE(evaluateJavaScriptSync(&page, "document.queryCommandEnabled('copy')").toBool(), copyResult); QCOMPARE(evaluateJavaScriptSync(&page, "document.execCommand('copy')").toBool(), copyResult); - QCOMPARE(QApplication::clipboard()->text(), - (copyResult ? QString("OriginalText") : QString())); + QTRY_COMPARE(QApplication::clipboard()->text(), + (copyResult ? QString("OriginalText") : QString())); QGuiApplication::clipboard()->setText("AnotherText"); diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index fad71a517..d01a5365f 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -186,6 +186,7 @@ private Q_SLOTS: void contextMenu(); void webUIURLs_data(); void webUIURLs(); + void visibilityState(); }; // This will be called before the first test function is executed. @@ -306,11 +307,13 @@ class WebViewCrashTest : public QObject { QWebEngineView* m_view; public: bool m_invokedStop; + bool m_stopBypassed; WebViewCrashTest(QWebEngineView* view) : m_view(view) , m_invokedStop(false) + , m_stopBypassed(false) { view->connect(view, SIGNAL(loadProgress(int)), this, SLOT(loading(int))); } @@ -323,6 +326,8 @@ private Q_SLOTS: QVERIFY(!m_invokedStop); m_view->stop(); m_invokedStop = true; + } else if (!m_invokedStop && progress == 100) { + m_stopBypassed = true; } } }; @@ -340,7 +345,10 @@ void tst_QWebEngineView::crashTests() // If the verification fails, it means that either stopping doesn't work, or the hardware is // too slow to load the page and thus to slow to issue the first loadProgress > 0 signal. - QTRY_VERIFY_WITH_TIMEOUT(tester.m_invokedStop, 10000); + QTRY_VERIFY_WITH_TIMEOUT(tester.m_invokedStop || tester.m_stopBypassed, 10000); + if (tester.m_stopBypassed) + QEXPECT_FAIL("", "Loading was too fast to stop", Continue); + QVERIFY(tester.m_invokedStop); } void tst_QWebEngineView::microFocusCoordinates() @@ -1069,7 +1077,7 @@ void tst_QWebEngineView::changeLocale() QWebEngineView viewDE; QSignalSpy loadFinishedSpyDE(&viewDE, SIGNAL(loadFinished(bool))); viewDE.load(url); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000); QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty()); errorLines = toPlainTextSync(viewDE.page()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); @@ -1079,7 +1087,7 @@ void tst_QWebEngineView::changeLocale() QWebEngineView viewEN; QSignalSpy loadFinishedSpyEN(&viewEN, SIGNAL(loadFinished(bool))); viewEN.load(url); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyEN.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyEN.count(), 1, 20000); QTRY_VERIFY(!toPlainTextSync(viewEN.page()).isEmpty()); errorLines = toPlainTextSync(viewEN.page()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); @@ -1092,7 +1100,7 @@ void tst_QWebEngineView::changeLocale() // Check whether an existing QWebEngineView keeps the language settings after changing the default locale viewDE.load(url); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000); QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty()); errorLines = toPlainTextSync(viewDE.page()).split(QRegExp("[\r\n]"), QString::SkipEmptyParts); @@ -1258,60 +1266,55 @@ void tst_QWebEngineView::keyboardEvents() QVERIFY(loadFinishedSpy.wait()); } -void tst_QWebEngineView::keyboardFocusAfterPopup() -{ - QScopedPointer<QWidget> containerWidget(new QWidget); - - QLineEdit *urlLine = new QLineEdit(containerWidget.data()); - QStringList urlList; - urlList << "test"; - QCompleter *completer = new QCompleter(urlList, urlLine); - completer->setCompletionMode(QCompleter::PopupCompletion); - urlLine->setCompleter(completer); - urlLine->setFocus(); - - QWebEngineView *webView = new QWebEngineView(containerWidget.data()); - webView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); - QSignalSpy loadFinishedSpy(webView, SIGNAL(loadFinished(bool))); - - connect(urlLine, &QLineEdit::editingFinished, [=] { - webView->setHtml("<html><body onload=\"document.getElementById('input1').focus()\">" - " <input type='text' id='input1' />" - "</body></html>"); - - // Check whether the RenderWidgetHostView has the keyboard focus - QQuickWidget *rwhv = qobject_cast<QQuickWidget *>(webView->focusProxy()); - QVERIFY(rwhv); - QVERIFY(rwhv->hasFocus()); - QVERIFY(rwhv->rootObject()->hasFocus()); - QVERIFY(rwhv->window()->windowHandle()->isActive()); - QVERIFY(rwhv->rootObject()->hasActiveFocus()); - }); - +class WebViewWithUrlBar : public QWidget { +public: + QLineEdit *lineEdit = new QLineEdit; + QCompleter *urlCompleter = new QCompleter({ QStringLiteral("test") }, lineEdit); + QWebEngineView *webView = new QWebEngineView; QVBoxLayout *layout = new QVBoxLayout; - layout->addWidget(urlLine); - layout->addWidget(webView); - containerWidget->setLayout(layout); - containerWidget->show(); - QVERIFY(QTest::qWaitForWindowExposed(containerWidget.data())); - - // Trigger completer's popup and select the first suggestion - QTest::keyClick(urlLine, Qt::Key_T); - qApp->processEvents(); - QTRY_VERIFY(qApp->activePopupWidget()); - QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Down); - qApp->processEvents(); - QTest::keyClick(qApp->activePopupWidget(), Qt::Key_Enter); - qApp->processEvents(); + WebViewWithUrlBar() + { + resize(500, 500); + setLayout(layout); + layout->addWidget(lineEdit); + layout->addWidget(webView); + lineEdit->setCompleter(urlCompleter); + lineEdit->setFocus(); + } +}; - // After the load the focused window should forward the keyboard events to the webView - QVERIFY(loadFinishedSpy.wait()); - // Wait for active focus on the input field - QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.activeElement.id").toString(), QStringLiteral("input1")); - QTest::keyClick(qApp->focusWindow(), Qt::Key_X); - qApp->processEvents(); - QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').value").toString(), QStringLiteral("x")); +void tst_QWebEngineView::keyboardFocusAfterPopup() +{ + const QString html = QStringLiteral( + "<html>" + " <body onload=\"document.getElementById('input1').focus()\">" + " <input id=input1 type=text/>" + " </body>" + "</html>"); + WebViewWithUrlBar window; + QSignalSpy loadFinishedSpy(window.webView, &QWebEngineView::loadFinished); + connect(window.lineEdit, &QLineEdit::editingFinished, [&] { window.webView->setHtml(html); }); + window.webView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + window.show(); + + // Focus will initially go to the QLineEdit. + QTRY_COMPARE(QApplication::focusWidget(), window.lineEdit); + + // Trigger QCompleter's popup and select the first suggestion. + QTest::keyClick(QApplication::focusWindow(), Qt::Key_T); + QTRY_VERIFY(QApplication::activePopupWidget()); + QTest::keyClick(QApplication::focusWindow(), Qt::Key_Down); + QTest::keyClick(QApplication::focusWindow(), Qt::Key_Enter); + + // Due to FocusOnNavigationEnabled, focus should now move to the webView. + QTRY_COMPARE(QApplication::focusWidget(), window.webView->focusProxy()); + + // Keyboard events sent to the window should go to the <input> element. + QVERIFY(loadFinishedSpy.count() || loadFinishedSpy.wait()); + QTest::keyClick(QApplication::focusWindow(), Qt::Key_X); + QTRY_COMPARE(evaluateJavaScriptSync(window.webView->page(), "document.getElementById('input1').value").toString(), + QStringLiteral("x")); } void tst_QWebEngineView::mouseClick() @@ -1680,6 +1683,7 @@ void tst_QWebEngineView::softwareInputPanel() void tst_QWebEngineView::inputMethods() { QWebEngineView view; + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); view.resize(640, 480); view.show(); @@ -1777,6 +1781,7 @@ void tst_QWebEngineView::inputMethods() void tst_QWebEngineView::textSelectionInInputField() { QWebEngineView view; + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); view.resize(640, 480); view.show(); @@ -1969,6 +1974,7 @@ void tst_QWebEngineView::hiddenText() void tst_QWebEngineView::emptyInputMethodEvent() { QWebEngineView view; + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); view.resize(640, 480); view.show(); @@ -2016,6 +2022,7 @@ void tst_QWebEngineView::emptyInputMethodEvent() void tst_QWebEngineView::imeComposition() { QWebEngineView view; + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); view.resize(640, 480); view.show(); @@ -2191,6 +2198,7 @@ void tst_QWebEngineView::imeComposition() void tst_QWebEngineView::newlineInTextarea() { QWebEngineView view; + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); view.resize(640, 480); view.show(); @@ -2729,7 +2737,6 @@ void tst_QWebEngineView::webUIURLs_data() QTest::newRow("usb-internals") << QUrl("chrome://usb-internals") << false; QTest::newRow("user-actions") << QUrl("chrome://user-actions") << false; QTest::newRow("version") << QUrl("chrome://version") << false; - QTest::newRow("view-http-cache") << QUrl("chrome://view-http-cache") << true; QTest::newRow("webrtc-internals") << QUrl("chrome://webrtc-internals") << true; QTest::newRow("webrtc-logs") << QUrl("chrome://webrtc-logs") << false; } @@ -2747,5 +2754,18 @@ void tst_QWebEngineView::webUIURLs() QCOMPARE(loadFinishedSpy.takeFirst().at(0).toBool(), supported); } +void tst_QWebEngineView::visibilityState() +{ + QWebEngineView view; + QSignalSpy spy(&view, &QWebEngineView::loadFinished); + view.load(QStringLiteral("about:blank")); + QVERIFY(spy.count() || spy.wait()); + QVERIFY(spy.takeFirst().takeFirst().toBool()); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.visibilityState").toString(), QStringLiteral("hidden")); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QCOMPARE(evaluateJavaScriptSync(view.page(), "document.visibilityState").toString(), QStringLiteral("visible")); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" diff --git a/tests/auto/widgets/qwebengineschemes/BLACKLIST b/tests/auto/widgets/schemes/BLACKLIST index e69de29bb..e69de29bb 100644 --- a/tests/auto/widgets/qwebengineschemes/BLACKLIST +++ b/tests/auto/widgets/schemes/BLACKLIST diff --git a/tests/auto/widgets/qwebengineschemes/qwebengineschemes.pro b/tests/auto/widgets/schemes/schemes.pro index e56bbe8f7..e56bbe8f7 100644 --- a/tests/auto/widgets/qwebengineschemes/qwebengineschemes.pro +++ b/tests/auto/widgets/schemes/schemes.pro diff --git a/tests/auto/widgets/qwebengineschemes/tst_qwebengineschemes.cpp b/tests/auto/widgets/schemes/tst_schemes.cpp index 9381b3930..2097120ef 100644 --- a/tests/auto/widgets/qwebengineschemes/tst_qwebengineschemes.cpp +++ b/tests/auto/widgets/schemes/tst_schemes.cpp @@ -33,7 +33,7 @@ #include <qwebengineprofile.h> #include <qwebenginesettings.h> -class tst_QWebEngineSchemes : public QObject +class tst_Schemes : public QObject { Q_OBJECT @@ -58,7 +58,7 @@ public: } }; -void tst_QWebEngineSchemes::unknownUrlSchemePolicy() +void tst_Schemes::unknownUrlSchemePolicy() { QWebEngineView view; AcceptNavigationRequestHandler page; @@ -109,5 +109,5 @@ void tst_QWebEngineSchemes::unknownUrlSchemePolicy() } } -QTEST_MAIN(tst_QWebEngineSchemes) -#include "tst_qwebengineschemes.moc" +QTEST_MAIN(tst_Schemes) +#include "tst_schemes.moc" diff --git a/tests/auto/widgets/shutdown/shutdown.pro b/tests/auto/widgets/shutdown/shutdown.pro new file mode 100644 index 000000000..e99c7f493 --- /dev/null +++ b/tests/auto/widgets/shutdown/shutdown.pro @@ -0,0 +1 @@ +include(../tests.pri) diff --git a/tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp b/tests/auto/widgets/shutdown/tst_shutdown.cpp index d757e0d60..5c1e426d2 100644 --- a/tests/auto/widgets/qwebengineshutdown/tst_qwebengineshutdown.cpp +++ b/tests/auto/widgets/shutdown/tst_shutdown.cpp @@ -44,13 +44,13 @@ #include <qwebengineview.h> #include <QDebug> -class tst_QWebEngineShutdown : public QObject +class tst_Shutdown : public QObject { Q_OBJECT public: - tst_QWebEngineShutdown(); - virtual ~tst_QWebEngineShutdown(); + tst_Shutdown(); + virtual ~tst_Shutdown(); public Q_SLOTS: void init(); @@ -67,29 +67,29 @@ private: QWebEnginePage* m_page; }; -tst_QWebEngineShutdown::tst_QWebEngineShutdown() +tst_Shutdown::tst_Shutdown() { } -tst_QWebEngineShutdown::~tst_QWebEngineShutdown() +tst_Shutdown::~tst_Shutdown() { } -void tst_QWebEngineShutdown::init() +void tst_Shutdown::init() { m_view = new QWebEngineView(); m_page = m_view->page(); } -void tst_QWebEngineShutdown::cleanup() +void tst_Shutdown::cleanup() { delete m_view; } -void tst_QWebEngineShutdown::dummyTest() +void tst_Shutdown::dummyTest() { QVERIFY(m_view); } -QTEST_MAIN(tst_QWebEngineShutdown) -#include "tst_qwebengineshutdown.moc" +QTEST_MAIN(tst_Shutdown) +#include "tst_shutdown.moc" diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.aff b/tests/auto/widgets/spellchecking/dict/de-DE.aff index ff8185771..ff8185771 100644 --- a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.aff +++ b/tests/auto/widgets/spellchecking/dict/de-DE.aff diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic b/tests/auto/widgets/spellchecking/dict/de-DE.dic index a57ab15b4..a57ab15b4 100644 --- a/tests/auto/widgets/qwebenginespellcheck/dict/de-DE.dic +++ b/tests/auto/widgets/spellchecking/dict/de-DE.dic diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.aff b/tests/auto/widgets/spellchecking/dict/en-US.aff index ff8185771..ff8185771 100644 --- a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.aff +++ b/tests/auto/widgets/spellchecking/dict/en-US.aff diff --git a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic b/tests/auto/widgets/spellchecking/dict/en-US.dic index 63e9164cc..63e9164cc 100644 --- a/tests/auto/widgets/qwebenginespellcheck/dict/en-US.dic +++ b/tests/auto/widgets/spellchecking/dict/en-US.dic diff --git a/tests/auto/widgets/qwebenginespellcheck/resources/index.html b/tests/auto/widgets/spellchecking/resources/index.html index 520979244..520979244 100644 --- a/tests/auto/widgets/qwebenginespellcheck/resources/index.html +++ b/tests/auto/widgets/spellchecking/resources/index.html diff --git a/tests/auto/widgets/qwebenginespellcheck/qwebenginespellcheck.pro b/tests/auto/widgets/spellchecking/spellchecking.pro index a36c82e20..a36c82e20 100644 --- a/tests/auto/widgets/qwebenginespellcheck/qwebenginespellcheck.pro +++ b/tests/auto/widgets/spellchecking/spellchecking.pro diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp index 0dec6d72f..b6582083d 100644 --- a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.cpp +++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp @@ -65,7 +65,7 @@ private: QWebEngineContextMenuData m_data; }; -class tst_QWebEngineSpellcheck : public QObject +class tst_Spellchecking : public QObject { Q_OBJECT @@ -84,7 +84,7 @@ private: WebView *m_view; }; -void tst_QWebEngineSpellcheck::initTestCase() +void tst_Spellchecking::initTestCase() { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); QVERIFY(profile); @@ -92,7 +92,7 @@ void tst_QWebEngineSpellcheck::initTestCase() QVERIFY(profile->spellCheckLanguages().isEmpty()); } -void tst_QWebEngineSpellcheck::init() +void tst_Spellchecking::init() { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); profile->setSpellCheckEnabled(false); @@ -100,7 +100,7 @@ void tst_QWebEngineSpellcheck::init() m_view = new WebView(); } -void tst_QWebEngineSpellcheck::load() +void tst_Spellchecking::load() { m_view->page()->load(QUrl("qrc:///resources/index.html")); m_view->show(); @@ -109,12 +109,12 @@ void tst_QWebEngineSpellcheck::load() } -void tst_QWebEngineSpellcheck::cleanup() +void tst_Spellchecking::cleanup() { delete m_view; } -void tst_QWebEngineSpellcheck::spellCheckLanguage() +void tst_Spellchecking::spellCheckLanguage() { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); QVERIFY(profile); @@ -122,7 +122,7 @@ void tst_QWebEngineSpellcheck::spellCheckLanguage() QVERIFY(profile->spellCheckLanguages() == QStringList({"en-US"})); } -void tst_QWebEngineSpellcheck::spellCheckLanguages() +void tst_Spellchecking::spellCheckLanguages() { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); QVERIFY(profile); @@ -131,7 +131,7 @@ void tst_QWebEngineSpellcheck::spellCheckLanguages() } -void tst_QWebEngineSpellcheck::spellCheckEnabled() +void tst_Spellchecking::spellCheckEnabled() { QWebEngineProfile *profile = QWebEngineProfile::defaultProfile(); QVERIFY(profile); @@ -139,7 +139,7 @@ void tst_QWebEngineSpellcheck::spellCheckEnabled() QVERIFY(profile->isSpellCheckEnabled()); } -void tst_QWebEngineSpellcheck::spellcheck() +void tst_Spellchecking::spellcheck() { QFETCH(QStringList, languages); QFETCH(QStringList, suggestions); @@ -195,7 +195,7 @@ void tst_QWebEngineSpellcheck::spellcheck() QTRY_VERIFY(evaluateJavaScriptSync(m_view->page(), "text();").toString() == text); } -void tst_QWebEngineSpellcheck::spellcheck_data() +void tst_Spellchecking::spellcheck_data() { QTest::addColumn<QStringList>("languages"); QTest::addColumn<QStringList>("suggestions"); @@ -203,5 +203,5 @@ void tst_QWebEngineSpellcheck::spellcheck_data() QTest::newRow("en-US,de-DE") << QStringList({"en-US", "de-DE"}) << QStringList({"löwe", "low", "love"}); } -QTEST_MAIN(tst_QWebEngineSpellcheck) -#include "tst_qwebenginespellcheck.moc" +QTEST_MAIN(tst_Spellchecking) +#include "tst_spellchecking.moc" diff --git a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.qrc b/tests/auto/widgets/spellchecking/tst_spellchecking.qrc index 505b932c7..505b932c7 100644 --- a/tests/auto/widgets/qwebenginespellcheck/tst_qwebenginespellcheck.qrc +++ b/tests/auto/widgets/spellchecking/tst_spellchecking.qrc diff --git a/tests/auto/widgets/tests.pri b/tests/auto/widgets/tests.pri index 5e6699cf8..97954aedc 100644 --- a/tests/auto/widgets/tests.pri +++ b/tests/auto/widgets/tests.pri @@ -1,9 +1,10 @@ -QT_FOR_CONFIG += webengine-private +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 +QT_FOR_CONFIG += webenginecore-private TEMPLATE = app CONFIG += testcase -CONFIG += c++11 +CONFIG += c++14 VPATH += $$_PRO_FILE_PWD_ TARGET = tst_$$TARGET diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h index ab3b9e6b9..f27466225 100644 --- a/tests/auto/widgets/util.h +++ b/tests/auto/widgets/util.h @@ -160,9 +160,6 @@ static inline QUrl baseUrlSync(QWebEnginePage *page) #define W_QSKIP(a, b) QSKIP(a) #define W_QTEST_MAIN(TestObject, params) \ -QT_BEGIN_NAMESPACE \ -QTEST_ADD_GPU_BLACKLIST_SUPPORT_DEFS \ -QT_END_NAMESPACE \ int main(int argc, char *argv[]) \ { \ QVector<const char *> w_argv(argc); \ @@ -175,7 +172,6 @@ int main(int argc, char *argv[]) \ QApplication app(w_argc, const_cast<char **>(w_argv.data())); \ app.setAttribute(Qt::AA_Use96Dpi, true); \ QTEST_DISABLE_KEYPAD_NAVIGATION \ - QTEST_ADD_GPU_BLACKLIST_SUPPORT \ TestObject tc; \ QTEST_SET_MAIN_SOURCE_PATH \ return QTest::qExec(&tc, argc, argv); \ diff --git a/tests/auto/widgets/widgets.pro b/tests/auto/widgets/widgets.pro index 5a13e8075..05a4bfa59 100644 --- a/tests/auto/widgets/widgets.pro +++ b/tests/auto/widgets/widgets.pro @@ -1,37 +1,43 @@ -QT_FOR_CONFIG += webengine +include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri) # workaround for QTBUG-68093 +QT_FOR_CONFIG += webenginecore webenginecore-private TEMPLATE = subdirs SUBDIRS += \ + defaultsurfaceformat \ + devtools \ + faviconmanager \ + loadsignals \ origins \ - qwebenginedefaultsurfaceformat \ - qwebenginedownloads \ - qwebenginefaviconmanager \ + schemes \ + shutdown \ + qwebenginedownloaditem \ qwebenginepage \ qwebenginehistory \ - qwebengineinspector \ qwebengineprofile \ - qwebengineschemes \ qwebenginescript \ qwebenginesettings \ - qwebengineshutdown \ qwebengineview qtConfig(accessibility) { - SUBDIRS += qwebengineaccessibility + SUBDIRS += accessibility +} + +qtConfig(webengine-printing-and-pdf) { + SUBDIRS += printing } qtConfig(webengine-spellchecker):!cross_compile { !qtConfig(webengine-native-spellchecker) { - SUBDIRS += qwebenginespellcheck + SUBDIRS += spellchecking } else { message("Spellcheck test will not be built because it depends on usage of Hunspell dictionaries.") } } # QTBUG-60268 -boot2qt: SUBDIRS -= qwebengineaccessibility qwebenginedefaultsurfaceformat \ - qwebenginefaviconmanager qwebenginepage qwebenginehistory \ - qwebengineprofile qwebengineschemes qwebenginescript \ - qwebengineview qwebenginedownloads qwebenginesettings \ - origins +boot2qt: SUBDIRS -= accessibility defaultsurfaceformat devtools \ + faviconmanager qwebenginepage qwebenginehistory \ + qwebengineprofile qwebenginescript \ + qwebengineview qwebenginedownloaditem qwebenginesettings \ + schemes origins loadsignals diff --git a/tests/quicktestbrowser/main.cpp b/tests/quicktestbrowser/main.cpp index 45661b5d4..00c1ee4ad 100644 --- a/tests/quicktestbrowser/main.cpp +++ b/tests/quicktestbrowser/main.cpp @@ -47,7 +47,7 @@ static QUrl startupUrl() QUrl ret; QStringList args(qApp->arguments()); args.takeFirst(); - Q_FOREACH (const QString& arg, args) { + for (const QString &arg : qAsConst(args)) { if (arg.startsWith(QLatin1Char('-'))) continue; ret = Utils::fromUserInput(arg); |