diff options
Diffstat (limited to 'tests/auto')
17 files changed, 1085 insertions, 63 deletions
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp index 7d3ad1440..c0762aa14 100644 --- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp +++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp @@ -65,6 +65,7 @@ private Q_SLOTS: void requestInterceptorByResourceType(); void firstPartyUrlHttp(); void passRefererHeader(); + void initiator(); }; tst_QWebEngineUrlRequestInterceptor::tst_QWebEngineUrlRequestInterceptor() @@ -95,11 +96,13 @@ struct RequestInfo { RequestInfo(QWebEngineUrlRequestInfo &info) : requestUrl(info.requestUrl()) , firstPartyUrl(info.firstPartyUrl()) + , initiator(info.initiator()) , resourceType(info.resourceType()) {} QUrl requestUrl; QUrl firstPartyUrl; + QUrl initiator; int resourceType; }; @@ -111,6 +114,7 @@ class TestRequestInterceptor : public QWebEngineUrlRequestInterceptor public: QList<RequestInfo> requestInfos; bool shouldIntercept; + QMap<QUrl, QUrl> requestInitiatorUrls; void interceptRequest(QWebEngineUrlRequestInfo &info) override { @@ -125,6 +129,7 @@ public: // Set referrer header info.setHttpHeader(kHttpHeaderRefererName, kHttpHeaderReferrerValue); + requestInitiatorUrls.insert(info.requestUrl(), info.initiator()); requestInfos.append(info); } @@ -553,5 +558,69 @@ void tst_QWebEngineUrlRequestInterceptor::passRefererHeader() QVERIFY(succeeded); } +void tst_QWebEngineUrlRequestInterceptor::initiator() +{ + QWebEngineProfile profile; + TestRequestInterceptor interceptor(/* intercept */ false); + profile.setUrlRequestInterceptor(&interceptor); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + QUrl url = QUrl("https://www.w3schools.com/tags/tryit.asp?filename=tryhtml5_video"); + page.setUrl(QUrl(url)); + if (!loadSpy.wait(15000) || !loadSpy.at(0).at(0).toBool()) + QSKIP("Couldn't load page from network, skipping test."); + + QList<RequestInfo> infos; + + // SubFrame + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeSubFrame); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // Stylesheet + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeStylesheet); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // Script + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeScript); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // Image + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeImage); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // FontResource + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFontResource); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // Media + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeMedia); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // Favicon + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeFavicon); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); + + // XMLHttpRequest + QTRY_VERIFY(interceptor.hasUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr)); + infos = interceptor.getUrlRequestForType(QWebEngineUrlRequestInfo::ResourceTypeXhr); + foreach (auto info, infos) + QCOMPARE(info.initiator, interceptor.requestInitiatorUrls[info.requestUrl]); +} + QTEST_MAIN(tst_QWebEngineUrlRequestInterceptor) #include "tst_qwebengineurlrequestinterceptor.moc" diff --git a/tests/auto/quick/dialogs/BLACKLIST b/tests/auto/quick/dialogs/BLACKLIST new file mode 100644 index 000000000..6d7e2a2fc --- /dev/null +++ b/tests/auto/quick/dialogs/BLACKLIST @@ -0,0 +1,2 @@ +[contextMenuRequested] +osx-10.13 diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index 90b768ac7..f464d58d0 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -80,6 +80,7 @@ static const QList<const QMetaObject *> typesToCheck = QList<const QMetaObject * << &QQuickWebEngineColorDialogRequest::staticMetaObject << &QQuickWebEngineFileDialogRequest::staticMetaObject << &QQuickWebEngineFormValidationMessageRequest::staticMetaObject + << &QQuickWebEngineTooltipRequest::staticMetaObject << &QQuickWebEngineContextMenuRequest::staticMetaObject << &QWebEngineQuotaRequest::staticMetaObject << &QWebEngineRegisterProtocolHandlerRequest::staticMetaObject @@ -259,6 +260,12 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineDownloadItem.type --> DownloadType" << "QQuickWebEngineDownloadItem.typeChanged() --> void" << "QQuickWebEngineDownloadItem.view --> QQuickWebEngineView*" + << "QQuickWebEngineDownloadItem.url --> QUrl" + << "QQuickWebEngineDownloadItem.suggestedFileName --> QString" + << "QQuickWebEngineDownloadItem.downloadDirectory --> QString" + << "QQuickWebEngineDownloadItem.downloadDirectoryChanged() --> void" + << "QQuickWebEngineDownloadItem.downloadFileName --> QString" + << "QQuickWebEngineDownloadItem.downloadFileNameChanged() --> void" << "QQuickWebEngineFileDialogRequest.FileModeOpen --> FileMode" << "QQuickWebEngineFileDialogRequest.FileModeOpenMultiple --> FileMode" << "QQuickWebEngineFileDialogRequest.FileModeSave --> FileMode" @@ -277,6 +284,13 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineFormValidationMessageRequest.subText --> QString" << "QQuickWebEngineFormValidationMessageRequest.text --> QString" << "QQuickWebEngineFormValidationMessageRequest.type --> RequestType" + << "QQuickWebEngineTooltipRequest.Hide --> RequestType" + << "QQuickWebEngineTooltipRequest.Show --> RequestType" + << "QQuickWebEngineTooltipRequest.x --> int" + << "QQuickWebEngineTooltipRequest.y --> int" + << "QQuickWebEngineTooltipRequest.text --> QString" + << "QQuickWebEngineTooltipRequest.type --> RequestType" + << "QQuickWebEngineTooltipRequest.accepted --> bool" << "QQuickWebEngineFullScreenRequest.accept() --> void" << "QQuickWebEngineFullScreenRequest.origin --> QUrl" << "QQuickWebEngineFullScreenRequest.reject() --> void" @@ -596,6 +610,9 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.LetterExtra --> PrintedPageSizeId" << "QQuickWebEngineView.LetterPlus --> PrintedPageSizeId" << "QQuickWebEngineView.LetterSmall --> PrintedPageSizeId" + << "QQuickWebEngineView.LifecycleState.Active --> LifecycleState" + << "QQuickWebEngineView.LifecycleState.Discarded --> LifecycleState" + << "QQuickWebEngineView.LifecycleState.Frozen --> LifecycleState" << "QQuickWebEngineView.LinkClickedNavigation --> NavigationType" << "QQuickWebEngineView.LoadFailedStatus --> LoadStatus" << "QQuickWebEngineView.LoadStartedStatus --> LoadStatus" @@ -628,6 +645,7 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.Prc32K --> PrintedPageSizeId" << "QQuickWebEngineView.Prc32KBig --> PrintedPageSizeId" << "QQuickWebEngineView.Quarto --> PrintedPageSizeId" + << "QQuickWebEngineView.RedirectNavigation --> NavigationType" << "QQuickWebEngineView.Redo --> WebAction" << "QQuickWebEngineView.Reload --> WebAction" << "QQuickWebEngineView.ReloadAndBypassCache --> WebAction" @@ -692,6 +710,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.isFullScreenChanged() --> void" << "QQuickWebEngineView.javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString) --> void" << "QQuickWebEngineView.javaScriptDialogRequested(QQuickWebEngineJavaScriptDialogRequest*) --> void" + << "QQuickWebEngineView.lifecycleState --> LifecycleState" + << "QQuickWebEngineView.lifecycleStateChanged(LifecycleState) --> void" << "QQuickWebEngineView.linkHovered(QUrl) --> void" << "QQuickWebEngineView.loadHtml(QString) --> void" << "QQuickWebEngineView.loadHtml(QString,QUrl) --> void" @@ -715,6 +735,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineView.quotaRequested(QWebEngineQuotaRequest) --> void" << "QQuickWebEngineView.recentlyAudible --> bool" << "QQuickWebEngineView.recentlyAudibleChanged(bool) --> void" + << "QQuickWebEngineView.recommendedState --> LifecycleState" + << "QQuickWebEngineView.recommendedStateChanged(LifecycleState) --> void" << "QQuickWebEngineView.registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest) --> void" << "QQuickWebEngineView.reload() --> void" << "QQuickWebEngineView.reloadAndBypassCache() --> void" @@ -736,6 +758,7 @@ static const QStringList expectedAPI = QStringList() #endif << "QQuickWebEngineView.title --> QString" << "QQuickWebEngineView.titleChanged() --> void" + << "QQuickWebEngineView.tooltipRequested(QQuickWebEngineTooltipRequest*) --> void" << "QQuickWebEngineView.triggerWebAction(WebAction) --> void" << "QQuickWebEngineView.url --> QUrl" << "QQuickWebEngineView.urlChanged() --> void" @@ -811,8 +834,9 @@ static void checkKnownType(const QByteArray &typeName) static void gatherAPI(const QString &prefix, const QMetaEnum &metaEnum, QStringList *output) { + const auto format = metaEnum.isScoped() ? "%1%3.%2 --> %3" : "%1%2 --> %3"; for (int i = 0; i < metaEnum.keyCount(); ++i) - *output << QString::fromLatin1("%1%2 --> %3").arg(prefix).arg(metaEnum.key(i)).arg(metaEnum.name()); + *output << QString::fromLatin1(format).arg(prefix).arg(metaEnum.key(i)).arg(metaEnum.name()); } static void gatherAPI(const QString &prefix, const QMetaProperty &property, QStringList *output) diff --git a/tests/auto/quick/qmltests/BLACKLIST b/tests/auto/quick/qmltests/BLACKLIST index 957911c3b..0a71e9f27 100644 --- a/tests/auto/quick/qmltests/BLACKLIST +++ b/tests/auto/quick/qmltests/BLACKLIST @@ -1,11 +1,7 @@ -[WebViewGeopermission::test_deniedGeolocationByUser] -osx - -[WebViewGeopermission::test_geoPermissionRequest] -osx - [WebViewFindText::test_findTextInterruptedByLoad] -* - +linux +qemu +b2qt +windows [WebEngineViewSource::test_viewSourceURL] * diff --git a/tests/auto/quick/qmltests/data/tst_action.qml b/tests/auto/quick/qmltests/data/tst_action.qml index 56a91d8d0..852d4145a 100644 --- a/tests/auto/quick/qmltests/data/tst_action.qml +++ b/tests/auto/quick/qmltests/data/tst_action.qml @@ -51,8 +51,8 @@ TestWebEngineView { { webAction: WebEngineView.Forward, text: "Forward", iconName: "go-next", enabled: false }, { webAction: WebEngineView.Stop, text: "Stop", iconName: "", enabled: false }, { webAction: WebEngineView.Reload, text: "Reload", iconName: "view-refresh", enabled: true }, - { webAction: WebEngineView.Cut, text: "Cut", iconName: "Cut", enabled: true }, - { webAction: WebEngineView.Copy, text: "Copy", iconName: "", enabled: true }, + { webAction: WebEngineView.Cut, text: "Cut", iconName: "Cut", enabled: false }, + { webAction: WebEngineView.Copy, text: "Copy", iconName: "", enabled: false }, { webAction: WebEngineView.Paste, text: "Paste", iconName: "", enabled: true }, { webAction: WebEngineView.Undo, text: "Undo", iconName: "", enabled: true }, { webAction: WebEngineView.Redo, text: "Redo", iconName: "", enabled: true }, @@ -76,7 +76,7 @@ TestWebEngineView { { webAction: WebEngineView.InspectElement, text: "Inspect", iconName: "", enabled: true }, { webAction: WebEngineView.ExitFullScreen, text: "Exit full screen", iconName: "", enabled: true }, { webAction: WebEngineView.RequestClose, text: "Close Page", iconName: "", enabled: true }, - { webAction: WebEngineView.Unselect, text: "Unselect", iconName: "", enabled: true }, + { webAction: WebEngineView.Unselect, text: "Unselect", iconName: "", enabled: false }, { webAction: WebEngineView.SavePage, text: "Save page", iconName: "", enabled: true }, { webAction: WebEngineView.ViewSource, text: "View page source", iconName: "view-source", enabled: true }, { webAction: WebEngineView.ToggleBold, text: "&Bold", iconName: "", enabled: true }, @@ -110,17 +110,17 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("test1.html"); verify(webEngineView.waitForLoadSucceeded()); - var copyAction = webEngineView.action(WebEngineView.Copy); - verify(copyAction); + var selectAction = webEngineView.action(WebEngineView.SelectAll); + verify(selectAction); var stopAction = webEngineView.action(WebEngineView.Stop); verify(stopAction); - var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: copyAction, signalName: "triggered"}); + var triggerSpy = createTemporaryObject(signalSpy, actionTests, {target: selectAction, signalName: "triggered"}); var stopTriggerSpy = createTemporaryObject(signalSpy, actionTests, {target: stopAction, signalName: "triggered"}); - verify(copyAction.enabled); - copyAction.trigger(); + verify(selectAction.enabled); + selectAction.trigger(); compare(triggerSpy.count, 1); verify(!stopAction.enabled); diff --git a/tests/auto/quick/qmltests/data/tst_download.qml b/tests/auto/quick/qmltests/data/tst_download.qml index 5eb704cce..ff57c76c7 100644 --- a/tests/auto/quick/qmltests/data/tst_download.qml +++ b/tests/auto/quick/qmltests/data/tst_download.qml @@ -28,7 +28,7 @@ import QtQuick 2.0 import QtTest 1.0 -import QtWebEngine 1.9 +import QtWebEngine 1.10 import Qt.labs.platform 1.0 TestWebEngineView { @@ -42,6 +42,14 @@ TestWebEngineView { property bool cancelDownload: false property var downloadState: [] property var downloadInterruptReason: null + property url downloadUrl: "" + property string suggestedFileName: "" + property string downloadDirectory: "" + property string downloadFileName: "" + property string downloadedPath: "" + property int downloadDirectoryChanged: 0 + property int downloadFileNameChanged: 0 + property int downloadPathChanged: 0 function urlToPath(url) { var path = url.toString() @@ -66,21 +74,36 @@ TestWebEngineView { ignoreUnknownSignals: true onStateChanged: downloadState.push(target.state) onInterruptReasonChanged: downloadInterruptReason = target.interruptReason + onDownloadDirectoryChanged: downloadDirectoryChanged++ + onDownloadFileNameChanged: downloadFileNameChanged++ + onPathChanged: downloadPathChanged++ } WebEngineProfile { id: testDownloadProfile onDownloadRequested: { + testDownloadProfile.downloadPath = urlToPath(StandardPaths.writableLocation(StandardPaths.TempLocation)) downloadState.push(download.state) downloadItemConnections.target = download if (cancelDownload) { download.cancel() } else { totalBytes = download.totalBytes - download.path = "testfile.zip" + download.downloadDirectory = testDownloadProfile.downloadPath + download.downloadFileName = "testfile.zip" + + if (downloadDirectory.length != 0) + download.downloadDirectory = testDownloadProfile.downloadPath + downloadDirectory + + if (downloadFileName.length != 0) + download.downloadFileName = downloadFileName + download.accept() } + downloadUrl = download.url + suggestedFileName = download.suggestedFileName + downloadedPath = download.downloadDirectory + download.downloadFileName } onDownloadFinished: { receivedBytes = download.receivedBytes; @@ -99,6 +122,9 @@ TestWebEngineView { downloadItemConnections.target = null downloadState = [] downloadInterruptReason = null + downloadDirectoryChanged = 0 + downloadFileNameChanged = 0 + downloadPathChanged = 0 } function test_downloadRequest() { @@ -106,6 +132,8 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("download.zip") downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(suggestedFileName, "download.zip") compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) verify(!downloadInterruptReason) } @@ -115,6 +143,8 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("download.zip") downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(suggestedFileName, "download.zip") compare(totalBytes, 325) verify(!downloadInterruptReason) } @@ -124,6 +154,8 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("download.zip") downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(suggestedFileName, "download.zip") compare(downloadState[0], WebEngineDownloadItem.DownloadRequested) tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress) downloadFinishedSpy.wait() @@ -138,6 +170,8 @@ TestWebEngineView { webEngineView.url = Qt.resolvedUrl("download.zip") downLoadRequestedSpy.wait() compare(downLoadRequestedSpy.count, 1) + compare(downloadUrl, webEngineView.url) + compare(suggestedFileName, "download.zip") compare(downloadFinishedSpy.count, 1) tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadCancelled) tryCompare(webEngineView, "downloadInterruptReason", WebEngineDownloadItem.UserCanceled) @@ -153,5 +187,28 @@ TestWebEngineView { testDownloadProfile.downloadPath = downloadPath; compare(testDownloadProfile.downloadPath, downloadPath); } + + function test_downloadToDirectoryWithFileName() { + compare(downLoadRequestedSpy.count, 0); + compare(downloadDirectoryChanged, 0); + compare(downloadFileNameChanged, 0); + downloadDirectory = "/test/"; + downloadFileName = "test.zip"; + webEngineView.url = Qt.resolvedUrl("download.zip"); + downLoadRequestedSpy.wait(); + compare(downLoadRequestedSpy.count, 1); + compare(downloadUrl, webEngineView.url); + compare(suggestedFileName, "download.zip"); + compare(downloadState[0], WebEngineDownloadItem.DownloadRequested); + tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress); + compare(downloadedPath, testDownloadProfile.downloadPath + downloadDirectory + downloadFileName); + compare(downloadDirectoryChanged, 1); + compare(downloadFileNameChanged, 3); + compare(downloadPathChanged, 4); + downloadFinishedSpy.wait(); + compare(totalBytes, receivedBytes); + tryCompare(downloadState, "2", WebEngineDownloadItem.DownloadCompleted); + verify(!downloadInterruptReason); + } } } diff --git a/tests/auto/quick/qquickwebengineview/BLACKLIST b/tests/auto/quick/qquickwebengineview/BLACKLIST index 166a6894e..d4d5c9844 100644 --- a/tests/auto/quick/qquickwebengineview/BLACKLIST +++ b/tests/auto/quick/qquickwebengineview/BLACKLIST @@ -1,17 +1,2 @@ [transparentWebEngineViews] windows - -[inputEventForwardingDisabledWhenActiveFocusOnPressDisabled] -* - -[transparentWebEngineViews] -* - -[basicRenderingSanity] -* - -[javascriptClipboard:default] -opensuse-leap - -[javascriptClipboard:canPaste] -opensuse-leap diff --git a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp index e614f3751..c0bb8d5c5 100644 --- a/tests/auto/widgets/loadsignals/tst_loadsignals.cpp +++ b/tests/auto/widgets/loadsignals/tst_loadsignals.cpp @@ -238,7 +238,8 @@ void tst_LoadSignals::fileDownloadDoesNotTriggerLoadSignals_qtbug66661() connect(item, &QWebEngineDownloadItem::stateChanged, [&downloadState](QWebEngineDownloadItem::DownloadState newState){ downloadState = newState; }); - item->setPath(tempDir.filePath(QFileInfo(item->path()).fileName())); + item->setDownloadDirectory(tempDir.filePath(QFileInfo(item->path()).path())); + item->setDownloadFileName(QFileInfo(item->path()).fileName()); item->accept(); }); diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index 3566c2216..6dc7f03c1 100644 --- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -78,6 +78,7 @@ private Q_SLOTS: void downloadToNonExistentDir(); void downloadToReadOnlyDir(); void downloadPathValidation(); + void downloadToDirectoryWithFileName(); private: void saveLink(QPoint linkPos); @@ -447,6 +448,8 @@ void tst_QWebEngineDownloadItem::downloadLink() QByteArray slashFileName = QByteArrayLiteral("/") + fileName; QString suggestedPath = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + slashFileName; + QString downloadDirectory = tmpDir.path(); + QString downloadFileName = fileName; QString downloadPath = tmpDir.path() + slashFileName; QUrl downloadUrl = m_server->url(slashFileName); int acceptedCount = 0; @@ -460,7 +463,7 @@ void tst_QWebEngineDownloadItem::downloadLink() QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition)); QCOMPARE(item->isSavePageDownload(), false); QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected)); - QCOMPARE(item->path(), suggestedPath); + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), suggestedPath); QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); @@ -474,14 +477,15 @@ void tst_QWebEngineDownloadItem::downloadLink() QCOMPARE(item->type(), expectedDownloadType(userAction, fileDisposition)); QCOMPARE(item->isSavePageDownload(), false); QCOMPARE(item->mimeType(), QString(fileMimeTypeDetected)); - QCOMPARE(item->path(), downloadPath); + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); finishedCount++; }); - item->setPath(downloadPath); + item->setDownloadDirectory(downloadDirectory); + item->setDownloadFileName(downloadFileName); item->accept(); acceptedCount++; @@ -575,7 +579,8 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks() QCOMPARE(item->savePageFormat(), QWebEngineDownloadItem::UnknownSaveFormat); QCOMPARE(item->mimeType(), QStringLiteral("text/plain")); QString filePart = QChar('/') + item->url().fileName(); - QCOMPARE(item->path(), standardDir + filePart); + QString fileName = item->url().fileName(); + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), standardDir + filePart); // type() is broken due to race condition in DownloadManagerDelegateQt if (action1 == ClickLink && action2 == ClickLink) { @@ -590,7 +595,8 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks() connect(item, &QWebEngineDownloadItem::finished, [&]() { finishedCount++; }); - item->setPath(tmpDir.path() + filePart); + item->setDownloadDirectory(tmpDir.path()); + item->setDownloadFileName(fileName); item->accept(); acceptedCount++; @@ -655,7 +661,7 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(item->isSavePageDownload(), true); // FIXME(juvaldma): why is mimeType always the same? QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive")); - QCOMPARE(item->path(), downloadPath); + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); @@ -670,7 +676,7 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(item->type(), QWebEngineDownloadItem::SavePage); QCOMPARE(item->isSavePageDownload(), true); QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive")); - QCOMPARE(item->path(), downloadPath); + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); @@ -869,6 +875,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename() QFETCH(QString, extension); QString fileName = QString("%1.%2").arg(baseName).arg(extension); QString downloadedFilePath; + QString suggestedFileName; bool downloadFinished = false; QTemporaryDir tmpDir; @@ -890,6 +897,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename() // Set up profile and download handler ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { + suggestedFileName = item->suggestedFileName(); item->accept(); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -899,7 +907,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename() QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason); QCOMPARE(item->type(), QWebEngineDownloadItem::Attachment); QCOMPARE(item->isSavePageDownload(), false); - downloadedFilePath = item->path(); + downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName()); downloadFinished = true; }); }); @@ -915,6 +923,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilename() QTRY_VERIFY(downloadFinished); QVERIFY(QFile(downloadedFilePath).exists()); QCOMPARE(downloadedFilePath, m_profile->downloadPath() + "/" + baseName + " (" + QString::number(i) + ")." + extension); + QCOMPARE(suggestedFileName, fileName); } } @@ -925,6 +934,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() QString extension("txt"); QString fileName = QString("%1.%2").arg(baseName).arg(extension); QString downloadedFilePath; + QString suggestedFileName; bool downloadFinished = false; QTemporaryDir tmpDir; @@ -945,6 +955,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() // Set up profile and download handler ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { + suggestedFileName = item->suggestedFileName(); item->accept(); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -954,7 +965,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason); QCOMPARE(item->page(), m_page); downloadFinished = true; - downloadedFilePath = item->path(); + downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName()); }); }); @@ -975,6 +986,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() QTRY_VERIFY(downloadFinished); QVERIFY(QFile(downloadedFilePath).exists()); QCOMPARE(downloadedFilePath, m_profile->downloadPath() + "/" + baseName + " (100)." + extension); + QCOMPARE(suggestedFileName, fileName); // Check if the downloaded files are suffixed with timestamp after the 100th download. for (int i = 101; i < 103; i++) { @@ -988,6 +1000,7 @@ void tst_QWebEngineDownloadItem::downloadUniqueFilenameWithTimestamp() // 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))); + QCOMPARE(suggestedFileName, fileName); } } @@ -1014,6 +1027,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir() QString extension("txt"); QString fileName = QString("%1.%2").arg(baseName).arg(extension); QString downloadedFilePath; + QString suggestedFileName; bool downloadFinished = false; QTemporaryDir tmpDir; @@ -1035,6 +1049,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir() // Set up profile and download handler ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { + suggestedFileName = item->suggestedFileName(); item->accept(); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -1044,7 +1059,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir() QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason); QCOMPARE(item->page(), m_page); downloadFinished = true; - downloadedFilePath = item->path(); + downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName()); }); }); @@ -1056,6 +1071,7 @@ void tst_QWebEngineDownloadItem::downloadToNonExistentDir() QTRY_VERIFY(downloadFinished); QVERIFY(QFile(downloadedFilePath).exists()); QCOMPARE(downloadedFilePath, nonExistentDownloadPath + "/" + fileName); + QCOMPARE(suggestedFileName, fileName); } void tst_QWebEngineDownloadItem::downloadToReadOnlyDir() @@ -1067,6 +1083,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir() QString extension("txt"); QString fileName = QString("%1.%2").arg(baseName).arg(extension); QString downloadedFilePath; + QString suggestedFileName; bool downloadAccepted = false; bool downloadFinished = false; @@ -1089,6 +1106,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir() QPointer<QWebEngineDownloadItem> downloadItem; ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { + suggestedFileName = item->suggestedFileName(); downloadItem = item; item->accept(); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { @@ -1109,6 +1127,7 @@ void tst_QWebEngineDownloadItem::downloadToReadOnlyDir() QCOMPARE(downloadItem->isFinished(), false); QCOMPARE(downloadItem->interruptReason(), QWebEngineDownloadItem::FileAccessDenied); QVERIFY(!QFile(downloadedFilePath).exists()); + QCOMPARE(suggestedFileName, fileName); // Clear m_requestedDownloads explicitly because download is accepted but never finished. m_requestedDownloads.clear(); @@ -1233,5 +1252,135 @@ void tst_QWebEngineDownloadItem::downloadPathValidation() QDir::setCurrent(oldPath); } +void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName() +{ + QString downloadDirectory; + QString downloadFileName; + QString downloadedFilePath; + QString downloadedSuggestedFileName; + QString fileName = "test.txt"; + QString uniqueFileName = "test (1).txt"; + + bool downloadFinished = false; + + QTemporaryDir tmpDir; + QVERIFY(tmpDir.isValid()); + m_profile->setDownloadPath(tmpDir.path()); + + // Set up HTTP server + ScopedConnection sc1 = connect(m_server, &HttpServer::newRequest, [&](HttpReqRep *rr) { + if (rr->requestMethod() == "GET" && rr->requestPath() == ("/" + fileName)) { + rr->setResponseHeader(QByteArrayLiteral("content-type"), QByteArrayLiteral("application/octet-stream")); + rr->setResponseHeader(QByteArrayLiteral("content-disposition"), QByteArrayLiteral("attachment")); + rr->setResponseBody(QByteArrayLiteral("a")); + rr->sendResponse(); + } else { + rr->setResponseStatus(404); + rr->sendResponse(); + } + }); + + // Set up profile and download handler + ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { + + if (!downloadDirectory.isEmpty()) { + item->setDownloadDirectory(downloadDirectory); + QCOMPARE(item->downloadDirectory(), downloadDirectory); + } + + if (!downloadFileName.isEmpty()) { + item->setDownloadFileName(downloadFileName); + QCOMPARE(item->downloadFileName(), downloadFileName); + } + + QCOMPARE(item->path(), QDir(item->downloadDirectory()).filePath(item->downloadFileName())); + item->accept(); + + connect(item, &QWebEngineDownloadItem::finished, [&, item]() { + QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); + QCOMPARE(item->isFinished(), true); + QCOMPARE(item->totalBytes(), item->receivedBytes()); + QVERIFY(item->receivedBytes() > 0); + QCOMPARE(item->interruptReason(), QWebEngineDownloadItem::NoReason); + QCOMPARE(item->page(), m_page); + downloadFinished = true; + downloadedFilePath = QDir(item->downloadDirectory()).filePath(item->downloadFileName()); + downloadedSuggestedFileName = item->suggestedFileName(); + }); + }); + + // Download file to the default download directory. + downloadDirectory = ""; + downloadFileName = ""; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(m_profile->downloadPath()).filePath(fileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download the same file to another directory + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator(); + downloadFileName = ""; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(fileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download the same file to the same directory and the file name must be unique. + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator(); + downloadFileName = ""; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(uniqueFileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download another file to the same directory and set file name by + // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification. + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test1" + QDir::separator(); + downloadFileName = "test1.txt"; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download the same file to another directory without uniquifying the file name + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator(); + downloadFileName = "test1.txt"; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download the same file to same directory and set file name by + // QWebEngineDownloadItem::setDownloadDirectory() and setDownloadFileName() to avoid uniquification. + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator(); + downloadFileName = "test1.txt"; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(downloadFileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); + + // Download the same file in the same directory. + // Use the suggested file name (test.txt) and the file name will not be unique because this file name don't yet exists. + downloadFinished = false; + downloadDirectory = m_profile->downloadPath() + QDir::separator() + "test2" + QDir::separator(); + downloadFileName = ""; + m_page->setUrl(m_server->url("/" + fileName)); + QTRY_VERIFY(downloadFinished); + QVERIFY(QFile(downloadedFilePath).exists()); + QCOMPARE(downloadedFilePath, QDir(downloadDirectory).filePath(fileName)); + QCOMPARE(downloadedSuggestedFileName, fileName); +} + QTEST_MAIN(tst_QWebEngineDownloadItem) #include "tst_qwebenginedownloaditem.moc" diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST index e6d50da39..4e344c936 100644 --- a/tests/auto/widgets/qwebenginepage/BLACKLIST +++ b/tests/auto/widgets/qwebenginepage/BLACKLIST @@ -4,14 +4,6 @@ osx [mouseMovementProperties] windows -[getUserMediaRequest] -windows - -[getUserMediaRequestDesktopVideoManyPages] -windows - -[getUserMediaRequestDesktopVideoManyRequests] -windows - [runJavaScriptFromSlot] osx +linux diff --git a/tests/auto/widgets/qwebenginepage/resources/lifecycle.html b/tests/auto/widgets/qwebenginepage/resources/lifecycle.html new file mode 100644 index 000000000..aa477a359 --- /dev/null +++ b/tests/auto/widgets/qwebenginepage/resources/lifecycle.html @@ -0,0 +1,17 @@ +<!DOCTYPE html> +<html> + <head> + <title>Lifecycle</title> + <script> + let frozenness = 0; + document.addEventListener("freeze", function() { + frozenness += 1; + }); + document.addEventListener("resume", function() { + frozenness -= 1; + }); + </script> + </head> + <body> + </body> +</html> diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 8ad11ec75..7ec1fbef0 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -202,9 +202,23 @@ private Q_SLOTS: void sendNotification(); void contentsSize(); + void setLifecycleState(); + void setVisible(); + void discardPreservesProperties(); + void discardBeforeInitialization(); + void automaticUndiscard(); + void setLifecycleStateWithDevTools(); + void discardPreservesCommittedLoad(); + void discardAbortsPendingLoad(); + void discardAbortsPendingLoadAndPreservesCommittedLoad(); + void recommendedState(); + void recommendedStateAuto(); + void setLifecycleStateAndReload(); + void editActionsWithExplicitFocus(); void editActionsWithInitialFocus(); void editActionsWithFocusOnIframe(); + void editActionsWithoutSelection(); private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); @@ -577,7 +591,7 @@ void tst_QWebEnginePage::acceptNavigationRequestNavigationType() << QWebEnginePage::NavigationTypeBackForward << QWebEnginePage::NavigationTypeReload << QWebEnginePage::NavigationTypeTyped - << QWebEnginePage::NavigationTypeOther; + << QWebEnginePage::NavigationTypeRedirect; QVERIFY(expectedList.count() == page.navigations.count()); for (int i = 0; i < expectedList.count(); ++i) { QCOMPARE(page.navigations[i].type, expectedList[i]); @@ -3405,6 +3419,645 @@ void tst_QWebEnginePage::contentsSize() QCOMPARE(m_page->contentsSize().height(), 1216); } +void tst_QWebEnginePage::setLifecycleState() +{ + qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged); + QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged); + + page.load(QStringLiteral("qrc:/resources/lifecycle.html")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false)); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0)); + + // Active -> Frozen + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false)); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(1)); + + // Frozen -> Active + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false)); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0)); + + // Active -> Discarded + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QTest::ignoreMessage(QtWarningMsg, "runJavaScript: disabled in Discarded state"); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant()); + QTest::ignoreMessage(QtWarningMsg, "runJavaScript: disabled in Discarded state"); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant()); + QCOMPARE(loadSpy.count(), 0); + + // Discarded -> Frozen (illegal!) + QTest::ignoreMessage(QtWarningMsg, + "setLifecycleState: failed to transition from Discarded to Frozen state: " + "illegal transition"); + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); + + // Discarded -> Active + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(true)); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0)); + + // Active -> Frozen -> Discarded -> Active + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QCOMPARE(lifecycleSpy.count(), 3); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(true)); + QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0)); + + // Reload clears document.wasDiscarded + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false)); +} + +void tst_QWebEnginePage::setVisible() +{ + qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged); + QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged); + + page.load(QStringLiteral("about:blank")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(page.isVisible(), false); + + // hidden -> visible + page.setVisible(true); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(page.isVisible(), true); + + // Active -> Frozen (illegal) + QTest::ignoreMessage( + QtWarningMsg, + "setLifecycleState: failed to transition from Active to Frozen state: page is visible"); + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(lifecycleSpy.count(), 0); + + // visible -> hidden + page.setVisible(false); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(false)); + QCOMPARE(page.isVisible(), false); + + // Active -> Frozen + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen); + + // hidden -> visible (triggers Frozen -> Active) + page.setVisible(true); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(page.isVisible(), true); + + // Active -> Discarded (illegal) + QTest::ignoreMessage(QtWarningMsg, + "setLifecycleState: failed to transition from Active to Discarded state: " + "page is visible"); + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(lifecycleSpy.count(), 0); + + // visible -> hidden + page.setVisible(false); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(false)); + QCOMPARE(page.isVisible(), false); + + // Active -> Discarded + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); + + // hidden -> visible (triggers Discarded -> Active) + page.setVisible(true); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(page.isVisible(), true); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); +} + +void tst_QWebEnginePage::discardPreservesProperties() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + + page.load(QStringLiteral("about:blank")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + + // Change as many properties as possible to non-default values + bool audioMuted = true; + QVERIFY(page.isAudioMuted() != audioMuted); + page.setAudioMuted(audioMuted); + QColor backgroundColor = Qt::black; + QVERIFY(page.backgroundColor() != backgroundColor); + page.setBackgroundColor(backgroundColor); + qreal zoomFactor = 2; + QVERIFY(page.zoomFactor() != zoomFactor); + page.setZoomFactor(zoomFactor); +#if QT_CONFIG(webengine_webchannel) + QWebChannel *webChannel = new QWebChannel(&page); + page.setWebChannel(webChannel); +#endif + + // Take snapshot of the rest + QSizeF contentsSize = page.contentsSize(); + QIcon icon = page.icon(); + QUrl iconUrl = page.iconUrl(); + QUrl requestedUrl = page.requestedUrl(); + QString title = page.title(); + QUrl url = page.url(); + + // History should be preserved too + int historyCount = page.history()->count(); + QCOMPARE(historyCount, 1); + int historyIndex = page.history()->currentItemIndex(); + QCOMPARE(historyIndex, 0); + QWebEngineHistoryItem historyItem = page.history()->currentItem(); + QVERIFY(historyItem.isValid()); + + // Discard + undiscard + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + + // Property changes should be preserved + QCOMPARE(page.isAudioMuted(), audioMuted); + QCOMPARE(page.backgroundColor(), backgroundColor); + QCOMPARE(page.contentsSize(), contentsSize); + QCOMPARE(page.icon(), icon); + QCOMPARE(page.iconUrl(), iconUrl); + QCOMPARE(page.requestedUrl(), requestedUrl); + QCOMPARE(page.title(), title); + QCOMPARE(page.url(), url); + QCOMPARE(page.zoomFactor(), zoomFactor); +#if QT_CONFIG(webengine_webchannel) + QCOMPARE(page.webChannel(), webChannel); +#endif + QCOMPARE(page.history()->count(), historyCount); + QCOMPARE(page.history()->currentItemIndex(), historyIndex); + QCOMPARE(page.history()->currentItem().url(), historyItem.url()); + QCOMPARE(page.history()->currentItem().originalUrl(), historyItem.originalUrl()); + QCOMPARE(page.history()->currentItem().title(), historyItem.title()); +} + +void tst_QWebEnginePage::discardBeforeInitialization() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + // The call is ignored + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); +} + +void tst_QWebEnginePage::automaticUndiscard() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + + page.load(QStringLiteral("about:blank")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + + // setUrl + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setUrl(QStringLiteral("qrc:/resources/lifecycle.html")); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + + // setContent + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setContent(QByteArrayLiteral("foo")); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); +} + +void tst_QWebEnginePage::setLifecycleStateWithDevTools() +{ + QWebEngineProfile profile; + QWebEnginePage inspectedPage(&profile); + QWebEnginePage devToolsPage(&profile); + QSignalSpy devToolsSpy(&devToolsPage, &QWebEnginePage::loadFinished); + QSignalSpy inspectedSpy(&inspectedPage, &QWebEnginePage::loadFinished); + + // Ensure pages are initialized + inspectedPage.load(QStringLiteral("about:blank")); + devToolsPage.load(QStringLiteral("about:blank")); + QTRY_COMPARE(inspectedSpy.count(), 1); + QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true)); + QTRY_COMPARE(devToolsSpy.count(), 1); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); + + // Open DevTools with Frozen inspectedPage + inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + inspectedPage.setDevToolsPage(&devToolsPage); + QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(devToolsSpy.count(), 1); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); + inspectedPage.setDevToolsPage(nullptr); + + // Open DevTools with Discarded inspectedPage + inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + inspectedPage.setDevToolsPage(&devToolsPage); + QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(devToolsSpy.count(), 1); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); + QTRY_COMPARE(inspectedSpy.count(), 1); + QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true)); + inspectedPage.setDevToolsPage(nullptr); + + // Open DevTools with Frozen devToolsPage + devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + devToolsPage.setInspectedPage(&inspectedPage); + QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(devToolsSpy.count(), 1); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); + devToolsPage.setInspectedPage(nullptr); + + // Open DevTools with Discarded devToolsPage + devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + devToolsPage.setInspectedPage(&inspectedPage); + QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(devToolsSpy.count(), 2); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(false)); + QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); + // keep DevTools open + + // Try to change state while DevTools are open + QTest::ignoreMessage( + QtWarningMsg, + "setLifecycleState: failed to transition from Active to Frozen state: DevTools open"); + inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTest::ignoreMessage(QtWarningMsg, + "setLifecycleState: failed to transition from Active to Discarded state: " + "DevTools open"); + inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTest::ignoreMessage( + QtWarningMsg, + "setLifecycleState: failed to transition from Active to Frozen state: DevTools open"); + devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QTest::ignoreMessage(QtWarningMsg, + "setLifecycleState: failed to transition from Active to Discarded state: " + "DevTools open"); + devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); +} + +void tst_QWebEnginePage::discardPreservesCommittedLoad() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted); + QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged); + QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged); + + QString url = QStringLiteral("qrc:/resources/lifecycle.html"); + page.setUrl(url); + QTRY_COMPARE(loadStartedSpy.count(), 1); + loadStartedSpy.clear(); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(urlChangedSpy.count(), 1); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url))); + QCOMPARE(page.url(), url); + QCOMPARE(titleChangedSpy.count(), 2); + QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(url)); + QString title = QStringLiteral("Lifecycle"); + QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(title)); + QCOMPARE(page.title(), title); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(loadStartedSpy.count(), 0); + QCOMPARE(loadFinishedSpy.count(), 0); + QCOMPARE(urlChangedSpy.count(), 0); + QCOMPARE(page.url(), QUrl(url)); + QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(page.title(), title); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(loadStartedSpy.count(), 1); + loadStartedSpy.clear(); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(urlChangedSpy.count(), 0); + QCOMPARE(page.url(), url); + QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(page.title(), title); +} + +void tst_QWebEnginePage::discardAbortsPendingLoad() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted); + QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged); + QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged); + + connect(&page, &QWebEnginePage::loadStarted, + [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); }); + QUrl url = QStringLiteral("qrc:/resources/lifecycle.html"); + page.setUrl(url); + QTRY_COMPARE(loadStartedSpy.count(), 1); + loadStartedSpy.clear(); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false)); + QCOMPARE(urlChangedSpy.count(), 2); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(url)); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl())); + QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(page.url(), QUrl()); + QCOMPARE(page.title(), QString()); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QCOMPARE(loadStartedSpy.count(), 0); + QCOMPARE(loadFinishedSpy.count(), 0); + QCOMPARE(urlChangedSpy.count(), 0); + QCOMPARE(page.url(), QUrl()); + QCOMPARE(page.title(), QString()); +} + +void tst_QWebEnginePage::discardAbortsPendingLoadAndPreservesCommittedLoad() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadStartedSpy(&page, &QWebEnginePage::loadStarted); + QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy urlChangedSpy(&page, &QWebEnginePage::urlChanged); + QSignalSpy titleChangedSpy(&page, &QWebEnginePage::titleChanged); + + QString url1 = QStringLiteral("qrc:/resources/lifecycle.html"); + page.setUrl(url1); + QTRY_COMPARE(loadStartedSpy.count(), 1); + loadStartedSpy.clear(); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(urlChangedSpy.count(), 1); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1))); + QCOMPARE(page.url(), url1); + QCOMPARE(titleChangedSpy.count(), 2); + QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(url1)); + QString title = QStringLiteral("Lifecycle"); + QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(title)); + QCOMPARE(page.title(), title); + + connect(&page, &QWebEnginePage::loadStarted, + [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); }); + QString url2 = QStringLiteral("about:blank"); + page.setUrl(url2); + QTRY_COMPARE(loadStartedSpy.count(), 1); + loadStartedSpy.clear(); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false)); + QCOMPARE(urlChangedSpy.count(), 2); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url2))); + QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1))); + QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(page.url(), url1); + QCOMPARE(page.title(), title); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QCOMPARE(loadStartedSpy.count(), 0); + QCOMPARE(loadFinishedSpy.count(), 0); + QCOMPARE(urlChangedSpy.count(), 0); + QCOMPARE(page.url(), url1); + QCOMPARE(page.title(), title); +} + +void tst_QWebEnginePage::recommendedState() +{ + qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + + struct Event { + enum { StateChange, RecommendationChange } key; + QWebEnginePage::LifecycleState value; + }; + std::vector<Event> events; + connect(&page, &QWebEnginePage::lifecycleStateChanged, [&](QWebEnginePage::LifecycleState state) { + events.push_back(Event { Event::StateChange, state }); + }); + connect(&page, &QWebEnginePage::recommendedStateChanged, [&](QWebEnginePage::LifecycleState state) { + events.push_back(Event { Event::RecommendationChange, state }); + }); + + page.load(QStringLiteral("qrc:/resources/lifecycle.html")); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen); + + page.setVisible(true); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Active); + + page.setVisible(false); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen); + + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(events.size(), 2u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active); + QCOMPARE(events[1].key, Event::RecommendationChange); + QCOMPARE(events[1].value, QWebEnginePage::LifecycleState::Frozen); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen); + + QWebEnginePage devTools; + page.setDevToolsPage(&devTools); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Active); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Active); + + page.setDevToolsPage(nullptr); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::RecommendationChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Frozen); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QTRY_COMPARE(events.size(), 2u); + QCOMPARE(events[0].key, Event::StateChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(events[1].key, Event::RecommendationChange); + QCOMPARE(events[1].value, QWebEnginePage::LifecycleState::Discarded); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Discarded); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QTRY_COMPARE(events.size(), 1u); + QCOMPARE(events[0].key, Event::StateChange); + QCOMPARE(events[0].value, QWebEnginePage::LifecycleState::Discarded); + events.clear(); + QCOMPARE(page.recommendedState(), QWebEnginePage::LifecycleState::Discarded); +} + +void tst_QWebEnginePage::recommendedStateAuto() +{ + qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged); + connect(&page, &QWebEnginePage::recommendedStateChanged, &page, &QWebEnginePage::setLifecycleState); + + page.load(QStringLiteral("qrc:/resources/lifecycle.html")); + QTRY_COMPARE(lifecycleSpy.count(), 2); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + + page.setVisible(true); + QTRY_COMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + + page.setVisible(false); + QTRY_COMPARE(lifecycleSpy.count(), 2); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(lifecycleSpy.count(), 3); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + + QWebEnginePage devTools; + page.setDevToolsPage(&devTools); + QTRY_COMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + + page.setDevToolsPage(nullptr); + QTRY_COMPARE(lifecycleSpy.count(), 2); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); +} + +void tst_QWebEnginePage::setLifecycleStateAndReload() +{ + qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); + + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged); + + page.load(QStringLiteral("qrc:/resources/lifecycle.html")); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); + + page.triggerAction(QWebEnginePage::Reload); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); + + page.triggerAction(QWebEnginePage::Reload); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); + QTRY_COMPARE(loadSpy.count(), 1); + QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); +} + void tst_QWebEnginePage::editActionsWithExplicitFocus() { QWebEngineView view; @@ -3492,6 +4145,44 @@ void tst_QWebEnginePage::editActionsWithFocusOnIframe() QCOMPARE(page->selectedText(), QStringLiteral("inner")); } +void tst_QWebEnginePage::editActionsWithoutSelection() +{ + QWebEngineView view; + QWebEnginePage *page = view.page(); + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + + QSignalSpy loadFinishedSpy(page, &QWebEnginePage::loadFinished); + QSignalSpy selectionChangedSpy(page, &QWebEnginePage::selectionChanged); + QSignalSpy actionChangedSpy(page->action(QWebEnginePage::SelectAll), &QAction::changed); + + page->setHtml(QString("<html><body><div>foo bar</div></body></html>")); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(actionChangedSpy.count(), 1); + + QVERIFY(!page->action(QWebEnginePage::Cut)->isEnabled()); + QVERIFY(!page->action(QWebEnginePage::Copy)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Paste)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Undo)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Redo)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled()); + QVERIFY(!page->action(QWebEnginePage::Unselect)->isEnabled()); + + page->triggerAction(QWebEnginePage::SelectAll); + QTRY_COMPARE(selectionChangedSpy.count(), 1); + QCOMPARE(page->hasSelection(), true); + QCOMPARE(page->selectedText(), QStringLiteral("foo bar")); + + QVERIFY(page->action(QWebEnginePage::Cut)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Copy)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Paste)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Undo)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Redo)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::PasteAndMatchStyle)->isEnabled()); + QVERIFY(page->action(QWebEnginePage::Unselect)->isEnabled()); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc index cf32486e7..013a307de 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.qrc @@ -23,6 +23,7 @@ <file>resources/foo.txt</file> <file>resources/bar.txt</file> <file>resources/path with spaces.txt</file> + <file>resources/lifecycle.html</file> </qresource> <qresource prefix='/shared'> <file alias='notification.html'>../../shared/data/notification.html</file> diff --git a/tests/auto/widgets/qwebengineprofile/BLACKLIST b/tests/auto/widgets/qwebengineprofile/BLACKLIST index fc1c957dd..55806eec4 100644 --- a/tests/auto/widgets/qwebengineprofile/BLACKLIST +++ b/tests/auto/widgets/qwebengineprofile/BLACKLIST @@ -1,5 +1,3 @@ -[clearDataFromCache] -* [disableCache] * diff --git a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp index 9a2ee9311..487e70d28 100644 --- a/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp +++ b/tests/auto/widgets/qwebenginescript/tst_qwebenginescript.cpp @@ -159,6 +159,14 @@ void tst_QWebEngineScript::loadEvents() QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + // After discard + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setLifecycleState(QWebEnginePage::LifecycleState::Active); + QTRY_COMPARE(page.spy.count(), 1); + QCOMPARE(page.spy.takeFirst().value(0).toBool(), true); + QCOMPARE(page.eval("window.log", QWebEngineScript::MainWorld).toStringList(), expected); + QCOMPARE(page.eval("window.log", QWebEngineScript::ApplicationWorld).toStringList(), expected); + // Multiple frames page.load(QUrl("qrc:/resources/test_iframe_main.html")); QTRY_COMPARE(page.spy.count(), 1); @@ -531,6 +539,11 @@ void tst_QWebEngineScript::navigation() page.setUrl(url3); QTRY_COMPARE(spyTextChanged.count(), 3); QCOMPARE(testObject.text(), url3); + + page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + page.setUrl(url1); + QTRY_COMPARE(spyTextChanged.count(), 4); + QCOMPARE(testObject.text(), url1); } // Try to set TestObject::text to an invalid UTF-16 string. diff --git a/tests/auto/widgets/qwebengineview/BLACKLIST b/tests/auto/widgets/qwebengineview/BLACKLIST index 9a574a687..9087067f5 100644 --- a/tests/auto/widgets/qwebengineview/BLACKLIST +++ b/tests/auto/widgets/qwebengineview/BLACKLIST @@ -1,11 +1,5 @@ -[doNotSendMouseKeyboardEventsWhenDisabled] -windows - [microFocusCoordinates] osx [textSelectionOutOfInputField] * - -[inputContextQueryInput] -windows diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index d3ea27fc2..f542c09d9 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -201,6 +201,7 @@ private Q_SLOTS: void setViewDeletesImplicitPage(); void setPagePreservesExplicitPage(); void setViewPreservesExplicitPage(); + void closeDiscardsPage(); }; // This will be called before the first test function is executed. @@ -2194,6 +2195,22 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QVERIFY(!view.hasSelection()); QVERIFY(view.page()->selectedText().isEmpty()); + // Select text by ctrl+a + QTest::keyClick(view.windowHandle(), Qt::Key_A, Qt::ControlModifier); + QVERIFY(selectionChangedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 3); + QVERIFY(view.hasSelection()); + QCOMPARE(view.page()->selectedText(), QString("This is a text")); + + // Deselect text via discard+undiscard + view.hide(); + view.page()->setLifecycleState(QWebEnginePage::LifecycleState::Discarded); + view.show(); + QVERIFY(loadFinishedSpy.wait()); + QCOMPARE(selectionChangedSpy.count(), 4); + QVERIFY(!view.hasSelection()); + QVERIFY(view.page()->selectedText().isEmpty()); + selectionChangedSpy.clear(); view.setHtml("<html><body>" " This is a text" @@ -3258,5 +3275,21 @@ void tst_QWebEngineView::setViewPreservesExplicitPage() QVERIFY(explicitPage1); // should not be deleted } +void tst_QWebEngineView::closeDiscardsPage() +{ + QWebEngineProfile profile; + QWebEnginePage page(&profile); + QWebEngineView view; + view.setPage(&page); + view.resize(300, 300); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QCOMPARE(page.isVisible(), true); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); + view.close(); + QCOMPARE(page.isVisible(), false); + QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" |