diff options
Diffstat (limited to 'tests/auto')
10 files changed, 834 insertions, 3 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/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index 90b768ac7..8b8eb8636 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,8 @@ static const QStringList expectedAPI = QStringList() << "QQuickWebEngineDownloadItem.type --> DownloadType" << "QQuickWebEngineDownloadItem.typeChanged() --> void" << "QQuickWebEngineDownloadItem.view --> QQuickWebEngineView*" + << "QQuickWebEngineDownloadItem.url --> QUrl" + << "QQuickWebEngineDownloadItem.suggestedFileName --> QString" << "QQuickWebEngineFileDialogRequest.FileModeOpen --> FileMode" << "QQuickWebEngineFileDialogRequest.FileModeOpenMultiple --> FileMode" << "QQuickWebEngineFileDialogRequest.FileModeSave --> FileMode" @@ -277,6 +280,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 +606,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 +641,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 +706,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 +731,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 +754,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 +830,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/data/tst_download.qml b/tests/auto/quick/qmltests/data/tst_download.qml index 5eb704cce..c8f783b03 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,8 @@ TestWebEngineView { property bool cancelDownload: false property var downloadState: [] property var downloadInterruptReason: null + property url downloadUrl: "" + property string suggestedFileName: "" function urlToPath(url) { var path = url.toString() @@ -81,6 +83,8 @@ TestWebEngineView { download.path = "testfile.zip" download.accept() } + downloadUrl = download.url + suggestedFileName = download.suggestedFileName } onDownloadFinished: { receivedBytes = download.receivedBytes; @@ -106,6 +110,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 +121,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 +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) tryCompare(downloadState, "1", WebEngineDownloadItem.DownloadInProgress) downloadFinishedSpy.wait() @@ -138,6 +148,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) diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index bc474457a..02b46bc6b 100644 --- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -869,6 +869,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 +891,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); @@ -915,6 +917,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 +928,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 +949,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); @@ -975,6 +980,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 +994,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 +1021,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 +1043,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); @@ -1056,6 +1065,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 +1077,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 +1100,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 +1121,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(); diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST index e6d50da39..3965ec8d3 100644 --- a/tests/auto/widgets/qwebenginepage/BLACKLIST +++ b/tests/auto/widgets/qwebenginepage/BLACKLIST @@ -15,3 +15,4 @@ 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 dd1140a4f..e361dbf0a 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -202,6 +202,19 @@ 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(); + private: static QPoint elementCenter(QWebEnginePage *page, const QString &id); @@ -573,7 +586,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]); @@ -3398,6 +3411,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)); +} + 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/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/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" |