diff options
Diffstat (limited to 'tests/auto/quick')
36 files changed, 888 insertions, 103 deletions
diff --git a/tests/auto/quick/CMakeLists.txt b/tests/auto/quick/CMakeLists.txt index d44d67d38..d2cf7c3b3 100644 --- a/tests/auto/quick/CMakeLists.txt +++ b/tests/auto/quick/CMakeLists.txt @@ -1,8 +1,14 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + add_subdirectory(dialogs) add_subdirectory(publicapi) add_subdirectory(qquickwebenginedefaultsurfaceformat) add_subdirectory(qtbug-70248) -add_subdirectory(uidelegates) +# Re-enable if QTBUG-101744 and QTBUG-103354 have been fixed. +if(NOT MACOS) + add_subdirectory(uidelegates) +endif() add_subdirectory(inspectorserver) add_subdirectory(qmltests) add_subdirectory(qquickwebengineview) diff --git a/tests/auto/quick/dialogs/CMakeLists.txt b/tests/auto/quick/dialogs/CMakeLists.txt index b7f088f0d..4d8dc853b 100644 --- a/tests/auto/quick/dialogs/CMakeLists.txt +++ b/tests/auto/quick/dialogs/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../httpserver/httpserver.cmake) include(../../util/util.cmake) diff --git a/tests/auto/quick/dialogs/tst_dialogs.cpp b/tests/auto/quick/dialogs/tst_dialogs.cpp index 086587cf4..2b861efa6 100644 --- a/tests/auto/quick/dialogs/tst_dialogs.cpp +++ b/tests/auto/quick/dialogs/tst_dialogs.cpp @@ -71,7 +71,7 @@ void tst_Dialogs::createDialog(const QLatin1String &dialog, bool &ok) m_listener->runJavaScript(trigger.arg(dialog)); QTRY_VERIFY(m_listener->ready()); QTest::mouseClick(m_window, Qt::LeftButton); - QTRY_COMPARE(dialogSpy.count(), 1); + QTRY_COMPARE(dialogSpy.size(), 1); ok = true; } @@ -96,7 +96,7 @@ void tst_Dialogs::contextMenuRequested() QTRY_COMPARE_WITH_TIMEOUT(m_listener->ready(), true, 20000); QSignalSpy dialogSpy(m_listener, &TestHandler::requestChanged); QTest::mouseClick(m_window, Qt::RightButton); - QTRY_COMPARE(dialogSpy.count(), 1); + QTRY_COMPARE(dialogSpy.size(), 1); auto dialog = qobject_cast<QWebEngineContextMenuRequest *>(m_listener->request()); QVERIFY2(dialog, "Incorrect dialog requested"); } @@ -153,7 +153,7 @@ void tst_Dialogs::authenticationDialogRequested() QSignalSpy dialogSpy(m_listener, &TestHandler::requestChanged); m_listener->load(url); - QTRY_COMPARE(dialogSpy.count(), 1); + QTRY_COMPARE(dialogSpy.size(), 1); auto *dialog = qobject_cast<QQuickWebEngineAuthenticationDialogRequest*>(m_listener->request()); QVERIFY2(dialog, "Incorrect dialog requested"); dialog->dialogReject(); @@ -197,7 +197,7 @@ void tst_Dialogs::javaScriptDialogRequested() QSignalSpy dialogSpy(m_listener, &TestHandler::requestChanged); m_listener->runJavaScript(script); - QTRY_COMPARE(dialogSpy.count(), 1); + QTRY_COMPARE(dialogSpy.size(), 1); auto *dialog = qobject_cast<QQuickWebEngineJavaScriptDialogRequest*>(m_listener->request()); QVERIFY2(dialog, "Incorrect dialog requested"); dialog->dialogReject(); diff --git a/tests/auto/quick/inspectorserver/CMakeLists.txt b/tests/auto/quick/inspectorserver/CMakeLists.txt index e2c3bb2ab..d890581b8 100644 --- a/tests/auto/quick/inspectorserver/CMakeLists.txt +++ b/tests/auto/quick/inspectorserver/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + qt_internal_add_test(tst_inspectorserver SOURCES tst_inspectorserver.cpp diff --git a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp index 6c22c5d33..a9638bee4 100644 --- a/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp +++ b/tests/auto/quick/inspectorserver/tst_inspectorserver.cpp @@ -9,6 +9,7 @@ #include <QtTest/QtTest> #include <QQuickWebEngineProfile> #include <QtWebEngineQuick/private/qquickwebengineview_p.h> +#include <QWebEnginePage> #define INSPECTOR_SERVER_PORT "23654" static const QUrl s_inspectorServerHttpBaseUrl("http://localhost:" INSPECTOR_SERVER_PORT); @@ -22,6 +23,7 @@ private Q_SLOTS: void init(); void cleanup(); + void testDevToolsId(); void testPageList(); void testRemoteDebuggingMessage(); void openRemoteDebuggingSession(); @@ -36,6 +38,7 @@ private: tst_InspectorServer::tst_InspectorServer() { + qputenv("QTWEBENGINE_CHROMIUM_FLAGS", "--remote-allow-origins=*"); qputenv("QTWEBENGINE_REMOTE_DEBUGGING", INSPECTOR_SERVER_PORT); QtWebEngineQuick::initialize(); QQuickWebEngineProfile::defaultProfile()->setOffTheRecord(true); @@ -78,7 +81,7 @@ inline QQuickWebEngineView* tst_InspectorServer::webView() const QJsonArray tst_InspectorServer::fetchPageList() const { QNetworkAccessManager qnam; - QSignalSpy spy(&qnam, &QNetworkAccessManager::finished);; + QSignalSpy spy(&qnam, &QNetworkAccessManager::finished); QNetworkRequest request(s_inspectorServerHttpBaseUrl.resolved(QUrl("json/list"))); QScopedPointer<QNetworkReply> reply(qnam.get(request)); spy.wait(); @@ -90,6 +93,21 @@ QJsonArray tst_InspectorServer::fetchPageList() const return QJsonDocument::fromJson(reply->readAll()).array(); } +void tst_InspectorServer::testDevToolsId() +{ + const QUrl testPageUrl = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() + + QLatin1String("/html/basic_page.html")); + QSignalSpy loadSpy(webView(), SIGNAL(loadingChanged(QWebEngineLoadingInfo))); + webView()->setUrl(testPageUrl); + QTRY_VERIFY_WITH_TIMEOUT(loadSpy.size() && !webView()->isLoading(), 10000); + + // Our page should be the only one in the list. + QJsonArray pageList = fetchPageList(); + QCOMPARE(pageList.size(), 1); + QCOMPARE(testPageUrl.toString(), pageList.at(0).toObject().value("url").toString()); + QCOMPARE(webView()->devToolsId(), pageList.at(0).toObject().value("id").toString()); +} + void tst_InspectorServer::testPageList() { const QUrl testPageUrl = QUrl::fromLocalFile(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath() @@ -136,7 +154,7 @@ void tst_InspectorServer::testRemoteDebuggingMessage() .arg(pageList.at(0).toObject().value("webSocketDebuggerUrl").toString()) .arg(jsExpression)); - QTRY_COMPARE(webSocketQueryWebView->title(), jsExpressionResult); + QTRY_COMPARE_WITH_TIMEOUT(webSocketQueryWebView->title(), jsExpressionResult, 10000); } void tst_InspectorServer::openRemoteDebuggingSession() @@ -160,7 +178,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_WITH_TIMEOUT(inspectorWebView->title().startsWith("DevTools -"), 30000); + QTRY_VERIFY_WITH_TIMEOUT(inspectorWebView->title().startsWith("DevTools -"), 60000); } QTEST_MAIN(tst_InspectorServer) diff --git a/tests/auto/quick/publicapi/CMakeLists.txt b/tests/auto/quick/publicapi/CMakeLists.txt index 4fa18e0b3..e345a076a 100644 --- a/tests/auto/quick/publicapi/CMakeLists.txt +++ b/tests/auto/quick/publicapi/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + qt_internal_add_test(tst_publicapi SOURCES tst_publicapi.cpp diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index 75c7cd4f7..b98e2a942 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -10,6 +10,7 @@ #include <QtTest/QtTest> #include <QtWebEngineQuick/QQuickWebEngineProfile> #include <QtWebEngineCore/QWebEngineCertificateError> +#include <QtWebEngineCore/QWebEngineDesktopMediaRequest> #include <QtWebEngineCore/QWebEngineFileSystemAccessRequest> #include <QtWebEngineCore/QWebEngineFindTextResult> #include <QtWebEngineCore/QWebEngineFullScreenRequest> @@ -23,6 +24,7 @@ #include <QtWebEngineCore/QWebEngineDownloadRequest> #include <QtWebEngineCore/QWebEngineScript> #include <QtWebEngineCore/QWebEngineLoadingInfo> +#include <QtWebEngineCore/QWebEngineWebAuthUxRequest> #include <private/qquickwebengineview_p.h> #include <private/qquickwebengineaction_p.h> #include <private/qquickwebengineclientcertificateselection_p.h> @@ -61,18 +63,24 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject * << &QQuickWebEngineTooltipRequest::staticMetaObject << &QWebEngineContextMenuRequest::staticMetaObject << &QWebEngineCertificateError::staticMetaObject + << &QWebEngineDesktopMediaRequest::staticMetaObject << &QWebEngineFileSystemAccessRequest::staticMetaObject << &QWebEngineFindTextResult::staticMetaObject << &QWebEngineLoadingInfo::staticMetaObject + << &QAbstractListModel::staticMetaObject << &QWebEngineNavigationRequest::staticMetaObject << &QWebEngineNewWindowRequest::staticMetaObject << &QWebEngineNotification::staticMetaObject << &QWebEngineQuotaRequest::staticMetaObject << &QWebEngineRegisterProtocolHandlerRequest::staticMetaObject << &QQuickWebEngineTouchSelectionMenuRequest::staticMetaObject + << &QWebEngineWebAuthUxRequest::staticMetaObject + << &QWebEngineWebAuthPinRequest::staticMetaObject ; -static QList<QMetaEnum> knownEnumNames = QList<QMetaEnum>(); +static QList<QMetaEnum> knownEnumNames = QList<QMetaEnum>() + << QWebEngineDownloadRequest::staticMetaObject.enumerator(QWebEngineDownloadRequest::staticMetaObject.indexOfEnumerator("SavePageFormat")) + ; static const QStringList hardcodedTypes = QStringList() << "QJSValue" @@ -84,7 +92,8 @@ static const QStringList hardcodedTypes = QStringList() << "QWebEngineCookieStore*" << "Qt::LayoutDirection" << "QQuickWebEngineScriptCollection*" - << "QQmlComponent*"; + << "QQmlComponent*" + << "QMultiMap<QByteArray,QByteArray>"; static const QStringList expectedAPI = QStringList() << "QQuickWebEngineAction.text --> QString" @@ -261,6 +270,11 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineTooltipRequest.text --> QString" << "QQuickWebEngineTooltipRequest.type --> QQuickWebEngineTooltipRequest::RequestType" << "QQuickWebEngineTooltipRequest.accepted --> bool" + << "QWebEngineDesktopMediaRequest.screensModel --> QAbstractListModel*" + << "QWebEngineDesktopMediaRequest.windowsModel --> QAbstractListModel*" + << "QWebEngineDesktopMediaRequest.selectScreen(QModelIndex) --> void" + << "QWebEngineDesktopMediaRequest.selectWindow(QModelIndex) --> void" + << "QWebEngineDesktopMediaRequest.cancel() --> void" << "QWebEngineFullScreenRequest.accept() --> void" << "QWebEngineFullScreenRequest.origin --> QUrl" << "QWebEngineFullScreenRequest.reject() --> void" @@ -293,6 +307,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineJavaScriptDialogRequest.title --> QString" << "QQuickWebEngineJavaScriptDialogRequest.type --> QQuickWebEngineJavaScriptDialogRequest::DialogType" << "QWebEngineLoadingInfo.errorCode --> int" + << "QWebEngineLoadingInfo.responseHeaders --> QMultiMap<QByteArray,QByteArray>" << "QWebEngineLoadingInfo.errorDomain --> QWebEngineLoadingInfo::ErrorDomain" << "QWebEngineLoadingInfo.errorString --> QString" << "QWebEngineLoadingInfo.status --> QWebEngineLoadingInfo::LoadStatus" @@ -313,6 +328,7 @@ static const QStringList expectedAPI = QStringList() << "QWebEngineNavigationRequest.action --> QWebEngineNavigationRequest::NavigationRequestAction" << "QWebEngineNavigationRequest.actionChanged() --> void" << "QWebEngineNavigationRequest.isMainFrame --> bool" + << "QWebEngineNavigationRequest.hasFormData --> bool" << "QWebEngineNavigationRequest.navigationType --> QWebEngineNavigationRequest::NavigationType" << "QWebEngineNavigationRequest.url --> QUrl" << "QWebEngineNavigationRequest.AcceptRequest --> NavigationRequestAction" @@ -344,6 +360,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineProfile.cachePath --> QString" << "QQuickWebEngineProfile.cachePathChanged() --> void" << "QQuickWebEngineProfile.clearHttpCache() --> void" + << "QQuickWebEngineProfile.clearHttpCacheCompleted() --> void" << "QQuickWebEngineProfile.downloadFinished(QQuickWebEngineDownloadRequest*) --> void" << "QQuickWebEngineProfile.downloadRequested(QQuickWebEngineDownloadRequest*) --> void" << "QQuickWebEngineProfile.downloadPath --> QString" @@ -363,6 +380,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineProfile.persistentCookiesPolicyChanged() --> void" << "QQuickWebEngineProfile.persistentStoragePath --> QString" << "QQuickWebEngineProfile.persistentStoragePathChanged() --> void" + << "QQuickWebEngineProfile.isPushServiceEnabled --> bool" + << "QQuickWebEngineProfile.pushServiceEnabledChanged() --> void" << "QQuickWebEngineProfile.spellCheckEnabled --> bool" << "QQuickWebEngineProfile.spellCheckEnabledChanged() --> void" << "QQuickWebEngineProfile.spellCheckLanguages --> QStringList" @@ -391,6 +410,10 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineSettings.dnsPrefetchEnabledChanged() --> void" << "QQuickWebEngineSettings.errorPageEnabled --> bool" << "QQuickWebEngineSettings.errorPageEnabledChanged() --> void" + << "QQuickWebEngineSettings.forceDarkMode --> bool" + << "QQuickWebEngineSettings.forceDarkModeChanged() --> void" + << "QQuickWebEngineSettings.scrollAnimatorEnabled --> bool" + << "QQuickWebEngineSettings.scrollAnimatorEnabledChanged() --> void" << "QQuickWebEngineSettings.focusOnNavigationEnabled --> bool" << "QQuickWebEngineSettings.focusOnNavigationEnabledChanged() --> void" << "QQuickWebEngineSettings.fullScreenSupportEnabled --> bool" @@ -437,6 +460,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineSettings.webGLEnabledChanged() --> void" << "QQuickWebEngineSettings.webRTCPublicInterfacesOnly --> bool" << "QQuickWebEngineSettings.webRTCPublicInterfacesOnlyChanged() --> void" + << "QQuickWebEngineSettings.readingFromCanvasEnabled --> bool" + << "QQuickWebEngineSettings.readingFromCanvasEnabledChanged() --> void" << "QQuickWebEngineSingleton.defaultProfile --> QQuickWebEngineProfile*" << "QQuickWebEngineSingleton.settings --> QQuickWebEngineSettings*" << "QQuickWebEngineSingleton.script() --> QWebEngineScript" @@ -461,7 +486,6 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.action(WebAction) --> QQuickWebEngineAction*" << "QQuickWebEngineView.A0 --> PrintedPageSizeId" << "QQuickWebEngineView.A1 --> PrintedPageSizeId" - << "QQuickWebEngineView.A10 --> PrintedPageSizeId" << "QQuickWebEngineView.A2 --> PrintedPageSizeId" << "QQuickWebEngineView.A3 --> PrintedPageSizeId" << "QQuickWebEngineView.A3Extra --> PrintedPageSizeId" @@ -475,6 +499,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.A7 --> PrintedPageSizeId" << "QQuickWebEngineView.A8 --> PrintedPageSizeId" << "QQuickWebEngineView.A9 --> PrintedPageSizeId" + << "QQuickWebEngineView.A10 --> PrintedPageSizeId" << "QQuickWebEngineView.AbnormalTerminationStatus --> RenderProcessTerminationStatus" << "QQuickWebEngineView.AlignCenter --> WebAction" << "QQuickWebEngineView.AlignJustified --> WebAction" @@ -492,7 +517,6 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.ArchE --> PrintedPageSizeId" << "QQuickWebEngineView.B0 --> PrintedPageSizeId" << "QQuickWebEngineView.B1 --> PrintedPageSizeId" - << "QQuickWebEngineView.B10 --> PrintedPageSizeId" << "QQuickWebEngineView.B2 --> PrintedPageSizeId" << "QQuickWebEngineView.B3 --> PrintedPageSizeId" << "QQuickWebEngineView.B4 --> PrintedPageSizeId" @@ -502,9 +526,13 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.B7 --> PrintedPageSizeId" << "QQuickWebEngineView.B8 --> PrintedPageSizeId" << "QQuickWebEngineView.B9 --> PrintedPageSizeId" + << "QQuickWebEngineView.B10 --> PrintedPageSizeId" << "QQuickWebEngineView.Back --> WebAction" << "QQuickWebEngineView.C5E --> PrintedPageSizeId" << "QQuickWebEngineView.CertificateErrorDomain --> ErrorDomain" + << "QQuickWebEngineView.ChangeTextDirectionLTR --> WebAction" + << "QQuickWebEngineView.ChangeTextDirectionRTL --> WebAction" + << "QQuickWebEngineView.ClipboardReadWrite --> Feature" << "QQuickWebEngineView.Comm10E --> PrintedPageSizeId" << "QQuickWebEngineView.ConnectionErrorDomain --> ErrorDomain" << "QQuickWebEngineView.Copy --> WebAction" @@ -617,11 +645,10 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.LoadStartedStatus --> LoadStatus" << "QQuickWebEngineView.LoadStoppedStatus --> LoadStatus" << "QQuickWebEngineView.LoadSucceededStatus --> LoadStatus" + << "QQuickWebEngineView.LocalFontsAccess --> Feature" << "QQuickWebEngineView.MediaAudioCapture --> Feature" << "QQuickWebEngineView.MediaAudioVideoCapture --> Feature" << "QQuickWebEngineView.MediaVideoCapture --> Feature" - << "QQuickWebEngineView.NPageSize --> PrintedPageSizeId" - << "QQuickWebEngineView.NPaperSize --> PrintedPageSizeId" << "QQuickWebEngineView.NoErrorDomain --> ErrorDomain" << "QQuickWebEngineView.Notifications --> Feature" << "QQuickWebEngineView.NoWebAction --> WebAction" @@ -661,6 +688,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.ToggleUnderline --> WebAction" << "QQuickWebEngineView.Undo --> WebAction" << "QQuickWebEngineView.Unselect --> WebAction" + << "QQuickWebEngineView.OpenLinkInNewBackgroundTab --> WebAction" << "QQuickWebEngineView.ViewSource --> WebAction" << "QQuickWebEngineView.WarningMessageLevel --> JavaScriptConsoleMessageLevel" << "QQuickWebEngineView.WebActionCount --> WebAction" @@ -680,9 +708,11 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.contentsSize --> QSizeF" << "QQuickWebEngineView.contentsSizeChanged(QSizeF) --> void" << "QQuickWebEngineView.contextMenuRequested(QWebEngineContextMenuRequest*) --> void" + << "QQuickWebEngineView.desktopMediaRequested(QWebEngineDesktopMediaRequest) --> void" + << "QQuickWebEngineView.devToolsId --> QString" << "QQuickWebEngineView.devToolsView --> QQuickWebEngineView*" << "QQuickWebEngineView.devToolsViewChanged() --> void" - << "QQuickWebEngineView.featurePermissionRequested(QUrl,Feature) --> void" + << "QQuickWebEngineView.featurePermissionRequested(QUrl,QQuickWebEngineView::Feature) --> void" << "QQuickWebEngineView.fileDialogRequested(QQuickWebEngineFileDialogRequest*) --> void" << "QQuickWebEngineView.fileSystemAccessRequested(QWebEngineFileSystemAccessRequest) --> void" << "QQuickWebEngineView.findText(QString) --> void" @@ -695,7 +725,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.goBack() --> void" << "QQuickWebEngineView.goBackOrForward(int) --> void" << "QQuickWebEngineView.goForward() --> void" - << "QQuickWebEngineView.grantFeaturePermission(QUrl,Feature,bool) --> void" + << "QQuickWebEngineView.grantFeaturePermission(QUrl,QQuickWebEngineView::Feature,bool) --> void" << "QQuickWebEngineView.history --> QWebEngineHistory*" << "QQuickWebEngineView.icon --> QUrl" << "QQuickWebEngineView.iconChanged() --> void" @@ -703,10 +733,10 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.inspectedViewChanged() --> void" << "QQuickWebEngineView.isFullScreen --> bool" << "QQuickWebEngineView.isFullScreenChanged() --> void" - << "QQuickWebEngineView.javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString) --> void" + << "QQuickWebEngineView.javaScriptConsoleMessage(QQuickWebEngineView::JavaScriptConsoleMessageLevel,QString,int,QString) --> void" << "QQuickWebEngineView.javaScriptDialogRequested(QQuickWebEngineJavaScriptDialogRequest*) --> void" << "QQuickWebEngineView.lifecycleState --> QQuickWebEngineView::LifecycleState" - << "QQuickWebEngineView.lifecycleStateChanged(LifecycleState) --> void" + << "QQuickWebEngineView.lifecycleStateChanged(QQuickWebEngineView::LifecycleState) --> void" << "QQuickWebEngineView.linkHovered(QUrl) --> void" << "QQuickWebEngineView.loadHtml(QString) --> void" << "QQuickWebEngineView.loadHtml(QString,QUrl) --> void" @@ -745,11 +775,11 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.renderProcessPid --> qlonglong" << "QQuickWebEngineView.renderProcessPidChanged(qlonglong) --> void" << "QQuickWebEngineView.recommendedState --> QQuickWebEngineView::LifecycleState" - << "QQuickWebEngineView.recommendedStateChanged(LifecycleState) --> void" + << "QQuickWebEngineView.recommendedStateChanged(QQuickWebEngineView::LifecycleState) --> void" << "QQuickWebEngineView.registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest) --> void" << "QQuickWebEngineView.reload() --> void" << "QQuickWebEngineView.reloadAndBypassCache() --> void" - << "QQuickWebEngineView.renderProcessTerminated(RenderProcessTerminationStatus,int) --> void" + << "QQuickWebEngineView.renderProcessTerminated(QQuickWebEngineView::RenderProcessTerminationStatus,int) --> void" << "QQuickWebEngineView.replaceMisspelledWord(QString) --> void" << "QQuickWebEngineView.runJavaScript(QString) --> void" << "QQuickWebEngineView.runJavaScript(QString,QJSValue) --> void" @@ -781,6 +811,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.zoomFactor --> double" << "QQuickWebEngineView.zoomFactorChanged(double) --> void" << "QQuickWebEngineView.acceptAsNewWindow(QWebEngineNewWindowRequest*) --> void" + << "QQuickWebEngineView.save(QString) --> void" + << "QQuickWebEngineView.save(QString,QWebEngineDownloadRequest::SavePageFormat) --> void" << "QWebEngineQuotaRequest.accept() --> void" << "QWebEngineQuotaRequest.origin --> QUrl" << "QWebEngineQuotaRequest.reject() --> void" @@ -799,6 +831,55 @@ static const QStringList expectedAPI = QStringList() << "QWebEngineNotification.click() --> void" << "QWebEngineNotification.close() --> void" << "QWebEngineNotification.closed() --> void" + << "QQuickWebEngineView.webAuthUxRequested(QWebEngineWebAuthUxRequest*) --> void" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.NotStarted --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.SelectAccount --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.CollectPin --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.FinishTokenCollection --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.RequestFailed --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.Cancelled --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.WebAuthUxState.Completed --> WebAuthUxState" + << "QWebEngineWebAuthUxRequest.PinEntryReason.Set --> PinEntryReason" + << "QWebEngineWebAuthUxRequest.PinEntryReason.Change --> PinEntryReason" + << "QWebEngineWebAuthUxRequest.PinEntryReason.Challenge --> PinEntryReason" + << "QWebEngineWebAuthUxRequest.PinEntryError.NoError --> PinEntryError" + << "QWebEngineWebAuthUxRequest.PinEntryError.InternalUvLocked --> PinEntryError" + << "QWebEngineWebAuthUxRequest.PinEntryError.WrongPin --> PinEntryError" + << "QWebEngineWebAuthUxRequest.PinEntryError.TooShort --> PinEntryError" + << "QWebEngineWebAuthUxRequest.PinEntryError.InvalidCharacters --> PinEntryError" + << "QWebEngineWebAuthUxRequest.PinEntryError.SameAsCurrentPin --> PinEntryError" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.Timeout --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.KeyNotRegistered --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.KeyAlreadyRegistered --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.SoftPinBlock --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.HardPinBlock --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorRemovedDuringPinEntry --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingResidentKeys --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingUserVerification --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingLargeBlob --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.NoCommonAlgorithms --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.StorageFull --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.UserConsentDenied --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.RequestFailureReason.WinUserCancelled --> RequestFailureReason" + << "QWebEngineWebAuthUxRequest.userNames --> QStringList" + << "QWebEngineWebAuthUxRequest.state --> QWebEngineWebAuthUxRequest::WebAuthUxState" + << "QWebEngineWebAuthUxRequest.relyingPartyId --> QString" + << "QWebEngineWebAuthUxRequest.pinRequest --> QWebEngineWebAuthPinRequest" + << "QWebEngineWebAuthUxRequest.requestFailureReason --> QWebEngineWebAuthUxRequest::RequestFailureReason" + << "QWebEngineWebAuthUxRequest.stateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState) --> void" + << "QWebEngineWebAuthUxRequest.cancel() --> void" + << "QWebEngineWebAuthUxRequest.retry() --> void" + << "QWebEngineWebAuthUxRequest.setSelectedAccount(QString) --> void" + << "QWebEngineWebAuthUxRequest.setPin(QString) --> void" + << "QWebEngineWebAuthPinRequest.reason --> QWebEngineWebAuthUxRequest::PinEntryReason" + << "QWebEngineWebAuthPinRequest.error --> QWebEngineWebAuthUxRequest::PinEntryError" + << "QWebEngineWebAuthPinRequest.minPinLength --> int" + << "QWebEngineWebAuthPinRequest.remainingAttempts --> int" + << "QQuickWebEngineSettings.AllowImageAnimation --> ImageAnimationPolicy" + << "QQuickWebEngineSettings.AnimateImageOnce --> ImageAnimationPolicy" + << "QQuickWebEngineSettings.DisallowImageAnimation --> ImageAnimationPolicy" + << "QQuickWebEngineSettings.imageAnimationPolicy --> QQuickWebEngineSettings::ImageAnimationPolicy" + << "QQuickWebEngineSettings.imageAnimationPolicyChanged() --> void" ; static bool isCheckedEnum(QMetaType t) @@ -892,12 +973,12 @@ void tst_publicapi::publicAPI() // Uncomment to print the actual API. // QStringList sortedAPI(actualAPI); // std::sort(sortedAPI.begin(), sortedAPI.end()); - // for (const QString &actual : qAsConst(sortedAPI)) + // for (const QString &actual : std::as_const(sortedAPI)) // printf(" << \"%s\"\n", qPrintable(actual)); bool apiMatch = true; // Make sure that nothing slips in the public API unintentionally. - for (const QString &actual : qAsConst(actualAPI)) { + for (const QString &actual : std::as_const(actualAPI)) { if (!expectedAPI.contains(actual)) { qWarning("Expected list is not up-to-date: %ls", qUtf16Printable(actual)); apiMatch = false; diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST index 2f8fa5e66..fc8f9f0d8 100644 --- a/tests/auto/quick/qmltests/BLACKLIST +++ b/tests/auto/quick/qmltests/BLACKLIST @@ -9,3 +9,4 @@ macos [CertificateError::test_error] * + diff --git a/tests/auto/quick/qmltests/CMakeLists.txt b/tests/auto/quick/qmltests/CMakeLists.txt index 53c8ed231..daae6d60d 100644 --- a/tests/auto/quick/qmltests/CMakeLists.txt +++ b/tests/auto/quick/qmltests/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../httpserver/httpserver.cmake) include(../../util/util.cmake) @@ -22,15 +25,17 @@ set(testList tst_datalist.qml tst_desktopBehaviorLoadHtml.qml tst_download.qml + tst_dragHandlerUnderView.qml tst_favicon.qml tst_faviconDatabase.qml tst_filePicker.qml + tst_filesystem.qml tst_findText.qml tst_focusOnNavigation.qml tst_fullScreenRequest.qml - tst_geopermission.qml tst_getUserMedia.qml tst_inputMethod.qml + tst_inputTextDirection.qml tst_javaScriptDialogs.qml tst_keyboardEvents.qml tst_keyboardModifierMapping.qml @@ -55,6 +60,7 @@ set(testList tst_userScripts.qml tst_userScriptCollection.qml tst_viewSource.qml + tst_save.qml ) if(QT_FEATURE_webengine_webchannel) @@ -65,6 +71,10 @@ if(QT_FEATURE_ssl) list(APPEND testList tst_certificateError.qml) endif() +if (NOT APPLE) + list(APPEND testList tst_geopermission.qml) +endif() + set(content "") foreach(test ${testList}) set(contents "${contents}${CMAKE_CURRENT_LIST_DIR}/data/${test}\n") diff --git a/tests/auto/quick/qmltests/data/TestWebEngineView.qml b/tests/auto/quick/qmltests/data/TestWebEngineView.qml index 7f8c271d0..415985471 100644 --- a/tests/auto/quick/qmltests/data/TestWebEngineView.qml +++ b/tests/auto/quick/qmltests/data/TestWebEngineView.qml @@ -40,7 +40,7 @@ WebEngineView { } function _waitFor(predicate, timeout) { if (timeout === undefined) - timeout = 12000; + timeout = 30000; var i = 0 while (i < timeout && !predicate()) { testResult.wait(50) diff --git a/tests/auto/quick/qmltests/data/filesystemapi.html b/tests/auto/quick/qmltests/data/filesystemapi.html new file mode 100644 index 000000000..ab1a33e4d --- /dev/null +++ b/tests/auto/quick/qmltests/data/filesystemapi.html @@ -0,0 +1,66 @@ +<html> +<head> +<meta name="viewport" content="width=device-width, initial-scale=1.0"> +<title> Failed to Upload </title> +</script> +</head> + +<body> +<button>Request File Picker</button> +<script> + async function handleDirectoryEntry( dirHandle, out ) { + for await (const entry of dirHandle.values()) { + if (entry.kind === "file"){ + const file = await entry.getFile(); + out[ file.name ] = file; + } + if (entry.kind === "directory") { + const newHandle = await dirHandle.getDirectoryHandle( entry.name, { create: false } ); + const newOut = out[ entry.name ] = {}; + await handleDirectoryEntry( newHandle, newOut ); + } + } + } + const button = document.querySelector('button'); + button.addEventListener('click', async function() { + switch(window.dialogType) { + case "savePicker": + const saveFileHandle = await window.showSaveFilePicker(); + const writable = await saveFileHandle.createWritable(); + await writable.write(new Blob(['TEST_CONTENT'])); + await writable.close(); + console.log("TEST:DONE") + break; + case "filePicker": + let [openFileHandle] = await window.showOpenFilePicker(); + const options = {}; + options.mode = 'readwrite' + await openFileHandle.requestPermission(options) + const file = await openFileHandle.getFile(); + const contents = await file.text(); + console.log("TEST:" + contents) + console.log("TEST:DONE") + break; + case "directoryPicker": + console.log("start") + const dirHandle = await window.showDirectoryPicker(); + for await (const entry of dirHandle.values()) { + if (entry.kind === "file"){ + continue + } + if (entry.kind === "directory") { + console.log("TEST:" + entry.name) + } + } + console.log("TEST:DONE") + break; + default: + } + }); + window.onload = function() { + window.dialogType = window.location.href.split('=')[1]; + document.querySelector('button').focus() + } +</script> +</body> +</html> diff --git a/tests/auto/quick/qmltests/data/test4.html b/tests/auto/quick/qmltests/data/test4.html index cf5708994..82830668a 100644 --- a/tests/auto/quick/qmltests/data/test4.html +++ b/tests/auto/quick/qmltests/data/test4.html @@ -9,7 +9,6 @@ font-size: 50px; } </style> - <meta name="viewport" content="initial-scale=2.0"/> </head> <body> <button onclick="scrollWin()" id="scroll">Click me to scroll!</button><br><br> diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml index abe5f71b0..9e49c2dbf 100644 --- a/tests/auto/quick/qmltests/data/tst_action.qml +++ b/tests/auto/quick/qmltests/data/tst_action.qml @@ -65,7 +65,9 @@ TestWebEngineView { { webAction: WebEngineView.Indent, text: "&Indent", iconName: "", enabled: true }, { webAction: WebEngineView.Outdent, text: "&Outdent", iconName: "", enabled: true }, { webAction: WebEngineView.InsertOrderedList, text: "Insert &Ordered List", iconName: "", enabled: true }, - { webAction: WebEngineView.InsertUnorderedList, text: "Insert &Unordered List", iconName: "", enabled: true } + { webAction: WebEngineView.InsertUnorderedList, text: "Insert &Unordered List", iconName: "", enabled: true }, + { webAction: WebEngineView.ChangeTextDirectionLTR, text: "Change text direction left to right", iconName: "", enabled: true }, + { webAction: WebEngineView.ChangeTextDirectionRTL, text: "Change text direction right to left", iconName: "", enabled: true } ]; } diff --git a/tests/auto/quick/qmltests/data/tst_datalist.qml b/tests/auto/quick/qmltests/data/tst_datalist.qml index 66cc49b0c..f739639b2 100644 --- a/tests/auto/quick/qmltests/data/tst_datalist.qml +++ b/tests/auto/quick/qmltests/data/tst_datalist.qml @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 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$ -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick import QtQuick.Controls diff --git a/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml b/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml new file mode 100644 index 000000000..c22bd44c2 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_dragHandlerUnderView.qml @@ -0,0 +1,67 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +Item { + id: parentItem + width: 400 + height: 300 + + Rectangle { + id: draggableDownUnder + color: "wheat" + width: 350 + height: 250 + + DragHandler { id: dragHandler } + } + + TestWebEngineView { + id: webEngineView + width: 300 + height: 250 + + property var testUrl: Qt.resolvedUrl("test4.html") + + SignalSpy { + id: scrollPositionSpy + target: webEngineView + signalName: "onScrollPositionChanged" + } + + SignalSpy { + id: dragActiveSpy + target: dragHandler + signalName: "activeChanged" + } + + TestCase { + id: testCase + name: "KeepMouseGrabDuringScrolling" + when: windowShown + + function test_scroll() { + webEngineView.url = Qt.resolvedUrl("test4.html"); + verify(webEngineView.waitForLoadSucceeded()); + + mousePress(webEngineView, 295, 20); + mouseMove(webEngineView, 295, 200); + mouseRelease(webEngineView, 295, 200); + + // WebEngineView scrolled if the scrollbar was visible. + // But on macOS, the scrollbar is hidden, so text gets selected. + tryVerify(function() { + return (scrollPositionSpy.count === 1 && webEngineView.scrollPosition.y > 100) + || webEngineView.getTextSelection().length > 0; + }); + + // DragHandler didn't take over and drag + compare(dragActiveSpy.count, 0); + compare(draggableDownUnder.y, 0); + } + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml b/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml index 774708af0..284390619 100644 --- a/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml +++ b/tests/auto/quick/qmltests/data/tst_faviconDatabase.qml @@ -85,6 +85,9 @@ TestWebEngineView { function test_iconDatabase(row) { + if (Screen.devicePixelRatio !== 1.0) + skip("This test is not supported on High DPI screens."); + webEngineView.profile = row.profile; compare(iconChangedSpy.count, 0); @@ -129,6 +132,9 @@ TestWebEngineView { function test_iconDatabaseMultiView() { + if (Screen.devicePixelRatio !== 1.0) + skip("This test is not supported on High DPI screens."); + var pixel; var faviconImage = Qt.createQmlObject(" diff --git a/tests/auto/quick/qmltests/data/tst_filePicker.qml b/tests/auto/quick/qmltests/data/tst_filePicker.qml index 2404efd2d..a7b59b2e9 100644 --- a/tests/auto/quick/qmltests/data/tst_filePicker.qml +++ b/tests/auto/quick/qmltests/data/tst_filePicker.qml @@ -11,7 +11,6 @@ TestWebEngineView { id: webEngineView width: 400 height: 300 - property var titleChanges: [] function driveLetter() { if (Qt.platform.os !== "windows") @@ -30,8 +29,6 @@ TestWebEngineView { signalName: "renderProcessTerminated" } - onTitleChanged: { titleChanges.push(webEngineView.title) } - TestCase { id: testCase name: "WebEngineViewSingleFileUpload" @@ -44,7 +41,6 @@ TestWebEngineView { FilePickerParams.nameFilters = [] titleSpy.clear() terminationSpy.clear() - titleChanges = [] } function cleanup() { @@ -87,10 +83,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 @@ -98,7 +94,7 @@ TestWebEngineView { function acceptedFileHandler(request) { request.accepted = true; - request.dialogAccept(row.input); + request.dialogAccept([row.input]); finished = true; } @@ -108,10 +104,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); } @@ -146,7 +142,7 @@ TestWebEngineView { FilePickerParams.selectedFilesUrl.push(Qt.resolvedUrl("../data")) keyClick(Qt.Key_Enter) // Focus is on the button. Open FileDialog. - tryCompare(FilePickerParams, "filePickerOpened", true) + tryCompare(FilePickerParams, "directoryPickerOpened", true) // Check that the title is a file list (eg. "test1.html,test2.html") tryVerify(function() { return webEngineView.title.match("^([^,]+,)+[^,]+$"); }) @@ -242,10 +238,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 @@ -253,7 +249,7 @@ TestWebEngineView { function acceptedFileHandler(request) { request.accepted = true; - request.dialogAccept(row.input); + request.dialogAccept([row.input]); finished = true; } @@ -263,10 +259,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/quick/qmltests/data/tst_filesystem.qml b/tests/auto/quick/qmltests/data/tst_filesystem.qml new file mode 100644 index 000000000..fa0da4457 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_filesystem.qml @@ -0,0 +1,124 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine +import Test.util +import "../../qmltests/data" +import "../mock-delegates/TestParams" + + +TestWebEngineView { + id: webEngineView + width: 400 + height: 300 + property var logs: [] + property bool accessRequested: false + property url file: tempDir.pathUrl('file.txt') + + onJavaScriptConsoleMessage: function(level, message, lineNumber, source) { + var pair = message.split(':'); + if (pair.length == 2 && pair[0] == "TEST") + logs.push(pair[1]); + } + + TempDir { id: tempDir } + + TestCase { + id: testCase + name: "FileSystemAPI" + when: windowShown + + function init() { + clearLog() + FilePickerParams.filePickerOpened = false + FilePickerParams.selectFiles = false + FilePickerParams.selectedFilesUrl = [] + FilePickerParams.nameFilters = [] + accessRequested = false; + } + + function cleanup() { + clearLog() + } + + function clearLog() { + logs = [] + } + + function logContainsDoneMarker() { + if (logs.indexOf("DONE") > -1) + return true + else + return false + } + + function result() { + return logs[0] + } + + function fileAccessRequest(request) { + testCase.verify(!accessRequested) + accessRequested = true + testCase.verify(request.filePath == file) + testCase.verify(request.accessFlags == WebEngineFileSystemAccessRequest.Write | WebEngineFileSystemAccessRequest.Read) + request.accept() + } + + function directoryAccessRequest(request) { + testCase.verify(!accessRequested) + accessRequested = true + testCase.verify(request.filePath == tempDir.pathUrl()) + testCase.verify(request.accessFlags == WebEngineFileSystemAccessRequest.Read) + request.accept() + } + + function test_saveFile() { + webEngineView.fileSystemAccessRequested.connect(fileAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=savePicker"); + verify(webEngineView.waitForLoadSucceeded()); + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(file); + keyClick(Qt.Key_Enter); // Open SaveDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + // write access for save dialogs is automatically granted + verify(!accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(fileAccessRequest); + } + + function test_openFile() { + // first save the file before open + test_saveFile() + init() + webEngineView.fileSystemAccessRequested.connect(fileAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=filePicker"); + verify(webEngineView.waitForLoadSucceeded()); + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(file); + keyClick(Qt.Key_Enter); // Open FileDialog. + tryCompare(FilePickerParams, "filePickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + verify(logs.indexOf("TEST_CONTENT") > -1) + verify(accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(fileAccessRequest); + } + + function test_selectDirectory() { + tempDir.createDirectory("TEST_DIR") + webEngineView.fileSystemAccessRequested.connect(directoryAccessRequest); + webEngineView.url = Qt.resolvedUrl("filesystemapi.html?dialog=directoryPicker"); + verify(webEngineView.waitForLoadSucceeded()) + FilePickerParams.selectFiles = true; + FilePickerParams.selectedFilesUrl.push(tempDir.pathUrl()); + keyClick(Qt.Key_Enter); // Open showDirectoryDialog. + tryCompare(FilePickerParams, "directoryPickerOpened", true); + tryVerify(logContainsDoneMarker,2000) + verify(logs.indexOf("TEST_DIR") > -1) + verify(accessRequested) + webEngineView.fileSystemAccessRequested.disconnect(directoryAccessRequest); + } + + } +} diff --git a/tests/auto/quick/qmltests/data/tst_findText.qml b/tests/auto/quick/qmltests/data/tst_findText.qml index 392ce5dca..597cff73e 100644 --- a/tests/auto/quick/qmltests/data/tst_findText.qml +++ b/tests/auto/quick/qmltests/data/tst_findText.qml @@ -206,8 +206,7 @@ TestWebEngineView { var listItemText = ''; for (var i = 0; i < 100000; ++i) - listItemText += "bla "; - listItemText = listItemText.trim(); + listItemText += "bla"; webEngineView.loadHtml( "<html><body>" + diff --git a/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml b/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml new file mode 100644 index 000000000..2141db4c8 --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_inputTextDirection.qml @@ -0,0 +1,43 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtTest +import QtWebEngine + +TestWebEngineView { + id: webEngineView + width: 400 + height: 400 + + TestCase { + id: testCase + name: "WebEngineInputTextDirection" + when: windowShown + + function getInputTextDirection(element) { + var dir; + runJavaScript("document.getElementById('" + element + "').dir", function(result) { + dir = result; + }); + tryVerify(function() { return dir != undefined; }); + return dir; + } + + function test_changeInputTextDirection() { + webEngineView.loadHtml("<html><body><input type='text' id='textfield' value='some text'></body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + setFocusToElement("textfield"); + + var rtlAction = webEngineView.action(WebEngineView.ChangeTextDirectionRTL); + verify(rtlAction); + rtlAction.trigger(); + compare(getInputTextDirection("textfield"), "rtl"); + + var ltrAction = webEngineView.action(WebEngineView.ChangeTextDirectionLTR); + verify(ltrAction); + ltrAction.trigger(); + compare(getInputTextDirection("textfield"), "ltr"); + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml index 6d4bdbb41..68350d107 100644 --- a/tests/auto/quick/qmltests/data/tst_newViewRequest.qml +++ b/tests/auto/quick/qmltests/data/tst_newViewRequest.qml @@ -101,8 +101,7 @@ TestWebEngineView { compare(dialog.webEngineView.url, Qt.url("about:blank")); dialog.destroy(); } - // https://chromium-review.googlesource.com/c/chromium/src/+/1300395 - compare(newViewRequest.requestedUrl, 'about:blank#blocked'); + compare(newViewRequest.requestedUrl, 'about:blank'); newViewRequestedSpy.clear(); // Open a page in a new dialog diff --git a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml index 22e427ad4..f16cd9c41 100644 --- a/tests/auto/quick/qmltests/data/tst_runJavaScript.qml +++ b/tests/auto/quick/qmltests/data/tst_runJavaScript.qml @@ -34,8 +34,7 @@ TestWebEngineView { compare(result, testTitle2); callbackCalled = true; }); - wait(100); - verify(callbackCalled); + tryVerify(function() { return callbackCalled; }); } } } diff --git a/tests/auto/quick/qmltests/data/tst_save.qml b/tests/auto/quick/qmltests/data/tst_save.qml new file mode 100644 index 000000000..3289dbd8b --- /dev/null +++ b/tests/auto/quick/qmltests/data/tst_save.qml @@ -0,0 +1,185 @@ +import QtQuick +import QtTest +import QtWebEngine +import Test.util + +TestWebEngineView { + id: webEngineView + width: 200 + height: 200 + profile: testSaveProfile + + property url downloadUrl: "" + property int totalBytes: 0 + property int receivedBytes: 0 + property string downloadDir: "" + property string downloadFileName: "" + property bool isSavePageDownload: false + property var downloadState: [] + property int savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat; + property bool autoCancel: false + + TempDir { + id: tempDir + } + + SignalSpy { + id: downLoadRequestedSpy + target: testSaveProfile + signalName: "downloadRequested" + } + + SignalSpy { + id: downloadFinishedSpy + target: testSaveProfile + signalName: "downloadFinished" + } + + WebEngineProfile { + id: testSaveProfile + + onDownloadRequested: function(download) { + downloadState.push(download.state) + downloadUrl = download.url + savePageFormat = download.savePageFormat + downloadDir = download.downloadDirectory; + downloadFileName = download.downloadFileName + isSavePageDownload = download.isSavePageDownload + + if (autoCancel) + download.cancel() + } + onDownloadFinished: function(download) { + receivedBytes = download.receivedBytes + totalBytes = download.totalBytes + downloadState.push(download.state) + } + } + + TestCase { + name: "WebEngineViewSave" + + function verifyData() { + var isDataValid = false + webEngineView.runJavaScript("(function() {" + + "var title = document.title.toString();" + + "var body = document.body.innerText;" + + " return title === \"Test page 1\" && body.includes(\"Hello.\")" + + "})();", function(result) { + isDataValid = result; + }); + tryVerify(function() { return isDataValid }); + return isDataValid; + } + + function init() { + downLoadRequestedSpy.clear() + downloadFinishedSpy.clear() + totalBytes = 0 + receivedBytes = 0 + downloadDir = "" + downloadFileName = "" + isSavePageDownload = false + downloadState = [] + downloadUrl = "" + autoCancel = false + } + + function test_savePage_data() { + return [ + { tag: "SingleHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.SingleHtmlSaveFormat }, + { tag: "CompleteHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.CompleteHtmlSaveFormat }, + { tag: "MimeHtmlSaveFormat", savePageFormat: WebEngineDownloadRequest.MimeHtmlSaveFormat }, + ]; + } + + function test_savePage(row) { + var saveFormat = row.savePageFormat + + var fileDir = tempDir.path() + var fileName = "saved_page.html" + var filePath = fileDir + "/"+ fileName + + // load data to view + webEngineView.url = Qt.resolvedUrl("test1.html") + verify(webEngineView.waitForLoadSucceeded()) + verify(verifyData()) + + webEngineView.save(filePath, saveFormat) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(savePageFormat, saveFormat) + compare(downloadDir, fileDir) + compare(downloadFileName, fileName) + compare(isSavePageDownload, true) + compare(downloadState[0], WebEngineDownloadRequest.DownloadInProgress) + downloadFinishedSpy.wait() + compare(downloadFinishedSpy.count, 1) + compare(totalBytes, receivedBytes) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCompleted) + + // load some other data + webEngineView.url = Qt.resolvedUrl("about:blank") + verify(webEngineView.waitForLoadSucceeded()) + + // load save file to view + webEngineView.url = Qt.resolvedUrl(filePath) + verify(webEngineView.waitForLoadSucceeded()) + verify(verifyData()) + } + + function test_saveImage_data() { + return [ + { tag: "Auto accept", autoCancel: false }, + { tag: "Cancel", autoCancel: true }, + ]; + } + + function test_saveImage(row) { + autoCancel = row.autoCancel + + var fileDir = tempDir.path() + var fileName = "favicon.png" + var filePath = fileDir + "/"+ fileName + + // Load an image + webEngineView.url = Qt.resolvedUrl("icons/favicon.png") + verify(webEngineView.waitForLoadSucceeded()) + + webEngineView.save(filePath) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(downloadDir, fileDir) + compare(downloadFileName, fileName) + compare(isSavePageDownload, true) + compare(downloadState[0], WebEngineDownloadRequest.DownloadInProgress) + downloadFinishedSpy.wait() + compare(downloadFinishedSpy.count, 1) + if (autoCancel) { + compare(receivedBytes, 0) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCancelled) + } else { + compare(totalBytes, receivedBytes) + compare(downloadState[1], WebEngineDownloadRequest.DownloadCompleted) + } + } + + function test_saveWebAction() { + // Load an image + webEngineView.url = Qt.resolvedUrl("icons/favicon.png") + verify(webEngineView.waitForLoadSucceeded()) + + // Saving without specifying path shouldn't be auto accepted + webEngineView.triggerWebAction(WebEngineView.SavePage) + downLoadRequestedSpy.wait() + compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(isSavePageDownload, true) + // The initial download request starts from DownloadRequested state, + // which means it wasn't automatically accepted. + compare(downloadState[0], WebEngineDownloadRequest.DownloadRequested) + } + } +} diff --git a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml index e9c72ab7d..cc7d15e4c 100644 --- a/tests/auto/quick/qmltests/data/tst_scrollPosition.qml +++ b/tests/auto/quick/qmltests/data/tst_scrollPosition.qml @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick -import QtQuick.Window import QtTest import QtWebEngine @@ -36,7 +35,7 @@ TestWebEngineView { tryCompare(scrollPositionSpy, "count", 1); compare(webEngineView.scrollPosition.x, 0); - compare(webEngineView.scrollPosition.y, 600 * Screen.devicePixelRatio); + compare(webEngineView.scrollPosition.y, 600); } function test_scrollPositionAfterReload() { @@ -49,13 +48,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 * Screen.devicePixelRatio); + tryCompare(webEngineView.scrollPosition, "y", 600); webEngineView.reload(); verify(webEngineView.waitForLoadSucceeded()); tryCompare(webEngineView.scrollPosition, "x", 0); - tryCompare(webEngineView.scrollPosition, "y", 600 * Screen.devicePixelRatio); + tryCompare(webEngineView.scrollPosition, "y", 600); } } } diff --git a/tests/auto/quick/qmltests/data/tst_settings.qml b/tests/auto/quick/qmltests/data/tst_settings.qml index 11b2321e0..f47674aa7 100644 --- a/tests/auto/quick/qmltests/data/tst_settings.qml +++ b/tests/auto/quick/qmltests/data/tst_settings.qml @@ -78,6 +78,68 @@ TestWebEngineView { webEngineView2.destroy(); } + + function test_disableReadingFromCanvas_data() { + return [ + { tag: 'disabled', disableReadingFromCanvas: false, result: true }, + { tag: 'enabled', disableReadingFromCanvas: true, result: false }, + ] + } + + function test_disableReadingFromCanvas(data) { + webEngineView.settings.readingFromCanvasEnabled = !data.disableReadingFromCanvas; + webEngineView.loadHtml("<html><body>" + + "<canvas id='myCanvas' width='200' height='40' style='border:1px solid #000000;'></canvas>" + + "</body></html>"); + verify(webEngineView.waitForLoadSucceeded()); + verify(webEngineView.settings.readingFromCanvasEnabled === !data.disableReadingFromCanvas ) + + var jsCode = "(function(){" + + " var canvas = document.getElementById(\"myCanvas\");" + + " var ctx = canvas.getContext(\"2d\");" + + " ctx.fillStyle = \"rgb(255,0,255)\";" + + " ctx.fillRect(0, 0, 200, 40);" + + " try {" + + " src = canvas.toDataURL();" + + " }" + + " catch(err) {" + + " src = \"\";" + + " }" + + " return src.length ? true : false;" + + "})();"; + + var isDataRead = false; + runJavaScript(jsCode, function(result) { + isDataRead = result + }); + tryVerify(function() { return isDataRead === data.result }); + } + + function test_forceDarkMode() { + // based on: https://developer.chrome.com/blog/auto-dark-theme/#detecting-auto-dark-theme + webEngineView.loadHtml("<html><body>" + + "<div id=\"detection\", style=\"display: none; background-color: canvas; color-scheme: light\"</div>" + + "</body></html>"); + const script = "(() => {" + + " const detectionDiv = document.querySelector('#detection');" + + " return getComputedStyle(detectionDiv).backgroundColor != 'rgb(255, 255, 255)';" + + "})()"; + verify(webEngineView.waitForLoadSucceeded()); + + var isAutoDark = true; + runJavaScript(script, result => isAutoDark = result); + tryVerify(() => {return !isAutoDark}); + + webEngineView.settings.forceDarkMode = true; + verify(webEngineView.settings.forceDarkMode == true) + + isAutoDark = false; + // the page is not updated immediately + tryVerify(function() { + runJavaScript(script, result => isAutoDark = result); + return isAutoDark; + }); + } } } diff --git a/tests/auto/quick/qmltests/data/tst_viewSource.qml b/tests/auto/quick/qmltests/data/tst_viewSource.qml index 44a88daab..d4449f7de 100644 --- a/tests/auto/quick/qmltests/data/tst_viewSource.qml +++ b/tests/auto/quick/qmltests/data/tst_viewSource.qml @@ -122,7 +122,7 @@ TestWebEngineView { WebEngine.settings.errorPageEnabled = true webEngineView.url = row.userInputUrl; - tryCompare(loadSpy, 'count', 2); + tryCompare(loadSpy, 'count', 2, 12000); let load = loadSpy.signalArguments[1][0] let expectedStatus = row.loadSucceed ? WebEngineView.LoadSucceededStatus : WebEngineView.LoadFailedStatus compare(load.status, expectedStatus); diff --git a/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml new file mode 100644 index 000000000..71da28843 --- /dev/null +++ b/tests/auto/quick/qmltests/mock-delegates/QtWebEngine/ControlsDelegates/DirectoryPicker.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import "../../TestParams" + +QtObject { + signal folderSelected(var folder) + signal rejected() + + function open() { + FilePickerParams.directoryPickerOpened = true; + if (FilePickerParams.selectFiles) + folderSelected(FilePickerParams.selectedFilesUrl); + else + rejected(); + } +} diff --git a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml index 4a1ffeb02..67d67dc40 100644 --- a/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml +++ b/tests/auto/quick/qmltests/mock-delegates/TestParams/FilePickerParams.qml @@ -8,5 +8,6 @@ QtObject { property var selectedFilesUrl: []; property bool selectFiles: false; property bool filePickerOpened: false; + property bool directoryPickerOpened: false; property var nameFilters: []; } diff --git a/tests/auto/quick/qmltests/tst_qmltests.cpp b/tests/auto/quick/qmltests/tst_qmltests.cpp index 5018c7e78..9e928157e 100644 --- a/tests/auto/quick/qmltests/tst_qmltests.cpp +++ b/tests/auto/quick/qmltests/tst_qmltests.cpp @@ -105,11 +105,18 @@ public: return tempDir.isValid() ? tempDir.path() : QString(); } + Q_INVOKABLE QUrl pathUrl(const QString &filename = QString()) + { + Q_ASSERT(tempDir.isValid()); + return filename.isEmpty() ? QUrl::fromLocalFile(tempDir.path()) + : QUrl::fromLocalFile(tempDir.filePath(filename)); + } + Q_INVOKABLE void removeRecursive(const QString dirname) { QDir dir(dirname); QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); - for (int i = 0; i < entries.count(); ++i) { + for (int i = 0; i < entries.size(); ++i) { if (entries[i].isDir()) removeRecursive(entries[i].filePath()); else @@ -118,6 +125,8 @@ public: QDir().rmdir(dirname); } + Q_INVOKABLE void createDirectory(const QString dirname) { QDir(tempDir.path()).mkdir(dirname); } + private: QTemporaryDir tempDir; }; @@ -253,8 +262,9 @@ int main(int argc, char **argv) #if QT_CONFIG(ssl) qmlRegisterSingletonType<HttpsServer>( - "Test.Shared", 1, 0, "HttpsServer", - [&](QQmlEngine *, QJSEngine *) { return new HttpsServer(":/resources/server.pem",":/resources/server.key"); }); + "Test.Shared", 1, 0, "HttpsServer", [&](QQmlEngine *, QJSEngine *) { + return new HttpsServer(":/resources/server.pem", ":/resources/server.key", ""); + }); #endif Setup setup; int i = quick_test_main_with_setup( diff --git a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/CMakeLists.txt b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/CMakeLists.txt index 07b184b89..9856ed513 100644 --- a/tests/auto/quick/qquickwebenginedefaultsurfaceformat/CMakeLists.txt +++ b/tests/auto/quick/qquickwebenginedefaultsurfaceformat/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../util/util.cmake) qt_internal_add_test(tst_qquickwebenginedefaultsurfaceformat diff --git a/tests/auto/quick/qquickwebengineview/CMakeLists.txt b/tests/auto/quick/qquickwebengineview/CMakeLists.txt index b0488048f..307ea36c9 100644 --- a/tests/auto/quick/qquickwebengineview/CMakeLists.txt +++ b/tests/auto/quick/qquickwebengineview/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../util/util.cmake) qt_internal_add_test(tst_qquickwebengineview diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 5b5003846..dbfa1cb33 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -1,8 +1,11 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses + #include "testwindow.h" #include "quickutil.h" +#include "util.h" #include <QScopedPointer> #include <QtCore/qelapsedtimer.h> @@ -16,6 +19,7 @@ #include <QtGui/private/qinputmethod_p.h> #include <QtWebEngineQuick/private/qquickwebenginescriptcollection_p.h> #include <QtWebEngineQuick/private/qquickwebenginesettings_p.h> +#include <QtWebEngineQuick/private/qquickwebenginedownloadrequest_p.h> #include <QtWebEngineQuick/private/qquickwebengineview_p.h> #include <QtWebEngineCore/private/qtwebenginecore-config_p.h> #include <qpa/qplatforminputcontext.h> @@ -69,9 +73,13 @@ private Q_SLOTS: void javascriptClipboard_data(); void javascriptClipboard(); void setProfile(); - void focusChild(); +#if QT_CONFIG(accessibility) void focusChild_data(); + void focusChild(); +#endif void htmlSelectPopup(); + void savePage_data(); + void savePage(); private: inline QQuickWebEngineView *newWebEngineView(); @@ -423,10 +431,10 @@ void tst_QQuickWebEngineView::transparentWebEngineViews() for (int i = 0; i < image.width(); i++) for (int j = 0; j < image.height(); j++) colors.insert(image.pixel(i, j)); - return colors.count() > 1; + return colors.size() > 1; }); - QVERIFY(colors.count() > 1); + QVERIFY(colors.size() > 1); QVERIFY(colors.contains(qRgb(0, 0, 0))); // black QVERIFY(colors.contains(qRgb(255, 0, 0))); // red for (auto color : colors) { @@ -599,12 +607,12 @@ void tst_QQuickWebEngineView::inputContextQueryInput() " <input type='text' id='input1' />" "</body></html>"); QVERIFY(waitForLoadSucceeded(view)); - QCOMPARE(testContext.infos.count(), 0); + QCOMPARE(testContext.infos.size(), 0); // Set focus on an input field. QPoint textInputCenter = elementCenter(view, "input1"); QTest::mouseClick(view->window(), Qt::LeftButton, {}, textInputCenter); - QTRY_COMPARE(testContext.infos.count(), 2); + QTRY_COMPARE(testContext.infos.size(), 2); QCOMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("input1")); foreach (const InputMethodInfo &info, testContext.infos) { QCOMPARE(info.cursorPosition, 0); @@ -616,7 +624,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() // Change content of an input field from JavaScript. evaluateJavaScriptSync(view, "document.getElementById('input1').value='QtWebEngine';"); - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QCOMPARE(testContext.infos[0].cursorPosition, 11); QCOMPARE(testContext.infos[0].anchorPosition, 11); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine")); @@ -625,7 +633,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() // Change content of an input field by key press. QTest::keyClick(view->window(), Qt::Key_Exclam); - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QCOMPARE(testContext.infos[0].cursorPosition, 12); QCOMPARE(testContext.infos[0].anchorPosition, 12); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); @@ -634,7 +642,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() // Change cursor position. QTest::keyClick(view->window(), Qt::Key_Left); - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QCOMPARE(testContext.infos[0].cursorPosition, 11); QCOMPARE(testContext.infos[0].anchorPosition, 11); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); @@ -649,7 +657,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() QInputMethodEvent event("", attributes); QGuiApplication::sendEvent(qApp->focusObject(), &event); } - QTRY_COMPARE(testContext.infos.count(), 2); + QTRY_COMPARE(testContext.infos.size(), 2); // As a first step, Chromium moves the cursor to the start of the selection. // We don't filter this in QtWebEngine because we don't know yet if this is part of a selection. @@ -673,7 +681,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() QInputMethodEvent event("", attributes); QGuiApplication::sendEvent(qApp->focusObject(), &event); } - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QCOMPARE(testContext.infos[0].cursorPosition, 0); QCOMPARE(testContext.infos[0].anchorPosition, 0); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); @@ -686,9 +694,9 @@ void tst_QQuickWebEngineView::inputContextQueryInput() QInputMethodEvent event("123", attributes); QGuiApplication::sendEvent(qApp->focusObject(), &event); } - QTRY_COMPARE(testContext.infos.count(), 1); - QCOMPARE(testContext.infos[0].cursorPosition, 3); - QCOMPARE(testContext.infos[0].anchorPosition, 3); + QTRY_COMPARE(testContext.infos.size(), 1); + QCOMPARE(testContext.infos[0].cursorPosition, 0); + QCOMPARE(testContext.infos[0].anchorPosition, 0); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("QtWebEngine!")); QCOMPARE(testContext.infos[0].selectedText, QStringLiteral("")); QCOMPARE(evaluateJavaScriptSync(view, "document.getElementById('input1').value").toString(), QStringLiteral("123QtWebEngine!")); @@ -700,7 +708,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() QInputMethodEvent event("", attributes); QGuiApplication::sendEvent(qApp->focusObject(), &event); } - QTRY_COMPARE(testContext.infos.count(), 2); + QTRY_COMPARE(testContext.infos.size(), 2); foreach (const InputMethodInfo &info, testContext.infos) { QCOMPARE(info.cursorPosition, 0); QCOMPARE(info.anchorPosition, 0); @@ -717,7 +725,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() event.setCommitString(QStringLiteral("123"), 0, 0); QGuiApplication::sendEvent(qApp->focusObject(), &event); } - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QCOMPARE(testContext.infos[0].cursorPosition, 3); QCOMPARE(testContext.infos[0].anchorPosition, 3); QCOMPARE(testContext.infos[0].surroundingText, QStringLiteral("123QtWebEngine!")); @@ -727,7 +735,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput() // Focus out. QTest::keyPress(view->window(), Qt::Key_Tab); - QTRY_COMPARE(testContext.infos.count(), 1); + QTRY_COMPARE(testContext.infos.size(), 1); QTRY_COMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("")); testContext.infos.clear(); } @@ -838,7 +846,7 @@ void tst_QQuickWebEngineView::printToPdf() QSignalSpy savePdfSpy(view, SIGNAL(pdfPrintingFinished(const QString&, bool))); QString path = tempDir.path() + "/print_success.pdf"; view->printToPdf(path, QQuickWebEngineView::A4, QQuickWebEngineView::Portrait); - QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); + QTRY_VERIFY2(savePdfSpy.size() == 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"); @@ -849,7 +857,7 @@ void tst_QQuickWebEngineView::printToPdf() path = tempDir.path() + "/print_|fail.pdf"; #endif // #if !defined(Q_OS_WIN) view->printToPdf(path, QQuickWebEngineView::A4, QQuickWebEngineView::Portrait); - QTRY_VERIFY2(savePdfSpy.count() == 1, "Printing to PDF file failed without signal"); + QTRY_VERIFY2(savePdfSpy.size() == 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"); @@ -1117,7 +1125,7 @@ void tst_QQuickWebEngineView::javascriptClipboard() // - return value of queryCommandEnabled and // - return value of execCommand // - comparing the clipboard / input field - QGuiApplication::clipboard()->clear(); + QGuiApplication::clipboard()->setText(QString()); QCOMPARE(evaluateJavaScriptSync(view, "document.queryCommandEnabled('copy')").toBool(), copyResult); QCOMPARE(evaluateJavaScriptSync(view, "document.execCommand('copy')").toBool(), copyResult); @@ -1144,9 +1152,9 @@ void tst_QQuickWebEngineView::javascriptClipboard() "if (result.state == 'prompt') accessPrompt = true;" "})")); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessGranted").toBool(), copyResult); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessDenied").toBool(), !javascriptCanAccessClipboard); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessPrompt").toBool(), false); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessGranted").toBool(), javascriptCanAccessClipboard && javascriptCanPaste); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessDenied").toBool(), false); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessPrompt").toBool(), !javascriptCanAccessClipboard || !javascriptCanPaste); evaluateJavaScriptSync(view, QStringLiteral( @@ -1160,9 +1168,9 @@ void tst_QQuickWebEngineView::javascriptClipboard() "if (result.state == 'prompt') accessPrompt = true;" "})")); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessGranted").toBool(), pasteResult); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessDenied").toBool(), !javascriptCanAccessClipboard || !javascriptCanPaste); - QTRY_COMPARE(evaluateJavaScriptSync(view, "accessPrompt").toBool(), false); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessGranted").toBool(), javascriptCanAccessClipboard && javascriptCanPaste); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessDenied").toBool(), false); + QTRY_COMPARE(evaluateJavaScriptSync(view, "accessPrompt").toBool(), !javascriptCanAccessClipboard || !javascriptCanPaste); } void tst_QQuickWebEngineView::setProfile() { @@ -1180,6 +1188,7 @@ void tst_QQuickWebEngineView::setProfile() { QTRY_COMPARE(webEngineView()->url() ,urlFromTestPath("html/basic_page2.html")); } +#if QT_CONFIG(accessibility) void tst_QQuickWebEngineView::focusChild_data() { QTest::addColumn<QString>("interfaceName"); @@ -1242,6 +1251,7 @@ void tst_QQuickWebEngineView::focusChild() // <html> -> <body> -> <input> QCOMPARE(traverseToWebDocumentAccessibleInterface(iface)->child(0)->child(0), iface->focusChild()); } +#endif // QT_CONFIG(accessibility) void tst_QQuickWebEngineView::htmlSelectPopup() { @@ -1270,8 +1280,92 @@ void tst_QQuickWebEngineView::htmlSelectPopup() QCOMPARE(evaluateJavaScriptSync(&view, "document.getElementById('select').value").toString(), QStringLiteral("O2")); } +void tst_QQuickWebEngineView::savePage_data() +{ + QTest::addColumn<QWebEngineDownloadRequest::SavePageFormat>("savePageFormat"); + + QTest::newRow("SingleHtmlSaveFormat") << QWebEngineDownloadRequest::SingleHtmlSaveFormat; + QTest::newRow("CompleteHtmlSaveFormat") << QWebEngineDownloadRequest::CompleteHtmlSaveFormat; + QTest::newRow("MimeHtmlSaveFormat") << QWebEngineDownloadRequest::MimeHtmlSaveFormat; +} + +void tst_QQuickWebEngineView::savePage() +{ + QFETCH(QWebEngineDownloadRequest::SavePageFormat, savePageFormat); + + QTemporaryDir tempDir(QDir::tempPath() + "/tst_QQuickWebEngineView-XXXXXX"); + QVERIFY(tempDir.isValid()); + const QString filePath = tempDir.path() + "/saved_page.html"; + + QQuickWebEngineView *view = webEngineView(); + int acceptedCount = 0; + int finishedCount = 0; + ScopedConnection sc1 = connect( + view->profile(), &QQuickWebEngineProfile::downloadRequested, + [&](QQuickWebEngineDownloadRequest *downloadRequest) { + QCOMPARE(downloadRequest->state(), + QQuickWebEngineDownloadRequest::DownloadInProgress); + QCOMPARE(downloadRequest->isSavePageDownload(), true); + QCOMPARE(downloadRequest->savePageFormat(), savePageFormat); + QCOMPARE(QDir(downloadRequest->downloadDirectory()) + .filePath(downloadRequest->downloadFileName()), + filePath); + QCOMPARE(downloadRequest->url(), view->url()); + + connect(downloadRequest, &QQuickWebEngineDownloadRequest::isFinishedChanged, + [&, downloadRequest]() { + QCOMPARE(downloadRequest->state(), + QQuickWebEngineDownloadRequest::DownloadCompleted); + QCOMPARE(downloadRequest->isSavePageDownload(), true); + QCOMPARE(downloadRequest->isFinished(), true); + QCOMPARE(downloadRequest->savePageFormat(), savePageFormat); + QCOMPARE(downloadRequest->totalBytes(), + downloadRequest->receivedBytes()); + QVERIFY(downloadRequest->receivedBytes() > 0); + QCOMPARE(QDir(downloadRequest->downloadDirectory()) + .filePath(downloadRequest->downloadFileName()), + filePath); + QCOMPARE(downloadRequest->url(), view->url()); + finishedCount++; + }); + acceptedCount++; + }); + + const QString originalData = QStringLiteral("Basic page"); + view->setUrl(urlFromTestPath("html/basic_page.html")); + QVERIFY(waitForLoadSucceeded(view)); + QCOMPARE(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText") + .toString(), + originalData); + + // Save the loaded page as HTML. + view->save(filePath, savePageFormat); + QTRY_COMPARE(acceptedCount, 1); + QTRY_COMPARE(finishedCount, 1); + QFile file(filePath); + QVERIFY(file.exists()); + + // Load something else. + view->setUrl(urlFromTestPath("html/basic_page2.html")); + QVERIFY(waitForLoadSucceeded(view)); + QVERIFY(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText") + .toString() + != originalData); + + // Load the saved page and compare the contents. + view->setUrl(QUrl::fromLocalFile(filePath)); + QVERIFY(waitForLoadSucceeded(view)); + QCOMPARE(evaluateJavaScriptSync(view, "document.getElementsByTagName('h1')[0].innerText") + .toString(), + originalData); +} + +#if QT_CONFIG(accessibility) static QByteArrayList params = QByteArrayList() << "--force-renderer-accessibility"; +#else +static QByteArrayList params; +#endif W_QTEST_MAIN(tst_QQuickWebEngineView, params) #include "tst_qquickwebengineview.moc" diff --git a/tests/auto/quick/qquickwebengineviewgraphics/CMakeLists.txt b/tests/auto/quick/qquickwebengineviewgraphics/CMakeLists.txt index 6bc0bc866..f22408d15 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/CMakeLists.txt +++ b/tests/auto/quick/qquickwebengineviewgraphics/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../util/util.cmake) qt_internal_add_test(tst_qquickwebengineviewgraphics SOURCES diff --git a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp index 71c3a1cf2..3644ac481 100644 --- a/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp +++ b/tests/auto/quick/qquickwebengineviewgraphics/tst_qquickwebengineviewgraphics.cpp @@ -124,6 +124,7 @@ void tst_QQuickWebEngineViewGraphics::reparentToOtherWindow() m_view->rootObject()->setParentItem(window.contentItem()); window.show(); + QVERIFY(QTest::qWaitForWindowExposed(&window)); verifyGreenSquare(&window); } diff --git a/tests/auto/quick/qtbug-70248/CMakeLists.txt b/tests/auto/quick/qtbug-70248/CMakeLists.txt index b1df50211..b177c5309 100644 --- a/tests/auto/quick/qtbug-70248/CMakeLists.txt +++ b/tests/auto/quick/qtbug-70248/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + qt_internal_add_test(tst_qtbug-70248 SOURCES tst_qtbug-70248.cpp diff --git a/tests/auto/quick/uidelegates/CMakeLists.txt b/tests/auto/quick/uidelegates/CMakeLists.txt index d8699ccfc..bdf041e04 100644 --- a/tests/auto/quick/uidelegates/CMakeLists.txt +++ b/tests/auto/quick/uidelegates/CMakeLists.txt @@ -1,3 +1,6 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + include(../../httpserver/httpserver.cmake) include(../../util/util.cmake) |