diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-05-28 09:55:20 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-05-28 09:55:20 +0200 |
commit | 5087a4eaa32e08fe59f1f5b71dc21dda0876a759 (patch) | |
tree | 234e059dbe9226f242ca15b063952ad37e4f54da /tests/auto | |
parent | 6eadb2f2588b240b5fcda38e1f68a49a4690eb6b (diff) | |
parent | f2db8f1988a3767d4f35aa4724d4e168e80dad59 (diff) |
Merge remote-tracking branch 'origin/5.15' into dev
Change-Id: I40d9ae90a4ea82c6242f5d0a1665af3856ad2f0b
Diffstat (limited to 'tests/auto')
12 files changed, 333 insertions, 40 deletions
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html new file mode 100644 index 000000000..af44b45a2 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> + <body> + <script> + if ('serviceWorker' in navigator) { + window.addEventListener('load', function() { + navigator.serviceWorker.register('/sw.js').then(function(registration) { + console.log('ServiceWorker registration successful with scope: ', registration.scope); + }, function(err) { + console.error('ServiceWorker registration failed: ', err); + }); + }); + } + </script> + </body> +</html> diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js new file mode 100644 index 000000000..2216e2a07 --- /dev/null +++ b/tests/auto/core/qwebengineurlrequestinterceptor/resources/sw.js @@ -0,0 +1,3 @@ +self.addEventListener('install', function(event) { + console.log('ServiceWorker installed'); +}); diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index b8ecce635..350c15174 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -74,6 +74,8 @@ private Q_SLOTS: void passRefererHeader(); void initiator_data(); void initiator(); + void jsServiceWorker_data(); + void jsServiceWorker(); }; tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor() @@ -186,6 +188,58 @@ public: } }; +class TestServer : public HttpServer +{ +public: + TestServer() + { + connect(this, &HttpServer::newRequest, this, &TestServer::onNewRequest); + } + +private: + void onNewRequest(HttpReqRep *rr) + { + const QDir resourceDir(TESTS_SOURCE_DIR "qwebengineurlrequestinterceptor/resources"); + QString path = rr->requestPath(); + path.remove(0, 1); + + if (rr->requestMethod() != "GET" || !resourceDir.exists(path)) + { + rr->setResponseStatus(404); + rr->sendResponse(); + return; + } + + QFile file(resourceDir.filePath(path)); + file.open(QIODevice::ReadOnly); + QByteArray data = file.readAll(); + rr->setResponseBody(data); + QMimeDatabase db; + QMimeType mime = db.mimeTypeForFileNameAndData(file.fileName(), data); + rr->setResponseHeader(QByteArrayLiteral("content-type"), mime.name().toUtf8()); + rr->sendResponse(); + } +}; + +class ConsolePage : public QWebEnginePage { + Q_OBJECT +public: + ConsolePage(QWebEngineProfile* profile) : QWebEnginePage(profile) {} + + virtual void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID) + { + levels.append(level); + messages.append(message); + lineNumbers.append(lineNumber); + sourceIDs.append(sourceID); + } + + QList<int> levels; + QStringList messages; + QList<int> lineNumbers; + QStringList sourceIDs; +}; + void tst_QWebEngineUrlRequestInterceptor::interceptRequest_data() { QTest::addColumn<InterceptorSetter>("setter"); @@ -699,5 +753,39 @@ void tst_QWebEngineUrlRequestInterceptor::initiator() QVERIFY(interceptor.requestInitiatorUrls[info.requestUrl].contains(info.initiator)); } +void tst_QWebEngineUrlRequestInterceptor::jsServiceWorker_data() +{ + interceptRequest_data(); +} + +void tst_QWebEngineUrlRequestInterceptor::jsServiceWorker() +{ + QFETCH(InterceptorSetter, setter); + + TestServer server; + QVERIFY(server.start()); + + QWebEngineProfile profile(QStringLiteral("Test")); + std::unique_ptr<ConsolePage> page; + page.reset(new ConsolePage(&profile)); + TestRequestInterceptor interceptor(/* intercept */ false); + (profile.*setter)(&interceptor); + QVERIFY(loadSync(page.get(), server.url("/sw.html"))); + + // We expect only one message here, because logging of services workers is not exposed in our API. + QTRY_COMPARE(page->messages.count(), 1); + QCOMPARE(page->levels.at(0), QWebEnginePage::InfoMessageLevel); + + QUrl firstPartyUrl = QUrl(server.url().toString() + "sw.js"); + QList<RequestInfo> infos; + // Service Worker + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeServiceWorker); + foreach (auto info, infos) + QCOMPARE(info.firstPartyUrl, firstPartyUrl); + + QVERIFY(server.stop()); +} + QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor) #include "tst_qwebengineurlrequestinterceptor.moc" diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc index 13dbb134e..6a34635f7 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.qrc @@ -17,6 +17,8 @@ <file>resources/resource_in_iframe.html</file> <file>resources/script.js</file> <file>resources/style.css</file> + <file>resources/sw.html</file> + <file>resources/sw.js</file> <file>resources/icons/favicon.png</file> </qresource> </RCC> diff --git a/tests/auto/quick/qmltests/data/TestWebEngineView.qml b/tests/auto/quick/qmltests/data/TestWebEngineView.qml index f5e83c5d2..6db076ae8 100644 --- a/tests/auto/quick/qmltests/data/TestWebEngineView.qml +++ b/tests/auto/quick/qmltests/data/TestWebEngineView.qml @@ -111,5 +111,12 @@ WebEngineView { onWindowCloseRequested: { windowCloseRequestedSignalEmitted = true; } + + function getBodyText() { + let text + runJavaScript('document.body.innerText', function(t) { text = t }) + testCase.tryVerify(function() { return text !== undefined }) + return text + } } diff --git a/tests/auto/quick/qmltests/data/tst_certificateError.qml b/tests/auto/quick/qmltests/data/tst_certificateError.qml new file mode 100644 index 000000000..0629be175 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_certificateError.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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.9 + +import Test.Shared 1.0 as Shared + +TestWebEngineView { + id: view; width: 320; height: 320 + + property bool deferError: false + property bool acceptCertificate: false + + onCertificateError: function(error) { + if (deferError) + error.defer() + else if (acceptCertificate) + error.ignoreCertificateError() + else + error.rejectCertificate() + } + + SignalSpy { + id: spyError + target: view + signalName: 'certificateError' + } + + TestCase { + name: 'CertificateError' + when: windowShown + + function initTestCase() { + Shared.HttpsServer.setExpectError(true) + Shared.HttpsServer.newRequest.connect(function (request) { + request.setResponseBody('<html><body>Test</body></html>') + request.sendResponse() + }) + view.settings.errorPageEnabled = false + } + + function init() { + verify(Shared.HttpsServer.start()) + } + + function cleanup() { + Shared.HttpsServer.stop() + view.deferError = false + view.acceptCertificate = false + spyError.clear() + } + + function test_error_data() { + return [ + { tag: 'reject', deferError: false, acceptCertificate: false, expectedContent: '' }, + { tag: 'defer_reject', deferError: true, acceptCertificate: false, expectedContent: '' }, + { tag: 'defer_accept', deferError: true, acceptCertificate: true, expectedContent: 'Test' }, + ] + } + + function test_error(data) { + view.deferError = data.deferError + view.acceptCertificate = data.acceptCertificate + view.url = Shared.HttpsServer.url() + + if (data.deferError) { + spyError.wait() + compare(spyError.count, 1) + compare('', view.getBodyText()) + + let error = spyError.signalArguments[0][0] + if (data.acceptCertificate) + error.ignoreCertificateError() + else + error.rejectCertificate() + } + + if (data.acceptCertificate) + verify(view.waitForLoadSucceeded()) + else + verify(view.waitForLoadFailed()) + + compare(spyError.count, 1) + compare(data.expectedContent, view.getBodyText()) + } + } +} diff --git a/tests/auto/quick/qmltests/qmltests.pro b/tests/auto/quick/qmltests/qmltests.pro index 5c57f7ad9..6bec6dc0d 100644 --- a/tests/auto/quick/qmltests/qmltests.pro +++ b/tests/auto/quick/qmltests/qmltests.pro @@ -1,4 +1,5 @@ include(../tests.pri) +include(../../shared/https.pri) QT += qmltest diff --git a/tests/auto/quick/qmltests/tst_qmltests.cpp b/tests/auto/quick/qmltests/tst_qmltests.cpp index 9e8d25222..0d830931d 100644 --- a/tests/auto/quick/qmltests/tst_qmltests.cpp +++ b/tests/auto/quick/qmltests/tst_qmltests.cpp @@ -26,6 +26,8 @@ ** ****************************************************************************/ +#include <httpsserver.h> + #include <QtCore/QScopedPointer> #include <QTemporaryDir> #include <QtQuickTest/quicktest.h> @@ -144,6 +146,8 @@ int main(int argc, char **argv) QTEST_SET_MAIN_SOURCE_PATH + qmlRegisterSingletonType<HttpsServer>("Test.Shared", 1, 0, "HttpsServer", [&] (QQmlEngine *, QJSEngine *) { return new HttpsServer; }); + int i = quick_test_main(argc, argv, "qmltests", QUICK_TEST_SOURCE_DIR); return i; } diff --git a/tests/auto/quick/qmltests2/data/tst_filePicker.qml b/tests/auto/quick/qmltests2/data/tst_filePicker.qml index ffd7ef87b..ab30d9e82 100644 --- a/tests/auto/quick/qmltests2/data/tst_filePicker.qml +++ b/tests/auto/quick/qmltests2/data/tst_filePicker.qml @@ -36,6 +36,7 @@ TestWebEngineView { id: webEngineView width: 400 height: 300 + property var titleChanges: [] function driveLetter() { if (Qt.platform.os !== "windows") @@ -54,6 +55,8 @@ TestWebEngineView { signalName: "renderProcessTerminated" } + onTitleChanged: { titleChanges.push(webEngineView.title) } + TestCase { name: "WebEngineViewSingleFileUpload" when: windowShown @@ -65,6 +68,7 @@ TestWebEngineView { FilePickerParams.nameFilters = [] titleSpy.clear() terminationSpy.clear() + titleChanges = [] } function cleanup() { @@ -80,14 +84,14 @@ TestWebEngineView { function test_acceptSingleFileSelection_data() { return [ + { tag: "test.txt", input: "test.txt", expected: "Failed to Upload" }, { tag: driveLetter() + "/test.txt", input: driveLetter() + "/test.txt", expected: "test.txt" }, - { tag: driveLetter() + "test.txt", input: driveLetter() + "test.txt", expected: "Failed to Upload" }, { tag: driveLetter() + "/tést.txt", input: driveLetter() + "/tést.txt", expected: "tést.txt" }, { tag: driveLetter() + "/t%65st.txt", input: driveLetter() + "/t%65st.txt", expected: "t%65st.txt" }, { tag: "file:///" + driveLetter() + "test.txt", input: "file:///" + driveLetter() + "test.txt", expected: "test.txt" }, { tag: "file:///" + driveLetter() + "tést.txt", input: "file:///" + driveLetter() + "tést.txt", expected: "tést.txt" }, - { tag: "file:///" + driveLetter() + "t%65st.txt", input: "file:///" + driveLetter() + "t%65st.txt", expected: "test.txt" }, - { tag: "file://" + driveLetter() + "test.txt", input: "file://" + driveLetter() + "test.txt", expected: "test.txt" }, + { tag: "file:///" + driveLetter() + "t%65st.txt", input: "file:///" + driveLetter() + "t%65st.txt", expected: "t%65st.txt" }, + { tag: "file://" + driveLetter() + "test.txt", input: "file://" + driveLetter() + "test.txt", expected: "Failed to Upload" }, { tag: "file:/" + driveLetter() + "test.txt", input: "file:/" + driveLetter() + "test.txt", expected: "test.txt"}, { tag: "file:test//test.txt", input: "file:test//test.txt", expected: "Failed to Upload" }, { tag: "http://test.txt", input: "http://test.txt", expected: "Failed to Upload" }, @@ -107,7 +111,10 @@ TestWebEngineView { keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. tryCompare(FilePickerParams, "filePickerOpened", true); - tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + compare(titleChanges[titleChanges.length-2], row.expected); // Custom dialog @@ -125,7 +132,10 @@ TestWebEngineView { keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. tryVerify(function() { return finished; }); - tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + compare(titleChanges[titleChanges.length-2], row.expected); webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); } @@ -212,19 +222,19 @@ TestWebEngineView { { tag: "C:/test.txt", input: "C:/test.txt", expected: "test.txt"}, { tag: "C:\\test.txt", input: "C:\\test.txt", expected: "test.txt"}, { tag: "C:\\Documents and Settings\\test\\test.txt", input: "C:\\Documents and Settings\\test\\test.txt", expected: "test.txt"}, - { tag: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"}, - { tag: "file://applib/products/a%2Db/ abc%5F9/t.est/test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"}, + { tag: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", input: "\\\\applib\\products\\a%2Db\\ abc%5F9\\t.est\\test.txt", expected: "test.txt"}, + { tag: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", input: "file://applib/products/a%2Db/ abc%5F9/4148.920a/media/test.txt", expected: "test.txt"}, { tag: "file://applib/products/a-b/abc_1/t.est/test.txt", input: "file://applib/products/a-b/abc_1/t.est/test.txt", expected: "test.txt"}, { tag: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", input: "file:\\\\applib\\products\\a-b\\abc_1\\t:est\\test.txt", expected: "test.txt"}, - { tag: "file:C:/test.txt", input: "file:C:/test.txt", expected: "Failed to Upload"}, - { tag: "file:/C:/test.txt", input: "file:/C:/test.txt", expected: "Failed to Upload"}, + { tag: "file:C:/test.txt", input: "file:C:/test.txt", expected: "test.tx"}, + { tag: "file:/C:/test.txt", input: "file:/C:/test.txt", expected: "test.tx"}, { tag: "file://C:/test.txt", input: "file://C:/test.txt", expected: "Failed to Upload"}, { tag: "file:///C:test.txt", input: "file:///C:test.txt", expected: "Failed to Upload"}, { tag: "file:///C:/test.txt", input: "file:///C:/test.txt", expected: "test.txt"}, { tag: "file:///C:\\test.txt", input: "file:///C:\\test.txt", expected: "test.txt"}, { tag: "file:\\//C:/test.txt", input: "file:\\//C:/test.txt", expected: "test.txt"}, { tag: "file:\\\\/C:\\test.txt", input: "file:\\\\/C:\\test.txt", expected: "test.txt"}, - { tag: "\\\\?\\C:/test.txt", input: "\\\\?\\C:/test.txt", expected: "Failed to Upload"}, + { tag: "\\\\?\\C:/test.txt", input: "\\\\?\\C:/test.txt", expected: "test.tx"}, ]; } @@ -241,7 +251,10 @@ TestWebEngineView { keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. tryCompare(FilePickerParams, "filePickerOpened", true); - tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + compare(titleChanges[titleChanges.length-2], row.expected); // Custom dialog @@ -259,7 +272,10 @@ TestWebEngineView { keyClick(Qt.Key_Enter); // Focus is on the button. Open FileDialog. tryVerify(function() { return finished; }); - tryCompare(webEngineView, "title", row.expected); + webEngineView.url = Qt.resolvedUrl("about:blank"); + verify(webEngineView.waitForLoadSucceeded()); + tryCompare(webEngineView, "title", "about:blank"); + compare(titleChanges[titleChanges.length-2], row.expected); webEngineView.fileDialogRequested.disconnect(acceptedFileHandler); } diff --git a/tests/auto/shared/httpreqrep.h b/tests/auto/shared/httpreqrep.h index bee8119eb..1666b17d0 100644 --- a/tests/auto/shared/httpreqrep.h +++ b/tests/auto/shared/httpreqrep.h @@ -40,7 +40,7 @@ class HttpReqRep : public QObject public: explicit HttpReqRep(QTcpSocket *socket, QObject *parent = nullptr); - void sendResponse(); + Q_INVOKABLE void sendResponse(); void close(); // Request parameters (only valid after requestReceived()) @@ -61,7 +61,7 @@ public: m_responseHeaders[key.toLower()] = std::move(value); } QByteArray responseBody() const { return m_responseBody; } - void setResponseBody(QByteArray content) + Q_INVOKABLE void setResponseBody(QByteArray content) { m_responseHeaders["content-length"] = QByteArray::number(content.size()); m_responseBody = std::move(content); diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index 55d8ac6e8..39948c211 100644 --- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -1016,8 +1016,10 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() QRegularExpressionMatch match = fileNameCheck.match(downloadedFilePath); QVERIFY(match.hasMatch()); // ISO 8601 Date and time in UTC - QRegExp timestamp("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9])([0-5][0-9])([0-5][0-9])([.][0-9]+)?(Z|[+-](?:2[0-3]|[01][0-9])[0-5][0-9])?$"); - QVERIFY(timestamp.exactMatch(match.captured(1))); + QRegularExpression timestamp("^(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[" + "12][0-9])T(2[0-3]|[01][0-9])([0-5][0-9])([0-5][0-9])([.][0-9]" + "+)?(Z|[+-](?:2[0-3]|[01][0-9])[0-5][0-9])?$"); + QVERIFY(timestamp.match(match.captured(1)).hasMatch()); QCOMPARE(suggestedFileName, fileName); } } diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 190758ed2..7bd540cc6 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -200,11 +200,10 @@ private Q_SLOTS: void triggerActionWithoutMenu(); void dynamicFrame(); - void notificationRequest_data(); - void notificationRequest(); + void notificationPermission_data(); + void notificationPermission(); void sendNotification(); void contentsSize(); - void notificationPermission(); void setLifecycleState(); void setVisible(); @@ -229,6 +228,7 @@ private Q_SLOTS: void renderProcessPid(); void backgroundColor(); void audioMuted(); + void closeContents(); private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); @@ -3575,42 +3575,61 @@ public: } }; -void tst_QWebEnginePage::notificationRequest_data() +void tst_QWebEnginePage::notificationPermission_data() { + QTest::addColumn<bool>("setOnInit"); QTest::addColumn<QWebEnginePage::PermissionPolicy>("policy"); QTest::addColumn<QString>("permission"); - QTest::newRow("deny") << QWebEnginePage::PermissionDeniedByUser << "denied"; - QTest::newRow("grant") << QWebEnginePage::PermissionGrantedByUser << "granted"; + QTest::newRow("denyOnInit") << true << QWebEnginePage::PermissionDeniedByUser << "denied"; + QTest::newRow("deny") << false << QWebEnginePage::PermissionDeniedByUser << "denied"; + QTest::newRow("grant") << false << QWebEnginePage::PermissionGrantedByUser << "granted"; + QTest::newRow("grantOnInit") << true << QWebEnginePage::PermissionGrantedByUser << "granted"; } -void tst_QWebEnginePage::notificationRequest() +void tst_QWebEnginePage::notificationPermission() { + QFETCH(bool, setOnInit); QFETCH(QWebEnginePage::PermissionPolicy, policy); QFETCH(QString, permission); - NotificationPage page(policy); - QVERIFY(page.spyLoad.waitForResult()); + QWebEngineProfile otr; + QWebEnginePage page(&otr, nullptr); - page.resetPermission(); - QCOMPARE(page.getPermission(), "default"); + QUrl baseUrl("https://www.example.com/somepage.html"); - page.requestPermission(); - page.spyRequest.waitForResult(); - QVERIFY(page.spyRequest.wasCalled()); + bool permissionRequested = false, errorState = false; + connect(&page, &QWebEnginePage::featurePermissionRequested, &page, [&] (const QUrl &o, QWebEnginePage::Feature f) { + if (f != QWebEnginePage::Notifications) + return; + if (permissionRequested || o != baseUrl.url(QUrl::RemoveFilename)) { + qWarning() << "Unexpected case. Can't proceed." << setOnInit << permissionRequested << o; + errorState = true; + return; + } + permissionRequested = true; + page.setFeaturePermission(o, f, policy); + }); - QCOMPARE(page.getPermission(), permission); -} + if (setOnInit) + page.setFeaturePermission(baseUrl, QWebEnginePage::Notifications, policy); -void tst_QWebEnginePage::notificationPermission() -{ - QWebEngineProfile otr; - QWebEnginePage page(&otr, nullptr); QSignalSpy spy(&page, &QWebEnginePage::loadFinished); - page.setHtml(QString("<html><body>Test</body></html>"), QUrl("https://www.example.com")); + page.setHtml(QString("<html><body>Test</body></html>"), baseUrl); QTRY_COMPARE(spy.count(), 1); - QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), QLatin1String("default")); - page.setFeaturePermission(QUrl("https://www.example.com"), QWebEnginePage::Notifications, QWebEnginePage::PermissionGrantedByUser); - QTRY_COMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), QLatin1String("granted")); + + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), setOnInit ? permission : QLatin1String("default")); + + if (!setOnInit) { + page.setFeaturePermission(baseUrl, QWebEnginePage::Notifications, policy); + QTRY_COMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), permission); + } + + auto js = QStringLiteral("var permission; Notification.requestPermission().then(p => { permission = p })"); + evaluateJavaScriptSync(&page, js); + QTRY_COMPARE(evaluateJavaScriptSync(&page, "permission").toString(), permission); + // permission is not 'remembered' from api standpoint, hence is not suppressed on explicit call from JS + QVERIFY(permissionRequested); + QVERIFY(!errorState); } void tst_QWebEnginePage::sendNotification() @@ -4608,6 +4627,27 @@ void tst_QWebEnginePage::audioMuted() QCOMPARE(spy[1][0], QVariant(false)); } +void tst_QWebEnginePage::closeContents() +{ + TestPage page; + QSignalSpy windowCreatedSpy(&page, &TestPage::windowCreated); + page.runJavaScript("var dialog = window.open('', '', 'width=100, height=100');"); + QTRY_COMPARE(windowCreatedSpy.count(), 1); + + QWebEngineView *dialogView = new QWebEngineView; + QWebEnginePage *dialogPage = page.createdWindows[0]; + dialogPage->setView(dialogView); + QCOMPARE(dialogPage->lifecycleState(), QWebEnginePage::LifecycleState::Active); + + // This should not crash. + connect(dialogPage, &QWebEnginePage::windowCloseRequested, dialogView, &QWebEngineView::close); + page.runJavaScript("dialog.close();"); + + // QWebEngineView::closeEvent() sets the life cycle state to discarded. + QTRY_COMPARE(dialogPage->lifecycleState(), QWebEnginePage::LifecycleState::Discarded); + delete dialogView; +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) |