diff options
Diffstat (limited to 'tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp')
-rw-r--r-- | tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 1671 |
1 files changed, 1251 insertions, 420 deletions
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index c118bd718..39a28759c 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -1,5 +1,5 @@ /* - Copyright (C) 2016 The Qt Company Ltd. + Copyright (C) 2023 The Qt Company Ltd. Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in> Copyright (C) 2010 Holger Hans Peter Freyther @@ -20,7 +20,9 @@ */ #include <widgetutil.h> +#include <QtNetwork/private/qtnetworkglobal_p.h> #include <QtWebEngineCore/qtwebenginecore-config.h> +#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h> #include <QByteArray> #include <QClipboard> #include <QDir> @@ -34,6 +36,7 @@ #include <QPaintEngine> #include <QPushButton> #include <QScreen> +#include <QWheelEvent> #if defined(QT_STATEMACHINE_LIB) # include <QStateMachine> #endif @@ -47,7 +50,10 @@ #include <qnetworkcookiejar.h> #include <qnetworkreply.h> #include <qnetworkrequest.h> +#include <qwebengineclienthints.h> #include <qwebenginedownloadrequest.h> +#include <qwebenginedesktopmediarequest.h> +#include <qwebenginefilesystemaccessrequest.h> #include <qwebenginefindtextresult.h> #include <qwebenginefullscreenrequest.h> #include <qwebenginehistory.h> @@ -61,17 +67,21 @@ #include <qwebenginescript.h> #include <qwebenginescriptcollection.h> #include <qwebenginesettings.h> +#include <qwebengineurlrequestinterceptor.h> #include <qwebengineurlrequestjob.h> #include <qwebengineurlscheme.h> #include <qwebengineurlschemehandler.h> #include <qwebengineview.h> #include <qimagewriter.h> +#include <QColorSpace> +#include <QQuickRenderControl> +#include <QQuickWindow> static void removeRecursive(const QString& dirname) { QDir dir(dirname); QFileInfoList entries(dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot)); - for (int i = 0; i < entries.count(); ++i) + for (int i = 0; i < entries.size(); ++i) if (entries[i].isDir()) removeRecursive(entries[i].filePath()); else @@ -79,6 +89,13 @@ static void removeRecursive(const QString& dirname) QDir().rmdir(dirname); } +struct TestBasePage : QWebEnginePage +{ + explicit TestBasePage(QWebEngineProfile *profile, QObject *parent = nullptr) : QWebEnginePage(profile, parent) { } + explicit TestBasePage(QObject *parent = nullptr) : QWebEnginePage(parent) { } + QSignalSpy loadSpy { this, &QWebEnginePage::loadFinished }; +}; + class tst_QWebEnginePage : public QObject { Q_OBJECT @@ -95,13 +112,17 @@ public Q_SLOTS: private Q_SLOTS: void initTestCase(); void cleanupTestCase(); + void comboBoxPopupPositionAfterMove_data(); void comboBoxPopupPositionAfterMove(); + void comboBoxPopupPositionAfterChildMove_data(); void comboBoxPopupPositionAfterChildMove(); void acceptNavigationRequest(); void acceptNavigationRequestNavigationType(); void acceptNavigationRequestRelativeToNothing(); +#ifndef Q_OS_MACOS void geolocationRequestJS_data(); void geolocationRequestJS(); +#endif void loadFinished(); void actionStates(); void pasteImage(); @@ -142,7 +163,7 @@ private Q_SLOTS: #endif void openWindowDefaultSize(); -#ifdef Q_OS_MAC +#ifdef Q_OS_MACOS void macCopyUnicodeToClipboard(); #endif @@ -150,7 +171,8 @@ private Q_SLOTS: void runJavaScriptDisabled(); void runJavaScriptFromSlot(); void fullScreenRequested(); - void quotaRequested(); + void requestQuota_data(); + void requestQuota(); // Tests from tst_QWebEngineFrame @@ -212,7 +234,13 @@ private Q_SLOTS: void notificationPermission_data(); void notificationPermission(); void sendNotification(); + void clipboardReadWritePermissionInitialState_data(); + void clipboardReadWritePermissionInitialState(); + void clipboardReadWritePermission_data(); + void clipboardReadWritePermission(); void contentsSize(); + void localFontAccessPermission_data(); + void localFontAccessPermission(); void setLifecycleState(); void setVisible(); @@ -233,6 +261,8 @@ private Q_SLOTS: void editActionsWithoutSelection(); void customUserAgentInNewTab(); + void openNewTabInDifferentProfile_data(); + void openNewTabInDifferentProfile(); void renderProcessCrashed(); void renderProcessPid(); void backgroundColor(); @@ -245,20 +275,50 @@ private Q_SLOTS: void testChooseFilesParameters(); void fileSystemAccessDialog(); + void localToRemoteNavigation(); + void clientHints_data(); + void clientHints(); + void childFrameInput(); + void openLinkInNewPageWithWebWindowType_data(); + void openLinkInNewPageWithWebWindowType(); + void keepInterceptorAfterNewWindowRequested(); + void chooseDesktopMedia(); + private: - static QPoint elementCenter(QWebEnginePage *page, const QString &id); static bool isFalseJavaScriptResult(QWebEnginePage *page, const QString &javaScript); static bool isTrueJavaScriptResult(QWebEnginePage *page, const QString &javaScript); static bool isEmptyListJavaScriptResult(QWebEnginePage *page, const QString &javaScript); QWebEngineView* m_view; QWebEnginePage* m_page; + QScopedPointer<QPointingDevice> s_touchDevice = + QScopedPointer<QPointingDevice>(QTest::createTouchDevice()); + QString tmpDirPath() const { static QString tmpd = QDir::tempPath() + "/tst_qwebenginepage-" + QDateTime::currentDateTime().toString(QLatin1String("yyyyMMddhhmmss")); return tmpd; } + + void makeClick(const QPointer<QWindow> window, bool withTouch = false, + const QPoint &p = QPoint()) + { + QVERIFY2(window, "window is gone"); + if (!withTouch) { + QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), p); + } else { + QTest::touchEvent(window, s_touchDevice.get()).press(1, p); + QTest::touchEvent(window, s_touchDevice.get()).release(1, p); + } + }; + + void makeScroll(QWidget *target, QPointF pos, QPoint globalPos, QPoint angleDelta) + { + QWheelEvent ev(pos, globalPos, QPoint(0, 0), angleDelta, Qt::NoButton, Qt::NoModifier, + Qt::NoScrollPhase, false); + QGuiApplication::sendEvent(target, &ev); + } }; tst_QWebEnginePage::tst_QWebEnginePage() @@ -304,6 +364,14 @@ void tst_QWebEnginePage::initTestCase() QWebEngineUrlScheme echo("echo"); echo.setSyntax(QWebEngineUrlScheme::Syntax::Path); QWebEngineUrlScheme::registerScheme(echo); + + QWebEngineUrlScheme local("local"); + local.setFlags(QWebEngineUrlScheme::LocalScheme); + QWebEngineUrlScheme::registerScheme(local); + + QWebEngineUrlScheme remote("remote"); + remote.setFlags(QWebEngineUrlScheme::CorsEnabled); + QWebEngineUrlScheme::registerScheme(remote); } void tst_QWebEnginePage::cleanupTestCase() @@ -356,15 +424,15 @@ void tst_QWebEnginePage::acceptNavigationRequest() page.setHtml(QString("<html><body><form name='tstform' action='foo' method='get'>" "<input type='text'><input type='submit'></form></body></html>"), QUrl("echo:/")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); evaluateJavaScriptSync(&page, "tstform.submit();"); - QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(loadSpy.size(), 2); // Content hasn't changed so the form submit will still work page.m_acceptNavigationRequest = true; evaluateJavaScriptSync(&page, "tstform.submit();"); - QTRY_COMPARE(loadSpy.count(), 3); + QTRY_COMPARE(loadSpy.size(), 3); // Now the content has changed QCOMPARE(toPlainTextSync(&page), QString("/foo?")); @@ -400,6 +468,7 @@ private: bool m_allowGeolocation; }; +#ifndef Q_OS_MACOS void tst_QWebEnginePage::geolocationRequestJS_data() { QTest::addColumn<bool>("allowed"); @@ -422,7 +491,7 @@ void tst_QWebEnginePage::geolocationRequestJS() QSignalSpy spyLoadFinished(newPage, SIGNAL(loadFinished(bool))); newPage->setHtml(QString("<html><body>test</body></html>"), QUrl("qrc://secure/origin")); - QTRY_COMPARE_WITH_TIMEOUT(spyLoadFinished.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spyLoadFinished.size(), 1, 20000); // Geolocation is only enabled for visible WebContents. view.show(); @@ -439,6 +508,7 @@ void tst_QWebEnginePage::geolocationRequestJS() QEXPECT_FAIL("", "No location service available.", Continue); QCOMPARE(result, errorCode); } +#endif void tst_QWebEnginePage::loadFinished() { @@ -449,19 +519,19 @@ void tst_QWebEnginePage::loadFinished() page.load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," "<head><meta http-equiv='refresh' content='1'></head>foo \">" "<frame src=\"data:text/html,bar\"></frameset>")); - QTRY_COMPARE_WITH_TIMEOUT(spyLoadFinished.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spyLoadFinished.size(), 1, 20000); QEXPECT_FAIL("", "Behavior change: Load signals are emitted only for the main frame in QtWebEngine.", Continue); - QTRY_VERIFY_WITH_TIMEOUT(spyLoadStarted.count() > 1, 100); + QTRY_VERIFY_WITH_TIMEOUT(spyLoadStarted.size() > 1, 100); QEXPECT_FAIL("", "Behavior change: Load signals are emitted only for the main frame in QtWebEngine.", Continue); - QTRY_VERIFY_WITH_TIMEOUT(spyLoadFinished.count() > 1, 100); + QTRY_VERIFY_WITH_TIMEOUT(spyLoadFinished.size() > 1, 100); spyLoadFinished.clear(); page.load(QUrl("data:text/html,<frameset cols=\"25%,75%\"><frame src=\"data:text/html," "foo \"><frame src=\"data:text/html,bar\"></frameset>")); - QTRY_COMPARE(spyLoadFinished.count(), 1); - QCOMPARE(spyLoadFinished.count(), 1); + QTRY_COMPARE(spyLoadFinished.size(), 1); + QCOMPARE(spyLoadFinished.size(), 1); } void tst_QWebEnginePage::actionStates() @@ -518,6 +588,7 @@ void tst_QWebEnginePage::pasteImage() QByteArray data = evaluateJavaScriptSync(page, "window.myImageDataURL").toByteArray(); data.remove(0, data.indexOf(";base64,") + 8); QImage image = QImage::fromData(QByteArray::fromBase64(data), "PNG"); + image.setColorSpace(origImage.colorSpace()); if (image.format() == QImage::Format_RGB32) image.reinterpretAsFormat(QImage::Format_ARGB32); QCOMPARE(image, origImage); @@ -547,7 +618,7 @@ void tst_QWebEnginePage::consoleOutput() ConsolePage page; // We don't care about the result but want this to be synchronous evaluateJavaScriptSync(&page, "this is not valid JavaScript"); - QCOMPARE(page.messages.count(), 1); + QCOMPARE(page.messages.size(), 1); QCOMPARE(page.lineNumbers.at(0), 1); } @@ -606,40 +677,40 @@ void tst_QWebEnginePage::acceptNavigationRequestNavigationType() QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); page.load(QUrl("qrc:///resources/script.html")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); - QTRY_COMPARE(page.navigations.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); + QTRY_COMPARE(page.navigations.size(), 1); page.load(QUrl("qrc:///resources/content.html")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 2, 20000); - QTRY_COMPARE(page.navigations.count(), 2); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 2, 20000); + QTRY_COMPARE(page.navigations.size(), 2); page.triggerAction(QWebEnginePage::Stop); QVERIFY(page.history()->canGoBack()); page.triggerAction(QWebEnginePage::Back); - QTRY_COMPARE(loadSpy.count(), 3); - QTRY_COMPARE(page.navigations.count(), 3); + QTRY_COMPARE(loadSpy.size(), 3); + QTRY_COMPARE(page.navigations.size(), 3); page.triggerAction(QWebEnginePage::Reload); - QTRY_COMPARE(loadSpy.count(), 4); - QTRY_COMPARE(page.navigations.count(), 4); - - page.load(QUrl("qrc:///resources/reload.html")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 6, 20000); - QTRY_COMPARE(page.navigations.count(), 6); + QTRY_COMPARE(loadSpy.size(), 4); + QTRY_COMPARE(page.navigations.size(), 4); QList<QWebEngineNavigationRequest::NavigationType> expectedList; expectedList << QWebEngineNavigationRequest::TypedNavigation << QWebEngineNavigationRequest::TypedNavigation << QWebEngineNavigationRequest::BackForwardNavigation - << QWebEngineNavigationRequest::ReloadNavigation - << QWebEngineNavigationRequest::TypedNavigation - << QWebEngineNavigationRequest::RedirectNavigation; + << QWebEngineNavigationRequest::ReloadNavigation; // client side redirect + page.load(QUrl("qrc:///resources/reload.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 6, 20000); + QTRY_COMPARE(page.navigations.size(), 6); + expectedList += { QWebEngineNavigationRequest::TypedNavigation, QWebEngineNavigationRequest::RedirectNavigation }; + + page.load(QUrl("qrc:///resources/redirect.html")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 7, 20000); - QTRY_COMPARE(page.navigations.count(), 8); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 7, 20000); + QTRY_COMPARE(page.navigations.size(), 8); expectedList += { QWebEngineNavigationRequest::TypedNavigation, QWebEngineNavigationRequest::RedirectNavigation }; // server side redirect @@ -660,18 +731,18 @@ void tst_QWebEnginePage::acceptNavigationRequestNavigationType() }); QVERIFY(server.start()); page.load(QUrl(server.url("/redirect1.html"))); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 8, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 8, 20000); expectedList += { QWebEngineNavigationRequest::TypedNavigation, QWebEngineNavigationRequest::RedirectNavigation, QWebEngineNavigationRequest::RedirectNavigation }; - for (int i = 0; i < expectedList.count(); ++i) { - QTRY_VERIFY(i < page.navigations.count()); + for (int i = 0; i < expectedList.size(); ++i) { + QTRY_VERIFY(i < page.navigations.size()); QCOMPARE(page.navigations[i].type, expectedList[i]); } - QVERIFY(expectedList.count() == page.navigations.count()); + QVERIFY(expectedList.size() == page.navigations.size()); } // Relative url without base url. @@ -684,18 +755,18 @@ void tst_QWebEnginePage::acceptNavigationRequestRelativeToNothing() page.setHtml(QString("<html><body><a id='link' href='S0'>limited time offer</a></body></html>"), /* baseUrl: */ QUrl()); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 2, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 2, 20000); page.setHtml(QString("<html><body><a id='link' href='S0'>limited time offer</a></body></html>"), /* baseUrl: */ QString("qrc:/")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 3, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 3, 20000); page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 4, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 4, 20000); // The two setHtml and the second click are counted, while the // first click is ignored due to the empty base url. - QCOMPARE(page.navigations.count(), 3); + QCOMPARE(page.navigations.size(), 3); QCOMPARE(page.navigations[0].type, QWebEngineNavigationRequest::TypedNavigation); QCOMPARE(page.navigations[1].type, QWebEngineNavigationRequest::TypedNavigation); QCOMPARE(page.navigations[2].type, QWebEngineNavigationRequest::LinkClickedNavigation); @@ -714,20 +785,19 @@ void tst_QWebEnginePage::popupFormSubmission() page.setHtml("<form name='form1' method=get action='' target='myNewWin'>" " <input type='hidden' name='foo' value='bar'>" "</form>", QUrl("echo:")); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 20000); page.runJavaScript("window.open('', 'myNewWin', 'width=500,height=300,toolbar=0');"); evaluateJavaScriptSync(&page, "document.form1.submit();"); - QTRY_COMPARE(windowCreatedSpy.count(), 1); + QTRY_COMPARE(windowCreatedSpy.size(), 1); // The number of popup created should be one. QVERIFY(page.createdWindows.size() == 1); QTRY_VERIFY(!page.createdWindows[0]->url().isEmpty()); - QString url = page.createdWindows[0]->url().toString(); // Check if the form submission was OK. - QVERIFY(url.contains("?foo=bar")); + QTRY_VERIFY(page.createdWindows[0]->url().toString().contains("?foo=bar")); } class TestNetworkManager : public QNetworkAccessManager @@ -768,16 +838,16 @@ void tst_QWebEnginePage::multipleProfilesAndLocalStorage() page1.setHtml(QString("<html><body> </body></html>"), QUrl("http://wwww.example.com")); page2.setHtml(QString("<html><body> </body></html>"), QUrl("http://wwww.example.com")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy1.count(), 1, 20000); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy2.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy1.size(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy2.size(), 1, 20000); evaluateJavaScriptSync(&page1, "localStorage.setItem('test', 'value1');"); evaluateJavaScriptSync(&page2, "localStorage.setItem('test', 'value2');"); page1.setHtml(QString("<html><body> </body></html>"), QUrl("http://wwww.example.com")); page2.setHtml(QString("<html><body> </body></html>"), QUrl("http://wwww.example.com")); - QTRY_COMPARE(loadSpy1.count(), 2); - QTRY_COMPARE(loadSpy2.count(), 2); + QTRY_COMPARE(loadSpy1.size(), 2); + QTRY_COMPARE(loadSpy2.size(), 2); QVariant s1 = evaluateJavaScriptSync(&page1, "localStorage.getItem('test')"); QCOMPARE(s1.toString(), QString("value1")); @@ -826,7 +896,7 @@ void tst_QWebEnginePage::textSelection() QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); page.setHtml(content); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); // these actions must exist QVERIFY(page.action(QWebEnginePage::SelectAll) != 0); @@ -853,7 +923,7 @@ void tst_QWebEnginePage::textSelection() // navigate away and check that selection is cleared page.load(QUrl("about:blank")); - QTRY_COMPARE(loadSpy.count(), 2); + QTRY_COMPARE(loadSpy.size(), 2); QVERIFY(!page.hasSelection()); QVERIFY(page.selectedText().isEmpty()); @@ -874,7 +944,7 @@ void tst_QWebEnginePage::backActionUpdate() QVERIFY(!action->isEnabled()); page->load(QUrl("qrc:///resources/framedindex.html")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); QVERIFY(!action->isEnabled()); auto firstAnchorCenterInFrame = [](QWebEnginePage *page, const QString &frameName) { @@ -886,7 +956,7 @@ void tst_QWebEnginePage::backActionUpdate() "return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" "})()").toList(); - if (rectList.count() != 2) { + if (rectList.size() != 2) { qWarning("firstAnchorCenterInFrame failed."); return QPoint(); } @@ -913,8 +983,8 @@ void tst_QWebEnginePage::localStorageVisibility() QSignalSpy loadSpy2(&webPage2, &QWebEnginePage::loadFinished); webPage1.setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/")); webPage2.setHtml(QString("<html><body>test</body></html>"), QUrl("http://www.example.com/")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy1.count(), 1, 20000); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy2.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy1.size(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy2.size(), 1, 20000); // The attribute determines the visibility of the window.localStorage object. QVERIFY(evaluateJavaScriptSync(&webPage1, QString("(window.localStorage != undefined)")).toBool()); @@ -927,13 +997,14 @@ void tst_QWebEnginePage::localStorageVisibility() // ...first check second page (for storage to appear) as applying settings is batched and done asynchronously QTRY_VERIFY(evaluateJavaScriptSync(&webPage2, QString("(window.localStorage != undefined)")).toBool()); // Switching the feature off does not actively remove the object from webPage1. - QVERIFY(evaluateJavaScriptSync(&webPage1, QString("(window.localStorage != undefined)")).toBool()); +// FIXME: 94-based: now it does +// QVERIFY(evaluateJavaScriptSync(&webPage1, QString("(window.localStorage != undefined)")).toBool()); // The object disappears only after reloading. webPage1.triggerAction(QWebEnginePage::Reload); webPage2.triggerAction(QWebEnginePage::Reload); - QTRY_COMPARE(loadSpy1.count(), 2); - QTRY_COMPARE(loadSpy2.count(), 2); + QTRY_COMPARE(loadSpy1.size(), 2); + QTRY_COMPARE(loadSpy2.size(), 2); QVERIFY(!evaluateJavaScriptSync(&webPage1, QString("(window.localStorage != undefined)")).toBool()); QVERIFY(evaluateJavaScriptSync(&webPage2, QString("(window.localStorage != undefined)")).toBool()); } @@ -1034,7 +1105,7 @@ void tst_QWebEnginePage::testJSPrompt() bool res; QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); page.setHtml(QStringLiteral("<html><body></body></html>")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); // OK + QString() res = evaluateJavaScriptSync(&page, @@ -1068,7 +1139,7 @@ void tst_QWebEnginePage::findText() // Showing is required, otherwise all find operations fail. m_view->show(); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); // Select whole page contents. QTRY_VERIFY(m_view->page()->action(QWebEnginePage::SelectAll)->isEnabled()); @@ -1082,7 +1153,7 @@ void tst_QWebEnginePage::findText() QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); m_view->findText("", {}, callbackSpy.ref()); QVERIFY(callbackSpy.wasCalled()); - QCOMPARE(signalSpy.count(), 1); + QCOMPARE(signalSpy.size(), 1); QTRY_COMPARE(m_view->selectedText(), QString("foo bar")); } @@ -1093,7 +1164,7 @@ void tst_QWebEnginePage::findText() QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); m_view->findText("Will not be found", {}, callbackSpy.ref()); QCOMPARE(callbackSpy.waitForResult().numberOfMatches(), 0); - QTRY_COMPARE(signalSpy.count(), 1); + QTRY_COMPARE(signalSpy.size(), 1); auto result = signalSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 0); QTRY_VERIFY(m_view->selectedText().isEmpty()); @@ -1110,7 +1181,7 @@ void tst_QWebEnginePage::findText() QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); m_view->findText("foo", {}, callbackSpy.ref()); QVERIFY(callbackSpy.waitForResult().numberOfMatches() > 0); - QTRY_COMPARE(signalSpy.count(), 1); + QTRY_COMPARE(signalSpy.size(), 1); QTRY_VERIFY(m_view->selectedText().isEmpty()); } @@ -1121,7 +1192,7 @@ void tst_QWebEnginePage::findText() QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); m_view->findText("", {}, callbackSpy.ref()); QTRY_VERIFY(callbackSpy.wasCalled()); - QTRY_COMPARE(signalSpy.count(), 1); + QTRY_COMPARE(signalSpy.size(), 1); QTRY_COMPARE(m_view->selectedText(), QString("foo")); } @@ -1131,7 +1202,7 @@ void tst_QWebEnginePage::findText() QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); m_view->findText("foo", {}); m_view->findText("foo", {}); - QTRY_COMPARE(signalSpy.count(), 2); + QTRY_COMPARE(signalSpy.size(), 2); QTRY_VERIFY(m_view->selectedText().isEmpty()); QCOMPARE(signalSpy.at(0).value(0).value<QWebEngineFindTextResult>().numberOfMatches(), 0); @@ -1143,7 +1214,7 @@ void tst_QWebEnginePage::findTextResult() { QSignalSpy findTextSpy(m_view->page(), &QWebEnginePage::findTextFinished); auto signalResult = [&findTextSpy]() -> QList<int> { - if (findTextSpy.count() != 1) + if (findTextSpy.size() != 1) return QList<int>({-1, -1}); auto r = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); return QList<int>({ r.numberOfMatches(), r.activeMatch() }); @@ -1155,7 +1226,7 @@ void tst_QWebEnginePage::findTextResult() QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(findTextSync(m_page, ""), false); QCOMPARE(signalResult(), QList<int>({0, 0})); @@ -1184,7 +1255,7 @@ void tst_QWebEnginePage::findTextSuccessiveShouldCallAllCallbacks() CallbackSpy<QWebEngineFindTextResult> spy5; QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool))); m_view->setHtml(QString("<html><head></head><body><div>abcdefg abcdefg abcdefg abcdefg abcdefg</div></body></html>")); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); m_page->findText("abcde", {}, spy1.ref()); m_page->findText("abcd", {}, spy2.ref()); m_page->findText("abc", {}, spy3.ref()); @@ -1206,7 +1277,7 @@ void tst_QWebEnginePage::findTextCalledOnMatch() m_view->resize(800, 600); m_view->show(); m_view->setHtml(QString("<html><head></head><body><div>foo bar</div></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); // CALLBACK bool callbackCalled = false; @@ -1243,12 +1314,12 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal() m_view->resize(800, 600); m_view->show(); m_view->setHtml(QString("<html><head></head><body><div>foo bar foo bar foo</div></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); // Iterate over all "foo" matches. for (int i = 1; i <= 3; ++i) { m_view->page()->findText("foo", {}); - QTRY_COMPARE(findTextSpy.count(), 1); + QTRY_COMPARE(findTextSpy.size(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 3); QCOMPARE(result.activeMatch(), i); @@ -1256,28 +1327,28 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal() // The last match is followed by the fist one. m_view->page()->findText("foo", {}); - QTRY_COMPARE(findTextSpy.count(), 1); + QTRY_COMPARE(findTextSpy.size(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 3); QCOMPARE(result.activeMatch(), 1); // The first match is preceded by the last one. m_view->page()->findText("foo", QWebEnginePage::FindBackward); - QTRY_COMPARE(findTextSpy.count(), 1); + QTRY_COMPARE(findTextSpy.size(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 3); QCOMPARE(result.activeMatch(), 3); // Finding another word resets the activeMatch. m_view->page()->findText("bar", {}); - QTRY_COMPARE(findTextSpy.count(), 1); + QTRY_COMPARE(findTextSpy.size(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 2); QCOMPARE(result.activeMatch(), 1); // If no match activeMatch is 0. m_view->page()->findText("bla", {}); - QTRY_COMPARE(findTextSpy.count(), 1); + QTRY_COMPARE(findTextSpy.size(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 0); QCOMPARE(result.activeMatch(), 0); @@ -1287,45 +1358,60 @@ static QWindow *findNewTopLevelWindow(const QWindowList &oldTopLevelWindows) { const auto tlws = QGuiApplication::topLevelWindows(); for (auto w : tlws) { - if (!oldTopLevelWindows.contains(w)) { + // note 'offscreen' window is a top-level window + if (!oldTopLevelWindows.contains(w) + && !QQuickRenderControl::renderWindowFor(qobject_cast<QQuickWindow *>(w))) { return w; } } return nullptr; } +void tst_QWebEnginePage::comboBoxPopupPositionAfterMove_data() +{ + QTest::addColumn<bool>("withTouch"); + QTest::addRow("mouse") << false; + QTest::addRow("touch") << true; +} + void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() { +#if defined(Q_OS_MACOS) && (defined(__arm64__) || defined(__aarch64__)) + QSKIP("This test crashes for Apple M1"); +#endif QWebEngineView view; + QTRY_VERIFY(QGuiApplication::primaryScreen()); view.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft()); view.resize(640, 480); view.show(); - - QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QSignalSpy spyLoadFinished(&view, SIGNAL(loadFinished(bool))); view.setHtml(QLatin1String("<html><head></head><body><select id='foo'>" "<option>fran</option><option>troz</option>" "</select></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(spyLoadFinished.size(), 1); const auto oldTlws = QGuiApplication::topLevelWindows(); - QWindow *window = view.windowHandle(); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - elementCenter(view.page(), "foo")); - + QFETCH(bool, withTouch); + QPointer<QWindow> window = view.windowHandle(); + auto pos = elementCenter(view.page(), "foo"); + makeClick(window, withTouch, pos); QWindow *popup = nullptr; - QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); + QTRY_VERIFY((popup = findNewTopLevelWindow(oldTlws))); + QVERIFY(QTest::qWaitForWindowExposed(popup)); + QTRY_VERIFY(popup->width() > 0 && popup->height() > 0); QTRY_VERIFY(QGuiApplication::topLevelWindows().contains(popup)); QTRY_VERIFY(!popup->position().isNull()); QPoint popupPos = popup->position(); - + QPointer<QWindow> pw(popup); // Close the popup by clicking somewhere into the page. - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(1, 1)); + makeClick(window, withTouch, QPoint(1, 1)); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); - + QTRY_VERIFY(!pw); auto jsViewPosition = [&view]() { QLatin1String script("(function() { return [window.screenX, window.screenY]; })()"); QVariantList posList = evaluateJavaScriptSync(view.page(), script).toList(); - if (posList.count() != 2) { + if (posList.size() != 2) { qWarning("jsViewPosition failed."); return QPoint(); } @@ -1337,18 +1423,28 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterMove() const QPoint offset(12, 13); view.move(view.pos() + offset); QTRY_COMPARE(jsViewPosition(), view.pos()); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - elementCenter(view.page(), "foo")); - QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); + makeClick(window, withTouch, elementCenter(view.page(), "foo")); + QTRY_VERIFY((popup = findNewTopLevelWindow(oldTlws))); + QTRY_VERIFY(popup->width() > 0 && popup->height() > 0); QTRY_VERIFY(QGuiApplication::topLevelWindows().contains(popup)); QTRY_VERIFY(!popup->position().isNull()); QCOMPARE(popupPos + offset, popup->position()); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), QPoint(1, 1)); + makeClick(window, withTouch, QPoint(1, 1)); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); } +void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove_data() +{ + QTest::addColumn<bool>("withTouch"); + QTest::addRow("mouse") << false; + QTest::addRow("touch") << true; +} + void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() { +#if defined(Q_OS_MACOS) && (defined(__arm64__) || defined(__aarch64__)) + QSKIP("This test crashes for Apple M1"); +#endif QWidget mainWidget; mainWidget.setLayout(new QHBoxLayout); @@ -1359,29 +1455,33 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() mainWidget.layout()->addWidget(&view); QScreen *screen = QGuiApplication::primaryScreen(); + Q_ASSERT(screen); mainWidget.move(screen->availableGeometry().topLeft()); mainWidget.resize(640, 480); mainWidget.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mainWidget)); QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); view.setHtml(QLatin1String("<html><head></head><body><select autofocus id='foo'>" "<option value=\"narf\">narf</option><option>zort</option>" "</select></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); const auto oldTlws = QGuiApplication::topLevelWindows(); - QWindow *window = view.window()->windowHandle(); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), elementCenter(view.page(), "foo"))); + + QFETCH(bool, withTouch); + QPointer<QWindow> window = view.window()->windowHandle(); + makeClick(window, withTouch, view.mapTo(view.window(), elementCenter(view.page(), "foo"))); QWindow *popup = nullptr; - QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); + QTRY_VERIFY((popup = findNewTopLevelWindow(oldTlws))); + QVERIFY(QTest::qWaitForWindowExposed(popup)); + QTRY_VERIFY(popup->width() > 0 && popup->height() > 0); QTRY_VERIFY(QGuiApplication::topLevelWindows().contains(popup)); QTRY_VERIFY(!popup->position().isNull()); QPoint popupPos = popup->position(); // Close the popup by clicking somewhere into the page. - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), QPoint(1, 1))); + makeClick(window, withTouch, view.mapTo(view.window(), QPoint(1, 1))); QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); int originalViewWidth = view.size().width(); @@ -1391,19 +1491,25 @@ void tst_QWebEnginePage::comboBoxPopupPositionAfterChildMove() return viewWidth; }; + QCOMPARE(jsViewWidth(), originalViewWidth); + // Resize the "spacer" widget, and implicitly change the global position of the QWebEngineView. const int offset = 50; spacer.setMinimumWidth(spacer.size().width() + offset); + QTRY_COMPARE(jsViewWidth(), originalViewWidth - offset); - QTest::mouseClick(window, Qt::LeftButton, Qt::KeyboardModifiers(), - view.mapTo(view.window(), elementCenter(view.page(), "foo"))); - QTRY_VERIFY(popup = findNewTopLevelWindow(oldTlws)); + makeClick(window, withTouch, view.mapTo(view.window(), elementCenter(view.page(), "foo"))); + QTRY_VERIFY((popup = findNewTopLevelWindow(oldTlws))); + QVERIFY(QTest::qWaitForWindowExposed(popup)); + QTRY_VERIFY(popup->width() > 0 && popup->height() > 0); QTRY_VERIFY(!popup->position().isNull()); - QCOMPARE(popupPos + QPoint(50, 0), popup->position()); + QCOMPARE(popupPos + QPoint(offset, 0), popup->position()); + makeClick(window, withTouch, QPoint(1, 1)); + QTRY_VERIFY(!QGuiApplication::topLevelWindows().contains(popup)); } -#ifdef Q_OS_MAC +#ifdef Q_OS_MACOS void tst_QWebEnginePage::macCopyUnicodeToClipboard() { QString unicodeText = QString::fromUtf8("αβγδεζηθικλμπ"); @@ -1797,14 +1903,14 @@ void tst_QWebEnginePage::openWindowDefaultSize() page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); view.setUrl(QUrl("about:blank")); view.show(); - QTRY_COMPARE(spyFinished.count(), 1); + QTRY_COMPARE(spyFinished.size(), 1); // Open a default window. page.runJavaScript("window.open()"); - QTRY_COMPARE(windowCreatedSpy.count(), 1); + QTRY_COMPARE(windowCreatedSpy.size(), 1); // Open a too small window. evaluateJavaScriptSync(&page, "window.open('','about:blank','width=10,height=10')"); - QTRY_COMPARE(windowCreatedSpy.count(), 2); + QTRY_COMPARE(windowCreatedSpy.size(), 2); // The number of popups created should be two. QCOMPARE(page.createdWindows.size(), 2); @@ -1875,7 +1981,7 @@ void tst_QWebEnginePage::runJavaScriptDisabled() // Settings changes take effect asynchronously. The load and wait ensure // that the settings are applied by the time we start to execute JavaScript. page.load(QStringLiteral("about:blank")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 20000); QCOMPARE(evaluateJavaScriptSyncInWorld(&page, QStringLiteral("1+1"), QWebEngineScript::MainWorld), QVariant()); QCOMPARE(evaluateJavaScriptSyncInWorld(&page, QStringLiteral("1+1"), QWebEngineScript::ApplicationWorld), @@ -1892,7 +1998,7 @@ void tst_QWebEnginePage::runJavaScriptFromSlot() page.setHtml("<html><body>" " <input type='text' id='input1' value='QtWebEngine' size='50' />" "</body></html>"); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); bool done = false; connect(&page, &QWebEnginePage::selectionChanged, [&]() { @@ -1916,7 +2022,7 @@ void tst_QWebEnginePage::fullScreenRequested() QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); page->load(QUrl("qrc:///resources/fullscreen.html")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QTRY_VERIFY(isTrueJavaScriptResult(page, "document.webkitFullscreenEnabled")); QVERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen")); @@ -1933,7 +2039,7 @@ void tst_QWebEnginePage::fullScreenRequested() QTest::mouseMove(view.windowHandle(), QPoint(10,10)); QTest::mouseClick(view.windowHandle(), Qt::RightButton); - QTRY_COMPARE(view.findChildren<QMenu *>().count(), 1); + QTRY_COMPARE(view.findChildren<QMenu *>().size(), 1); auto menu = view.findChildren<QMenu *>().first(); QVERIFY(menu->actions().contains(page->action(QWebEnginePage::ExitFullScreen))); @@ -1947,8 +2053,18 @@ void tst_QWebEnginePage::fullScreenRequested() QTRY_VERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen")); } -void tst_QWebEnginePage::quotaRequested() +void tst_QWebEnginePage::requestQuota_data() +{ + QTest::addColumn<QString>("storage"); + QTest::addRow("webkitPersistentStorage") << "navigator.webkitPersistentStorage"; + QTest::addRow("webkitTemporaryStorage") << "navigator.webkitTemporaryStorage"; + +} + +void tst_QWebEnginePage::requestQuota() { + QFETCH(QString, storage); + ConsolePage page; QWebEngineView view; view.setPage(&page); @@ -1956,35 +2072,23 @@ void tst_QWebEnginePage::quotaRequested() page.load(QUrl("qrc:///resources/content.html")); QVERIFY(loadFinishedSpy.wait()); - connect(&page, &QWebEnginePage::quotaRequested, - [] (QWebEngineQuotaRequest request) - { - if (request.requestedSize() <= 5000) - request.accept(); - else - request.reject(); - }); - - evaluateJavaScriptSync(&page, - "navigator.webkitPersistentStorage.requestQuota(1024, function(grantedSize) {" \ - "console.log(grantedSize);" \ - "});"); - QTRY_COMPARE(page.messages.count(), 1); + evaluateJavaScriptSync(&page, QString( + "var storage = %1;" + "storage.requestQuota(1024, function(grantedSize) {" + " console.log(grantedSize);" + "});").arg(storage)); + QTRY_COMPARE(page.messages.size(), 1); QTRY_COMPARE(page.messages[0], QString("1024")); - evaluateJavaScriptSync(&page, - "navigator.webkitPersistentStorage.requestQuota(6000, function(grantedSize) {" \ - "console.log(grantedSize);" \ - "});"); - QTRY_COMPARE(page.messages.count(), 2); - QTRY_COMPARE(page.messages[1], QString("1024")); - - evaluateJavaScriptSync(&page, - "navigator.webkitPersistentStorage.queryUsageAndQuota(function(usedBytes, grantedBytes) {" \ - "console.log(usedBytes + ', ' + grantedBytes);" \ - "});"); - QTRY_COMPARE(page.messages.count(), 3); - QTRY_COMPARE(page.messages[2], QString("0, 1024")); + evaluateJavaScriptSync(&page, QString( + "var storage = %1;" + "storage.queryUsageAndQuota(function(usedBytes, grantedBytes) {" + " console.log(usedBytes);" + " console.log(grantedBytes);" + "});").arg(storage)); + QTRY_COMPARE(page.messages.size(), 3); + QTRY_COMPARE(page.messages[1], QString("0")); + QTRY_VERIFY(page.messages[2].toLongLong() >= 1024); } void tst_QWebEnginePage::symmetricUrl() @@ -2006,7 +2110,7 @@ void tst_QWebEnginePage::symmetricUrl() // loading is _not_ immediate, so the text isn't set just yet. QVERIFY(toPlainTextSync(view.page()).isEmpty()); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 20000); QCOMPARE(view.history()->count(), 1); QCOMPARE(toPlainTextSync(view.page()), QString("Test")); @@ -2020,8 +2124,8 @@ void tst_QWebEnginePage::symmetricUrl() QCOMPARE(view.url(), dataUrl3); // setUrl(dataUrl3) might override the pending load for dataUrl2. Or not. - QTRY_VERIFY(loadFinishedSpy.count() >= 2); - QTRY_VERIFY(loadFinishedSpy.count() <= 3); + QTRY_VERIFY(loadFinishedSpy.size() >= 2); + QTRY_VERIFY(loadFinishedSpy.size() <= 3); // setUrl(dataUrl3) might stop Chromium from adding a navigation entry for dataUrl2, // depending on whether the load of dataUrl2 could be completed in time. @@ -2099,7 +2203,7 @@ public: setAttribute(QNetworkRequest::RedirectionTargetAttribute, QUrl("qrc:/test2.html")); QTimer::singleShot(0, this, SLOT(continueRedirect())); } -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) else if (request.url() == QUrl("qrc:/fake-ssl-error.html")) { setError(QNetworkReply::SslHandshakeFailedError, tr("Fake error!")); QTimer::singleShot(0, this, SLOT(continueError())); @@ -2156,7 +2260,7 @@ protected: { QString url = request.url().toString(); if (op == QNetworkAccessManager::GetOperation) { -#ifndef QT_NO_OPENSSL +#if QT_CONFIG(openssl) if (url == "qrc:/fake-ssl-error.html") { FakeReply* reply = new FakeReply(request, this); QList<QSslError> errors; @@ -2180,7 +2284,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() const QUrl first("http://abcdef.abcdef/"); page.setUrl(first); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 20000); QCOMPARE(page.url(), first); QCOMPARE(page.requestedUrl(), first); QVERIFY(!spy.at(0).first().toBool()); @@ -2189,7 +2293,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures() QVERIFY(first != second); page.load(second); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 2, 20000); QCOMPARE(page.url(), first); QCOMPARE(page.requestedUrl(), second); QVERIFY(!spy.at(1).first().toBool()); @@ -2235,7 +2339,7 @@ void tst_QWebEnginePage::setHtmlWithImageResource() QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.setHtml(html, QUrl("file:///path/to/file")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 12000); QCOMPARE(evaluateJavaScriptSync(&page, "document.images.length").toInt(), 1); QCOMPARE(evaluateJavaScriptSync(&page, "document.images[0].width").toInt(), 128); @@ -2244,7 +2348,7 @@ void tst_QWebEnginePage::setHtmlWithImageResource() // Now we test the opposite: without a baseUrl as a local file, we can still request qrc resources. page.setHtml(html); - QTRY_COMPARE(spy.count(), 2); + QTRY_COMPARE(spy.size(), 2); QCOMPARE(evaluateJavaScriptSync(&page, "document.images.length").toInt(), 1); QCOMPARE(evaluateJavaScriptSync(&page, "document.images[0].width").toInt(), 128); QCOMPARE(evaluateJavaScriptSync(&page, "document.images[0].height").toInt(), 128); @@ -2307,7 +2411,7 @@ void tst_QWebEnginePage::setHtmlWithBaseURL() QString("%1/foo.html").arg(QDir(QT_TESTCASE_SOURCEDIR).canonicalPath()))); QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); QVERIFY(spyFinished.wait()); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(evaluateJavaScriptSync(&page, "document.images.length").toInt(), 1); QCOMPARE(evaluateJavaScriptSync(&page, "document.images[0].width").toInt(), 128); @@ -2370,7 +2474,7 @@ void tst_QWebEnginePage::setHtmlWithModuleImport() QWebEnginePage page; QSignalSpy spy(&page, &QWebEnginePage::loadFinished); page.setHtml(html, server.url()); - QVERIFY(spy.count() || spy.wait()); + QVERIFY(spy.size() || spy.wait()); QCOMPARE(evaluateJavaScriptSync(&page, "fib7"), QVariant(13)); } @@ -2406,7 +2510,7 @@ void tst_QWebEnginePage::baseUrl() QSignalSpy loadSpy(m_page, SIGNAL(loadFinished(bool))); m_page->setHtml(html, loadUrl); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(m_page->url(), url); QEXPECT_FAIL("null", "Slight change: We now translate QUrl() to about:blank for the virtual url, but not for the baseUrl", Continue); QCOMPARE(baseUrlSync(m_page), baseUrl); @@ -2415,7 +2519,8 @@ void tst_QWebEnginePage::baseUrl() void tst_QWebEnginePage::scrollPosition() { // enlarged image in a small viewport, to provoke the scrollbars to appear - QString html("<html><body><img src='qrc:/image.png' height=500 width=500/></body></html>"); + QString html( + "<html><body><img src='qrc:/resources/image.png' height=500 width=500/></body></html>"); QWebEngineView view; view.setFixedSize(200,200); @@ -2425,12 +2530,12 @@ void tst_QWebEnginePage::scrollPosition() QSignalSpy loadSpy(view.page(), SIGNAL(loadFinished(bool))); view.setHtml(html); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); // try to set the scroll offset programmatically view.page()->runJavaScript("window.scrollTo(23, 29);"); - QTRY_COMPARE(view.page()->scrollPosition().x(), 23 * view.windowHandle()->devicePixelRatio()); - QCOMPARE(view.page()->scrollPosition().y(), 29 * view.windowHandle()->devicePixelRatio()); + QTRY_COMPARE(view.page()->scrollPosition().x(), 23); + QCOMPARE(view.page()->scrollPosition().y(), 29); int x = evaluateJavaScriptSync(view.page(), "window.scrollX").toInt(); int y = evaluateJavaScriptSync(view.page(), "window.scrollY").toInt(); @@ -2451,7 +2556,7 @@ void tst_QWebEnginePage::scrollbarsOff() QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); view.setHtml(html); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QVERIFY(evaluateJavaScriptSync(view.page(), "innerWidth == document.documentElement.offsetWidth").toBool()); } @@ -2486,7 +2591,7 @@ void tst_QWebEnginePage::evaluateWillCauseRepaint() QSignalSpy loadSpy(&view, SIGNAL(loadFinished(bool))); view.setHtml(html); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); evaluateJavaScriptSync(view.page(), "document.getElementById('junk').style.display = 'none';"); QSignalSpy repaintSpy(&view, &WebView::repaintRequested); @@ -2580,7 +2685,7 @@ void tst_QWebEnginePage::setUrlToEmpty() expectedLoadFinishedCount++; QVERIFY(spy.wait()); - QCOMPARE(spy.count(), expectedLoadFinishedCount); + QCOMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(page.url(), url); QCOMPARE(page.requestedUrl(), url); QCOMPARE(baseUrlSync(&page), url); @@ -2589,7 +2694,7 @@ void tst_QWebEnginePage::setUrlToEmpty() page.setUrl(QUrl()); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(page.url(), aboutBlank); QCOMPARE(page.requestedUrl(), QUrl()); QCOMPARE(baseUrlSync(&page), aboutBlank); @@ -2598,7 +2703,7 @@ void tst_QWebEnginePage::setUrlToEmpty() page.setUrl(url); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(page.url(), url); QCOMPARE(page.requestedUrl(), url); QCOMPARE(baseUrlSync(&page), url); @@ -2607,7 +2712,7 @@ void tst_QWebEnginePage::setUrlToEmpty() page.load(QUrl()); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(page.url(), aboutBlank); QCOMPARE(page.requestedUrl(), QUrl()); QCOMPARE(baseUrlSync(&page), aboutBlank); @@ -2662,9 +2767,9 @@ void tst_QWebEnginePage::setUrlToBadDomain() page.setUrl(url1); - QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 20000); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(urlSpy.size(), 1); + QTRY_COMPARE_WITH_TIMEOUT(titleSpy.size(), 1, 20000); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url1); QCOMPARE(titleSpy.takeFirst().value(0).toString(), url1.host()); @@ -2675,9 +2780,9 @@ void tst_QWebEnginePage::setUrlToBadDomain() page.setUrl(url2); - QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE_WITH_TIMEOUT(titleSpy.count(), 1, 20000); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(urlSpy.size(), 1); + QTRY_COMPARE_WITH_TIMEOUT(titleSpy.size(), 1, 20000); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url2); QCOMPARE(titleSpy.takeFirst().value(0).toString(), url2.host()); @@ -2701,9 +2806,9 @@ void tst_QWebEnginePage::setUrlToBadPort() page.setUrl(url1); - QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE(titleSpy.count(), 2); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(urlSpy.size(), 1); + QTRY_COMPARE(titleSpy.size(), 2); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url1); QCOMPARE(titleSpy.takeFirst().value(0).toString(), url1.authority()); @@ -2715,9 +2820,9 @@ void tst_QWebEnginePage::setUrlToBadPort() page.setUrl(url2); - QTRY_COMPARE(urlSpy.count(), 1); - QTRY_COMPARE(titleSpy.count(), 2); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(urlSpy.size(), 1); + QTRY_COMPARE(titleSpy.size(), 2); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), url2); QCOMPARE(titleSpy.takeFirst().value(0).toString(), url2.authority()); @@ -2748,7 +2853,7 @@ void tst_QWebEnginePage::setUrlHistory() m_page->setUrl(QUrl()); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), aboutBlank); QCOMPARE(m_page->requestedUrl(), QUrl()); // Chromium stores navigation entry for every successful loads. The load of the empty page is committed and stored as about:blank. @@ -2757,7 +2862,7 @@ void tst_QWebEnginePage::setUrlHistory() url = QUrl("http://url.invalid/"); m_page->setUrl(url); expectedLoadFinishedCount++; - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), expectedLoadFinishedCount, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), expectedLoadFinishedCount, 20000); // When error page is disabled in case of LoadFail the entry of the unavailable page is not stored. // We expect the url of the previously loaded page here. QCOMPARE(m_page->url(), aboutBlank); @@ -2768,14 +2873,14 @@ void tst_QWebEnginePage::setUrlHistory() url = QUrl("qrc:/resources/test1.html"); m_page->setUrl(url); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() << aboutBlank.toString() << QStringLiteral("qrc:/resources/test1.html")); m_page->setUrl(QUrl()); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), aboutBlank); QCOMPARE(m_page->requestedUrl(), QUrl()); // Chromium stores navigation entry for every successful loads. The load of the empty page is committed and stored as about:blank. @@ -2787,7 +2892,7 @@ void tst_QWebEnginePage::setUrlHistory() url = QUrl("qrc:/resources/test1.html"); m_page->setUrl(url); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); // The history count DOES change since the about:blank is in the list. @@ -2800,7 +2905,7 @@ void tst_QWebEnginePage::setUrlHistory() url = QUrl("qrc:/resources/test2.html"); m_page->setUrl(url); expectedLoadFinishedCount++; - QTRY_COMPARE(spy.count(), expectedLoadFinishedCount); + QTRY_COMPARE(spy.size(), expectedLoadFinishedCount); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); QCOMPARE(collectHistoryUrls(m_page->history()), QStringList() @@ -2815,6 +2920,7 @@ void tst_QWebEnginePage::setUrlUsingStateObject() { QUrl url; QSignalSpy urlChangedSpy(m_page, SIGNAL(urlChanged(QUrl))); + QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); int expectedUrlChangeCount = 0; QCOMPARE(m_page->history()->count(), 0); @@ -2822,20 +2928,22 @@ void tst_QWebEnginePage::setUrlUsingStateObject() url = QUrl("qrc:/resources/test1.html"); m_page->setUrl(url); expectedUrlChangeCount++; - QTRY_COMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.size(), expectedUrlChangeCount); + QCOMPARE(m_page->url(), url); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(m_page->url(), url); - QTRY_COMPARE(m_page->history()->count(), 1); + QCOMPARE(m_page->history()->count(), 1); evaluateJavaScriptSync(m_page, "window.history.pushState(null, 'push', 'navigate/to/here')"); expectedUrlChangeCount++; - QTRY_COMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.size(), expectedUrlChangeCount); QCOMPARE(m_page->url(), QUrl("qrc:/resources/navigate/to/here")); QCOMPARE(m_page->history()->count(), 2); QVERIFY(m_page->history()->canGoBack()); evaluateJavaScriptSync(m_page, "window.history.replaceState(null, 'replace', 'another/location')"); expectedUrlChangeCount++; - QTRY_COMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.size(), expectedUrlChangeCount); QCOMPARE(m_page->url(), QUrl("qrc:/resources/navigate/to/another/location")); QCOMPARE(m_page->history()->count(), 2); QVERIFY(!m_page->history()->canGoForward()); @@ -2843,7 +2951,7 @@ void tst_QWebEnginePage::setUrlUsingStateObject() evaluateJavaScriptSync(m_page, "window.history.back()"); expectedUrlChangeCount++; - QTRY_COMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.size(), expectedUrlChangeCount); QCOMPARE(m_page->url(), QUrl("qrc:/resources/test1.html")); QVERIFY(m_page->history()->canGoForward()); QVERIFY(!m_page->history()->canGoBack()); @@ -2872,9 +2980,9 @@ void tst_QWebEnginePage::setUrlThenLoads() QSignalSpy finishedSpy(m_page, SIGNAL(loadFinished(bool))); m_page->setUrl(url); - QTRY_COMPARE(startedSpy.count(), 1); - QTRY_COMPARE(urlChangedSpy.count(), 1); - QTRY_COMPARE(finishedSpy.count(), 1); + QTRY_COMPARE(startedSpy.size(), 1); + QTRY_COMPARE(urlChangedSpy.size(), 1); + QTRY_COMPARE(finishedSpy.size(), 1); QVERIFY(finishedSpy.at(0).first().toBool()); QCOMPARE(m_page->url(), url); QCOMPARE(m_page->requestedUrl(), url); @@ -2888,11 +2996,11 @@ void tst_QWebEnginePage::setUrlThenLoads() QTRY_COMPARE(m_page->requestedUrl(), urlToLoad1); // baseUrlSync spins an event loop and this sometimes return the next result. // QCOMPARE(baseUrlSync(m_page), baseUrl); - QTRY_COMPARE(startedSpy.count(), 2); + QTRY_COMPARE(startedSpy.size(), 2); // After first URL changed. - QTRY_COMPARE(urlChangedSpy.count(), 2); - QTRY_COMPARE(finishedSpy.count(), 2); + QTRY_COMPARE(urlChangedSpy.size(), 2); + QTRY_COMPARE(finishedSpy.size(), 2); QVERIFY(finishedSpy.at(1).first().toBool()); QCOMPARE(m_page->url(), urlToLoad1); QCOMPARE(m_page->requestedUrl(), urlToLoad1); @@ -2902,11 +3010,11 @@ void tst_QWebEnginePage::setUrlThenLoads() QCOMPARE(m_page->url(), urlToLoad1); QCOMPARE(m_page->requestedUrl(), urlToLoad2); QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1)); - QTRY_COMPARE(startedSpy.count(), 3); + QTRY_COMPARE(startedSpy.size(), 3); // After second URL changed. - QTRY_COMPARE(urlChangedSpy.count(), 3); - QTRY_COMPARE(finishedSpy.count(), 3); + QTRY_COMPARE(urlChangedSpy.size(), 3); + QTRY_COMPARE(finishedSpy.size(), 3); QVERIFY(finishedSpy.at(2).first().toBool()); QCOMPARE(m_page->url(), urlToLoad2); QCOMPARE(m_page->requestedUrl(), urlToLoad2); @@ -2994,7 +3102,7 @@ void tst_QWebEnginePage::loadInSignalHandlers() URLSetter setter(m_page, signal, type, urlForSetter); QSignalSpy spy(&setter, &URLSetter::finished); m_page->load(url); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); + QTRY_VERIFY_WITH_TIMEOUT(spy.size() >= 1, 20000); QCOMPARE(m_page->url(), urlForSetter); } @@ -3005,31 +3113,31 @@ void tst_QWebEnginePage::loadFromQrc() // Standard case. page.load(QStringLiteral("qrc:///resources/foo.txt")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().value(0).toBool(), true); QCOMPARE(toPlainTextSync(&page), QStringLiteral("foo\n")); // Query and fragment parts are ignored. page.load(QStringLiteral("qrc:///resources/bar.txt?foo=1#bar")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().value(0).toBool(), true); QCOMPARE(toPlainTextSync(&page), QStringLiteral("bar\n")); // Literal spaces are OK. page.load(QStringLiteral("qrc:///resources/path with spaces.txt")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().value(0).toBool(), true); QCOMPARE(toPlainTextSync(&page), QStringLiteral("contents with spaces\n")); // Escaped spaces are OK too. page.load(QStringLiteral("qrc:///resources/path%20with%20spaces.txt")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(spy.takeFirst().value(0).toBool(), true); QCOMPARE(toPlainTextSync(&page), QStringLiteral("contents with spaces\n")); // Resource not found, loading fails. page.load(QStringLiteral("qrc:///nope")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 10000); QCOMPARE(spy.takeFirst().value(0).toBool(), false); } @@ -3046,7 +3154,7 @@ void tst_QWebEnginePage::restoreHistory() QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.load(QUrl(QStringLiteral("qrc:/resources/test1.html"))); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(page.webChannel(), &channel); QVERIFY(page.scripts().contains(script)); @@ -3056,7 +3164,7 @@ void tst_QWebEnginePage::restoreHistory() out << *page.history(); QDataStream in(&data, QIODevice::ReadOnly); in >> *page.history(); - QTRY_COMPARE(spy.count(), 2); + QTRY_COMPARE(spy.size(), 2); QCOMPARE(page.webChannel(), &channel); QVERIFY(page.scripts().contains(script)); @@ -3079,42 +3187,59 @@ void tst_QWebEnginePage::toPlainTextLoadFinishedRace() QSignalSpy spy(page.data(), SIGNAL(loadFinished(bool))); page->load(QUrl("data:text/plain,foobarbaz")); - QTRY_VERIFY(spy.count() == 1); + QTRY_VERIFY(spy.size() == 1); QCOMPARE(toPlainTextSync(page.data()), QString("foobarbaz")); page->load(QUrl("http://fail.invalid/")); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 2, 20000); QString s = toPlainTextSync(page.data()); QVERIFY(s.contains("foobarbaz") == !enableErrorPage); page->load(QUrl("data:text/plain,lalala")); - QTRY_COMPARE(spy.count(), 3); + QTRY_COMPARE(spy.size(), 3); QTRY_COMPARE(toPlainTextSync(page.data()), QString("lalala")); page.reset(); - QCOMPARE(spy.count(), 3); + QCOMPARE(spy.size(), 3); } void tst_QWebEnginePage::setZoomFactor() { - QWebEnginePage page; + TestBasePage page, page2; - QVERIFY(qFuzzyCompare(page.zoomFactor(), 1.0)); + QCOMPARE(page.zoomFactor(), 1.0); page.setZoomFactor(2.5); - QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); - - const QUrl urlToLoad("qrc:/resources/test1.html"); - - QSignalSpy finishedSpy(&page, SIGNAL(loadFinished(bool))); - page.load(urlToLoad); - QTRY_COMPARE(finishedSpy.count(), 1); - QVERIFY(finishedSpy.at(0).first().toBool()); - QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); - - page.setZoomFactor(5.5); - QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); + QCOMPARE(page.zoomFactor(), 2.5); + + const QUrl url1("qrc:/resources/test1.html"), url2(QUrl("qrc:/resources/test2.html")); + + page.load(url1); + QTRY_COMPARE(page.loadSpy.size(), 1); + QVERIFY(page.loadSpy.at(0).first().toBool()); + QCOMPARE(page.zoomFactor(), 2.5); + + page.setZoomFactor(5.5); // max accepted zoom: kMaximumPageZoomFactor = 5.0 + QCOMPARE(page.zoomFactor(), 2.5); + + page.setZoomFactor(0.1); // min accepted zoom: kMinimumPageZoomFactor = 0.25 + QCOMPARE(page.zoomFactor(), 2.5); + + // try loading different url and check new values after load + page.loadSpy.clear(); + for (auto &&p : { + qMakePair(&page, 2.5), // navigating away to different url should keep zoom + qMakePair(&page2, 1.0), // same url navigation in diffent page shouldn't be affected + }) { + auto &&page = *p.first; auto zoomFactor = p.second; + page.load(url2); + QTRY_COMPARE(page.loadSpy.size(), 1); + QVERIFY(page.loadSpy.last().first().toBool()); + QCOMPARE(page.zoomFactor(), zoomFactor); + } - page.setZoomFactor(0.1); - QVERIFY(qFuzzyCompare(page.zoomFactor(), 2.5)); + // should have no influence on first page + page2.setZoomFactor(3.5); + for (auto &&p : { qMakePair(&page, 2.5), qMakePair(&page2, 3.5), }) + QCOMPARE(p.first->zoomFactor(), p.second); } void tst_QWebEnginePage::mouseButtonTranslation() @@ -3134,17 +3259,20 @@ void tst_QWebEnginePage::mouseButtonTranslation() view.resize(640, 480); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QTRY_VERIFY(spy.count() == 1); + QTRY_VERIFY(spy.size() == 1); QVERIFY(view.focusProxy() != nullptr); - QMouseEvent evpres(QEvent::MouseButtonPress, view.rect().center(), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + const QPoint mousePos = view.rect().center(); + QMouseEvent evpres(QEvent::MouseButtonPress, mousePos, view.mapToGlobal(mousePos), + Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); QGuiApplication::sendEvent(view.focusProxy(), &evpres); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.button").toInt(), 0); QCOMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.buttons").toInt(), 1); - QMouseEvent evpres2(QEvent::MouseButtonPress, view.rect().center(), Qt::RightButton, Qt::LeftButton | Qt::RightButton, Qt::NoModifier); + QMouseEvent evpres2(QEvent::MouseButtonPress, mousePos, view.mapToGlobal(mousePos), + Qt::RightButton, Qt::LeftButton | Qt::RightButton, Qt::NoModifier); QGuiApplication::sendEvent(view.focusProxy(), &evpres2); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "lastEvent.button").toInt(), 2); @@ -3173,34 +3301,17 @@ void tst_QWebEnginePage::mouseMovementProperties() loadFinishedSpy.wait(); QTest::mouseMove(&view, QPoint(20, 20)); - QTRY_COMPARE(page.messages.count(), 1); + QTRY_COMPARE(page.messages.size(), 1); QTest::mouseMove(&view, QPoint(30, 30)); - QTRY_COMPARE(page.messages.count(), 2); + QTRY_COMPARE(page.messages.size(), 2); QTRY_COMPARE(page.messages[1], QString("10, 10")); QTest::mouseMove(&view, QPoint(20, 20)); - QTRY_COMPARE(page.messages.count(), 3); + QTRY_COMPARE(page.messages.size(), 3); QTRY_COMPARE(page.messages[2], QString("-10, -10")); } -QPoint tst_QWebEnginePage::elementCenter(QWebEnginePage *page, const QString &id) -{ - QVariantList rectList = evaluateJavaScriptSync(page, - "(function(){" - "var elem = document.getElementById('" + id + "');" - "var rect = elem.getBoundingClientRect();" - "return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" - "})()").toList(); - - if (rectList.count() != 2) { - qWarning("elementCenter failed."); - return QPoint(); - } - - return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); -} - void tst_QWebEnginePage::viewSource() { TestPage page; @@ -3209,12 +3320,12 @@ void tst_QWebEnginePage::viewSource() const QUrl url("qrc:/resources/test1.html"); page.load(url); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(page.title(), QStringLiteral("Test page 1")); QVERIFY(page.action(QWebEnginePage::ViewSource)->isEnabled()); page.triggerAction(QWebEnginePage::ViewSource); - QTRY_COMPARE(windowCreatedSpy.count(), 1); + QTRY_COMPARE(windowCreatedSpy.size(), 1); QCOMPARE(page.createdWindows.size(), 1); QTRY_COMPARE(page.createdWindows[0]->url().toString(), QStringLiteral("view-source:%1").arg(url.toString())); @@ -3269,7 +3380,7 @@ void tst_QWebEnginePage::viewSourceURL() QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); page.load(userInputUrl); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 12000); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 12000); QList<QVariant> arguments = loadFinishedSpy.takeFirst(); QCOMPARE(arguments.at(0).toBool(), loadSucceed); @@ -3304,7 +3415,7 @@ void tst_QWebEnginePage::viewSourceCredentials() QVERIFY(page.action(QWebEnginePage::ViewSource)->isEnabled()); page.triggerAction(QWebEnginePage::ViewSource); - QTRY_COMPARE(windowCreatedSpy.count(), 1); + QTRY_COMPARE(windowCreatedSpy.size(), 1); QCOMPARE(page.createdWindows.size(), 1); QTRY_COMPARE(page.createdWindows[0]->url().toString(), QString("view-source:" + url.toDisplayString(QUrl::RemoveUserInfo))); @@ -3326,7 +3437,7 @@ void tst_QWebEnginePage::proxyConfigWithUnexpectedHostPortPair() QSignalSpy loadFinishedSpy(m_page, SIGNAL(loadFinished(bool))); m_page->load(QStringLiteral("http://127.0.0.1:245/")); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); } void tst_QWebEnginePage::registerProtocolHandler_data() @@ -3359,7 +3470,7 @@ void tst_QWebEnginePage::registerProtocolHandler() QSignalSpy permissionSpy(&page, &QWebEnginePage::registerProtocolHandlerRequested); page.setUrl(server.url("/")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0).toBool(), true); QString callFormat = QStringLiteral("window.navigator.registerProtocolHandler(\"%1\", \"%2\", \"%3\")"); @@ -3369,7 +3480,7 @@ void tst_QWebEnginePage::registerProtocolHandler() QString call = callFormat.arg(scheme).arg(url).arg(title); page.runJavaScript(call); - QTRY_COMPARE(permissionSpy.count(), 1); + QTRY_COMPARE(permissionSpy.size(), 1); auto request = permissionSpy.takeFirst().value(0).value<QWebEngineRegisterProtocolHandlerRequest>(); QCOMPARE(request.origin(), QUrl(url)); QCOMPARE(request.scheme(), scheme); @@ -3380,7 +3491,7 @@ void tst_QWebEnginePage::registerProtocolHandler() page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0).toBool(), permission); QCOMPARE(mailRequestCount, permission ? 1 : 0); QVERIFY(server.stop()); @@ -3396,7 +3507,7 @@ void tst_QWebEnginePage::dataURLFragment() m_page->setHtml("<html><body>" "<a id='link' href='#anchor'>anchor</a>" "</body></html>", QUrl("http://test.qt.io/mytest.html")); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link")); QVERIFY(urlChangedSpy.wait()); @@ -3420,7 +3531,7 @@ void tst_QWebEnginePage::devTools() QCOMPARE(devToolsPage.devToolsPage(), nullptr); QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage1); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 90000); QVERIFY(spy.takeFirst().value(0).toBool()); devToolsPage.setInspectedPage(&inspectedPage2); @@ -3432,7 +3543,7 @@ void tst_QWebEnginePage::devTools() QCOMPARE(devToolsPage.devToolsPage(), nullptr); QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage2); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 90000); QVERIFY(spy.takeFirst().value(0).toBool()); devToolsPage.setInspectedPage(nullptr); @@ -3443,6 +3554,8 @@ void tst_QWebEnginePage::devTools() QCOMPARE(inspectedPage2.inspectedPage(), nullptr); QCOMPARE(devToolsPage.devToolsPage(), nullptr); QCOMPARE(devToolsPage.inspectedPage(), nullptr); + + QVERIFY(!inspectedPage1.devToolsId().isEmpty()); } void tst_QWebEnginePage::openLinkInDifferentProfile() @@ -3464,11 +3577,11 @@ void tst_QWebEnginePage::openLinkInDifferentProfile() page1.setHtml("<html><body>" "<a id='link' href='hello'>link</a>" "</body></html>", QUrl("echo:/")); - QTRY_COMPARE(spy1.count(), 1); + QTRY_COMPARE(spy1.size(), 1); QVERIFY(spy1.takeFirst().value(0).toBool()); targetPage = &page2; QTest::mouseClick(view.focusProxy(), Qt::MiddleButton, {}, elementCenter(&page1, "link")); - QTRY_COMPARE(spy2.count(), 1); + QTRY_COMPARE(spy2.size(), 1); QVERIFY(spy2.takeFirst().value(0).toBool()); } @@ -3578,7 +3691,7 @@ void tst_QWebEnginePage::openLinkInNewPage() page1.setHtml("<html><body>" "<a id='link' href='hello' target='_blank'>link</a>" "</body></html>", QUrl("echo:/")); - QTRY_COMPARE(page1.spy.count(), 1); + QTRY_COMPARE(page1.spy.size(), 1); QVERIFY(page1.spy.takeFirst().value(0).toBool()); switch (decision) { @@ -3593,7 +3706,7 @@ void tst_QWebEnginePage::openLinkInNewPage() break; } - Qt::MouseButton button; + Qt::MouseButton button = Qt::NoButton; switch (cause) { case Cause::TargetBlank: button = Qt::LeftButton; @@ -3608,13 +3721,13 @@ void tst_QWebEnginePage::openLinkInNewPage() case Effect::Blocked: // Test nothing new loaded QTest::qWait(500); - QCOMPARE(page1.spy.count(), 0); - QCOMPARE(page2.spy.count(), 0); + QCOMPARE(page1.spy.size(), 0); + QCOMPARE(page2.spy.size(), 0); break; case Effect::LoadInSelf: - QTRY_COMPARE(page1.spy.count(), 1); + QTRY_COMPARE(page1.spy.size(), 1); QVERIFY(page1.spy.takeFirst().value(0).toBool()); - QCOMPARE(page2.spy.count(), 0); + QCOMPARE(page2.spy.size(), 0); if (decision == Decision::ReturnSelf && cause == Cause::TargetBlank) // History was discarded due to AddNewContents QCOMPARE(page1.history()->count(), 1); @@ -3623,9 +3736,9 @@ void tst_QWebEnginePage::openLinkInNewPage() QCOMPARE(page2.history()->count(), 0); break; case Effect::LoadInOther: - QTRY_COMPARE(page2.spy.count(), 1); + QTRY_COMPARE(page2.spy.size(), 1); QVERIFY(page2.spy.takeFirst().value(0).toBool()); - QCOMPARE(page1.spy.count(), 0); + QCOMPARE(page1.spy.size(), 0); QCOMPARE(page1.history()->count(), 1); QCOMPARE(page2.history()->count(), 1); break; @@ -3647,7 +3760,7 @@ void tst_QWebEnginePage::dynamicFrame() page.settings()->setAttribute(QWebEngineSettings::ErrorPageEnabled, false); QSignalSpy spy(&page, &QWebEnginePage::loadFinished); page.load(QStringLiteral("qrc:/resources/dynamicFrame.html")); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(toPlainTextSync(&page).trimmed(), QStringLiteral("foo")); } @@ -3723,7 +3836,7 @@ void tst_QWebEnginePage::notificationPermission() QSignalSpy spy(&page, &QWebEnginePage::loadFinished); page.setHtml(QString("<html><body>Test</body></html>"), baseUrl); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE(spy.size(), 1); QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("Notification.permission")), setOnInit ? permission : QLatin1String("default")); @@ -3781,6 +3894,149 @@ void tst_QWebEnginePage::sendNotification() QTRY_VERIFY2(page.messages.contains("onclose"), page.messages.join("\n").toLatin1().constData()); } +static QString clipboardPermissionQuery(QString variableName, QString permissionName) +{ + return QString("var %1; navigator.permissions.query({ name:'%2' }).then((p) => { %1 = p.state; " + "});") + .arg(variableName) + .arg(permissionName); +} + + +void tst_QWebEnginePage::clipboardReadWritePermissionInitialState_data() +{ + QTest::addColumn<bool>("canAccessClipboard"); + QTest::addColumn<bool>("canPaste"); + QTest::addColumn<QString>("permission"); + QTest::newRow("access and paste should grant") << true << true << "granted"; + QTest::newRow("no access should prompt") << false << true << "prompt"; + QTest::newRow("no paste should prompt") << true << false << "prompt"; + QTest::newRow("no access or paste should prompt") << false << false << "prompt"; +} + +void tst_QWebEnginePage::clipboardReadWritePermissionInitialState() +{ + QFETCH(bool, canAccessClipboard); + QFETCH(bool, canPaste); + QFETCH(QString, permission); + + QWebEngineProfile otr; + QWebEngineView view(&otr); + QWebEnginePage &page = *view.page(); + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, + canAccessClipboard); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste, canPaste); + + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + QUrl baseUrl("https://www.example.com/somepage.html"); + page.setHtml(QString("<html><body>Test</body></html>"), baseUrl); + QTRY_COMPARE(spy.size(), 1); + + evaluateJavaScriptSync(&page, clipboardPermissionQuery("readPermission", "clipboard-read")); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("readPermission")), permission); + evaluateJavaScriptSync(&page, clipboardPermissionQuery("writePermission", "clipboard-write")); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("writePermission")), permission); +} + +void tst_QWebEnginePage::clipboardReadWritePermission_data() +{ + QTest::addColumn<bool>("canAccessClipboard"); + QTest::addColumn<QWebEnginePage::PermissionPolicy>("initialPolicy"); + QTest::addColumn<QString>("initialPermission"); + QTest::addColumn<QWebEnginePage::PermissionPolicy>("requestPolicy"); + QTest::addColumn<QString>("finalPermission"); + + QTest::newRow("noAccessGrantGrant") + << false << QWebEnginePage::PermissionGrantedByUser << "granted" + << QWebEnginePage::PermissionGrantedByUser << "granted"; + QTest::newRow("noAccessGrantDeny") + << false << QWebEnginePage::PermissionGrantedByUser << "granted" + << QWebEnginePage::PermissionDeniedByUser << "denied"; + QTest::newRow("noAccessDenyGrant") + << false << QWebEnginePage::PermissionDeniedByUser << "denied" + << QWebEnginePage::PermissionGrantedByUser << "granted"; + QTest::newRow("noAccessDenyDeny") << false << QWebEnginePage::PermissionDeniedByUser << "denied" + << QWebEnginePage::PermissionDeniedByUser << "denied"; + QTest::newRow("noAccessAskGrant") << false << QWebEnginePage::PermissionUnknown << "prompt" + << QWebEnginePage::PermissionGrantedByUser << "granted"; + + // All policies are ignored and overridden by setting JsCanAccessClipboard and JsCanPaste to + // true + QTest::newRow("accessGrantGrant") + << true << QWebEnginePage::PermissionGrantedByUser << "granted" + << QWebEnginePage::PermissionGrantedByUser << "granted"; + QTest::newRow("accessDenyDeny") << true << QWebEnginePage::PermissionDeniedByUser << "granted" + << QWebEnginePage::PermissionDeniedByUser << "granted"; + QTest::newRow("accessAskAsk") << true << QWebEnginePage::PermissionUnknown << "granted" + << QWebEnginePage::PermissionUnknown << "granted"; +} + +void tst_QWebEnginePage::clipboardReadWritePermission() +{ + QFETCH(bool, canAccessClipboard); + QFETCH(QWebEnginePage::PermissionPolicy, initialPolicy); + QFETCH(QString, initialPermission); + QFETCH(QWebEnginePage::PermissionPolicy, requestPolicy); + QFETCH(QString, finalPermission); + + QWebEngineProfile otr; + QWebEngineView view(&otr); + QWebEnginePage &page = *view.page(); + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanAccessClipboard, + canAccessClipboard); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanPaste, true); + + QUrl baseUrl("https://www.example.com/somepage.html"); + + int permissionRequestCount = 0; + bool errorState = false; + + // if JavascriptCanAccessClipboard is true, this never fires + connect(&page, &QWebEnginePage::featurePermissionRequested, &page, + [&](const QUrl &o, QWebEnginePage::Feature f) { + if (f != QWebEnginePage::ClipboardReadWrite) + return; + if (o != baseUrl.url(QUrl::RemoveFilename)) { + qWarning() << "Unexpected case. Can't proceed." << o; + errorState = true; + return; + } + permissionRequestCount++; + page.setFeaturePermission(o, f, requestPolicy); + }); + + page.setFeaturePermission(baseUrl, QWebEnginePage::ClipboardReadWrite, initialPolicy); + + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + page.setHtml(QString("<html><body>Test</body></html>"), baseUrl); + QTRY_COMPARE(spy.size(), 1); + + evaluateJavaScriptSync(&page, clipboardPermissionQuery("readPermission", "clipboard-read")); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("readPermission")), initialPermission); + evaluateJavaScriptSync(&page, clipboardPermissionQuery("writePermission", "clipboard-write")); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("writePermission")), initialPermission); + + auto triggerRequest = [&page](QString variableName, QString apiCall) + { + auto js = QString("var %1; navigator.clipboard.%2.then((v) => { %1 = 'granted' }, (v) => { %1 = " + "'denied' });") + .arg(variableName) + .arg(apiCall); + evaluateJavaScriptSync(&page, js); + }; + + // permission is not 'remembered' from api standpoint, hence is not suppressed on explicit call + // from JS + triggerRequest("readState", "readText()"); + QTRY_COMPARE(evaluateJavaScriptSync(&page, "readState"), finalPermission); + triggerRequest("writeState", "writeText('foo')"); + QTRY_COMPARE(evaluateJavaScriptSync(&page, "writeState"), finalPermission); + QCOMPARE(permissionRequestCount, canAccessClipboard ? 0 : 2); + QVERIFY(!errorState); +} + void tst_QWebEnginePage::contentsSize() { m_view->resize(800, 600); @@ -3791,8 +4047,8 @@ void tst_QWebEnginePage::contentsSize() m_view->setHtml(QString("<html><body style=\"width: 1600px; height: 1200px;\"><p>hi</p></body></html>")); - QTRY_COMPARE(loadSpy.count(), 1); - QTRY_COMPARE(contentsSizeChangedSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); + QTRY_COMPARE(contentsSizeChangedSpy.size(), 1); // Verify the page's contents size is not limited by the view's size. QCOMPARE(m_page->contentsSize().width(), 1608); @@ -3809,6 +4065,60 @@ void tst_QWebEnginePage::contentsSize() QCOMPARE(m_page->contentsSize().height(), 1216); } +void tst_QWebEnginePage::localFontAccessPermission_data() +{ + QTest::addColumn<QWebEnginePage::PermissionPolicy>("policy"); + QTest::addColumn<bool>("ignore"); + QTest::addColumn<bool>("shouldBeEmpty"); + + QTest::newRow("ignore") << QWebEnginePage::PermissionDeniedByUser << true << true; + QTest::newRow("setDeny") << QWebEnginePage::PermissionDeniedByUser << false << true; + QTest::newRow("setGrant") << QWebEnginePage::PermissionGrantedByUser << false << false; +} + +void tst_QWebEnginePage::localFontAccessPermission() { + QFETCH(QWebEnginePage::PermissionPolicy, policy); + QFETCH(bool, ignore); + QFETCH(bool, shouldBeEmpty); + + QWebEngineView view; + QWebEnginePage page(&view); + view.setPage(&page); + + connect(&page, &QWebEnginePage::featurePermissionRequested, &page, [&] (const QUrl &o, QWebEnginePage::Feature f) { + if (f != QWebEnginePage::LocalFontsAccess) + return; + + if (!ignore) + page.setFeaturePermission(o, f, policy); + }); + + QSignalSpy spy(&page, &QWebEnginePage::loadFinished); + page.load(QUrl("qrc:///resources/fontaccess.html")); + QTRY_COMPARE(spy.size(), 1); + + // Font access is only enabled for visible WebContents. + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + if (evaluateJavaScriptSync(&page, QStringLiteral("!window.queryLocalFonts")).toBool()) + W_QSKIP("Local fonts access is not supported.", SkipSingle); + + // Access to the API requires recent user interaction + QTest::keyPress(view.focusProxy(), Qt::Key_Space); + QTRY_COMPARE(evaluateJavaScriptSync(&page, QStringLiteral("activated")).toBool(), true); + + if (ignore) { + QTRY_COMPARE_NE_WITH_TIMEOUT(evaluateJavaScriptSync(&page, QStringLiteral("done")).toBool(), true, 1000); + } else { + QTRY_VERIFY_WITH_TIMEOUT(evaluateJavaScriptSync(&page, QStringLiteral("done")).toBool() == true, 1000); + QVERIFY((evaluateJavaScriptSync(&page, QStringLiteral("fonts.length")).toInt() == 0) == shouldBeEmpty); + } + + // Reset permission, since otherwise it will be stored between runs + page.setFeaturePermission(QUrl("qrc:///resources/fontaccess.html"), QWebEnginePage::LocalFontsAccess, QWebEnginePage::PermissionUnknown); +} + void tst_QWebEnginePage::setLifecycleState() { qRegisterMetaType<QWebEnginePage::LifecycleState>("LifecycleState"); @@ -3820,64 +4130,64 @@ void tst_QWebEnginePage::setLifecycleState() QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged); page.load(QStringLiteral("qrc:/resources/lifecycle.html")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 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); + QCOMPARE(loadSpy.size(), 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(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Discarded); // Discarded -> Active page.setLifecycleState(QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 0); QCOMPARE(page.isVisible(), false); QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(true)); QCOMPARE(evaluateJavaScriptSync(&page, "frozenness"), QVariant(0)); @@ -3886,21 +4196,21 @@ void tst_QWebEnginePage::setLifecycleState() page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); page.setLifecycleState(QWebEnginePage::LifecycleState::Active); - QCOMPARE(lifecycleSpy.count(), 3); + QCOMPARE(lifecycleSpy.size(), 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(visibleSpy.size(), 0); QCOMPARE(page.isVisible(), false); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 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); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); QCOMPARE(evaluateJavaScriptSync(&page, "document.wasDiscarded"), QVariant(false)); } @@ -3916,18 +4226,18 @@ void tst_QWebEnginePage::setVisible() QSignalSpy visibleSpy(&page, &QWebEnginePage::visibleChanged); page.load(QStringLiteral("about:blank")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 0); + QCOMPARE(visibleSpy.size(), 0); QCOMPARE(page.isVisible(), false); // hidden -> visible page.setVisible(true); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.size(), 1); QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); QCOMPARE(page.isVisible(), true); @@ -3936,28 +4246,28 @@ void tst_QWebEnginePage::setVisible() QtWarningMsg, "setLifecycleState: failed to transition from Active to Frozen state: page is visible"); page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); // visible -> hidden page.setVisible(false); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.size(), 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.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.size(), 1); QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); QCOMPARE(page.isVisible(), true); @@ -3966,31 +4276,31 @@ void tst_QWebEnginePage::setVisible() "setLifecycleState: failed to transition from Active to Discarded state: " "page is visible"); page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); // visible -> hidden page.setVisible(false); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.size(), 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.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QCOMPARE(visibleSpy.count(), 1); + QCOMPARE(visibleSpy.size(), 1); QCOMPARE(visibleSpy.takeFirst().value(0), QVariant(true)); QCOMPARE(page.isVisible(), true); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); } @@ -4001,7 +4311,7 @@ void tst_QWebEnginePage::discardPreservesProperties() QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); page.load(QStringLiteral("about:blank")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); // Change as many properties as possible to non-default values @@ -4038,7 +4348,7 @@ void tst_QWebEnginePage::discardPreservesProperties() // Discard + undiscard page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); page.setLifecycleState(QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); // Property changes should be preserved @@ -4077,7 +4387,7 @@ void tst_QWebEnginePage::automaticUndiscard() QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); page.load(QStringLiteral("about:blank")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); // setUrl @@ -4102,16 +4412,16 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools() // Ensure pages are initialized inspectedPage.load(QStringLiteral("about:blank")); devToolsPage.load(QStringLiteral("about:blank")); - QTRY_COMPARE_WITH_TIMEOUT(inspectedSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(inspectedSpy.size(), 1, 90000); QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true)); - QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000); 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_WITH_TIMEOUT(devToolsSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000); QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); inspectedPage.setDevToolsPage(nullptr); @@ -4119,9 +4429,9 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools() inspectedPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); inspectedPage.setDevToolsPage(&devToolsPage); QCOMPARE(inspectedPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000); QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); - QTRY_COMPARE(inspectedSpy.count(), 1); + QTRY_COMPARE(inspectedSpy.size(), 1); QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true)); inspectedPage.setDevToolsPage(nullptr); @@ -4129,7 +4439,7 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools() devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); devToolsPage.setInspectedPage(&inspectedPage); QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000); QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); devToolsPage.setInspectedPage(nullptr); @@ -4137,7 +4447,7 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools() devToolsPage.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); devToolsPage.setInspectedPage(&inspectedPage); QCOMPARE(devToolsPage.lifecycleState(), QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 90000); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.size(), 1, 90000); QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); // keep DevTools open @@ -4175,35 +4485,35 @@ void tst_QWebEnginePage::discardPreservesCommittedLoad() QString url = QStringLiteral("qrc:/resources/lifecycle.html"); page.setUrl(url); - QTRY_COMPARE(loadStartedSpy.count(), 1); + QTRY_COMPARE(loadStartedSpy.size(), 1); loadStartedSpy.clear(); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(urlChangedSpy.count(), 1); + QCOMPARE(urlChangedSpy.size(), 1); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url))); QCOMPARE(page.url(), url); - QCOMPARE(titleChangedSpy.count(), 2); + QCOMPARE(titleChangedSpy.size(), 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(loadStartedSpy.size(), 0); + QCOMPARE(loadFinishedSpy.size(), 0); + QCOMPARE(urlChangedSpy.size(), 0); QCOMPARE(page.url(), QUrl(url)); - QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(titleChangedSpy.size(), 0); QCOMPARE(page.title(), title); page.setLifecycleState(QWebEnginePage::LifecycleState::Active); - QTRY_COMPARE(loadStartedSpy.count(), 1); + QTRY_COMPARE(loadStartedSpy.size(), 1); loadStartedSpy.clear(); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(urlChangedSpy.count(), 0); + QCOMPARE(urlChangedSpy.size(), 0); QCOMPARE(page.url(), url); - QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(titleChangedSpy.size(), 0); QCOMPARE(page.title(), title); } @@ -4220,21 +4530,21 @@ void tst_QWebEnginePage::discardAbortsPendingLoad() [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); }); QUrl url = QStringLiteral("qrc:/resources/lifecycle.html"); page.setUrl(url); - QTRY_COMPARE(loadStartedSpy.count(), 1); + QTRY_COMPARE(loadStartedSpy.size(), 1); loadStartedSpy.clear(); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false)); - QCOMPARE(urlChangedSpy.count(), 2); + QCOMPARE(urlChangedSpy.size(), 2); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(url)); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl())); - QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(titleChangedSpy.size(), 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(loadStartedSpy.size(), 0); + QCOMPARE(loadFinishedSpy.size(), 0); + QCOMPARE(urlChangedSpy.size(), 0); QCOMPARE(page.url(), QUrl()); QCOMPARE(page.title(), QString()); } @@ -4250,14 +4560,14 @@ void tst_QWebEnginePage::discardAbortsPendingLoadAndPreservesCommittedLoad() QString url1 = QStringLiteral("qrc:/resources/lifecycle.html"); page.setUrl(url1); - QTRY_COMPARE(loadStartedSpy.count(), 1); + QTRY_COMPARE(loadStartedSpy.size(), 1); loadStartedSpy.clear(); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(urlChangedSpy.count(), 1); + QCOMPARE(urlChangedSpy.size(), 1); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1))); QCOMPARE(page.url(), url1); - QCOMPARE(titleChangedSpy.count(), 2); + QCOMPARE(titleChangedSpy.size(), 2); QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(url1)); QString title = QStringLiteral("Lifecycle"); QCOMPARE(titleChangedSpy.takeFirst().value(0), QVariant(title)); @@ -4267,21 +4577,21 @@ void tst_QWebEnginePage::discardAbortsPendingLoadAndPreservesCommittedLoad() [&]() { page.setLifecycleState(QWebEnginePage::LifecycleState::Discarded); }); QString url2 = QStringLiteral("about:blank"); page.setUrl(url2); - QTRY_COMPARE(loadStartedSpy.count(), 1); + QTRY_COMPARE(loadStartedSpy.size(), 1); loadStartedSpy.clear(); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QCOMPARE(loadFinishedSpy.takeFirst().value(0), QVariant(false)); - QCOMPARE(urlChangedSpy.count(), 2); + QCOMPARE(urlChangedSpy.size(), 2); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url2))); QCOMPARE(urlChangedSpy.takeFirst().value(0), QVariant(QUrl(url1))); - QCOMPARE(titleChangedSpy.count(), 0); + QCOMPARE(titleChangedSpy.size(), 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(loadStartedSpy.size(), 0); + QCOMPARE(loadFinishedSpy.size(), 0); + QCOMPARE(urlChangedSpy.size(), 0); QCOMPARE(page.url(), url1); QCOMPARE(page.title(), title); } @@ -4377,32 +4687,32 @@ void tst_QWebEnginePage::recommendedStateAuto() connect(&page, &QWebEnginePage::recommendedStateChanged, &page, &QWebEnginePage::setLifecycleState); page.load(QStringLiteral("qrc:/resources/lifecycle.html")); - QTRY_COMPARE(lifecycleSpy.count(), 2); + QTRY_COMPARE(lifecycleSpy.size(), 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); + QTRY_COMPARE(lifecycleSpy.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); page.setVisible(false); - QTRY_COMPARE(lifecycleSpy.count(), 2); + QTRY_COMPARE(lifecycleSpy.size(), 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); + QTRY_COMPARE(lifecycleSpy.size(), 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); + QTRY_COMPARE(lifecycleSpy.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); page.setDevToolsPage(nullptr); - QTRY_COMPARE(lifecycleSpy.count(), 2); + QTRY_COMPARE(lifecycleSpy.size(), 2); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Frozen)); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Discarded)); } @@ -4417,33 +4727,33 @@ void tst_QWebEnginePage::setLifecycleStateAndReload() QSignalSpy lifecycleSpy(&page, &QWebEnginePage::lifecycleStateChanged); page.load(QStringLiteral("qrc:/resources/lifecycle.html")); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); - QCOMPARE(lifecycleSpy.count(), 0); + QCOMPARE(lifecycleSpy.size(), 0); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Active); page.setLifecycleState(QWebEnginePage::LifecycleState::Frozen); QCOMPARE(page.lifecycleState(), QWebEnginePage::LifecycleState::Frozen); - QCOMPARE(lifecycleSpy.count(), 1); + QCOMPARE(lifecycleSpy.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 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.size(), 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.size(), 1); QCOMPARE(lifecycleSpy.takeFirst().value(0), QVariant::fromValue(QWebEnginePage::LifecycleState::Active)); - QTRY_COMPARE(loadSpy.count(), 1); + QTRY_COMPARE(loadSpy.size(), 1); QCOMPARE(loadSpy.takeFirst().value(0), QVariant(true)); } @@ -4462,20 +4772,20 @@ void tst_QWebEnginePage::editActionsWithExplicitFocus() QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled()); page->setHtml(QString("<html><body><div>foo bar</div></body></html>")); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); // Still no focus because focus on navigation is disabled. Edit actions don't do anything (should not crash). QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled()); view.page()->triggerAction(QWebEnginePage::SelectAll); - QCOMPARE(selectionChangedSpy.count(), 0); + QCOMPARE(selectionChangedSpy.size(), 0); QCOMPARE(page->hasSelection(), false); // Focus content by focusing window from JavaScript. Edit actions should be enabled and functional. evaluateJavaScriptSync(page, "window.focus();"); - QTRY_COMPARE(actionChangedSpy.count(), 1); + QTRY_COMPARE(actionChangedSpy.size(), 1); QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled()); view.page()->triggerAction(QWebEnginePage::SelectAll); - QTRY_COMPARE(selectionChangedSpy.count(), 1); + QTRY_COMPARE(selectionChangedSpy.size(), 1); QCOMPARE(page->hasSelection(), true); QCOMPARE(page->selectedText(), QStringLiteral("foo bar")); } @@ -4495,13 +4805,13 @@ void tst_QWebEnginePage::editActionsWithInitialFocus() QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled()); page->setHtml(QString("<html><body><div>foo bar</div></body></html>")); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); // Content gets initial focus. - QTRY_COMPARE(actionChangedSpy.count(), 1); + QTRY_COMPARE(actionChangedSpy.size(), 1); QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled()); view.page()->triggerAction(QWebEnginePage::SelectAll); - QTRY_COMPARE(selectionChangedSpy.count(), 1); + QTRY_COMPARE(selectionChangedSpy.size(), 1); QCOMPARE(page->hasSelection(), true); QCOMPARE(page->selectedText(), QStringLiteral("foo bar")); } @@ -4521,15 +4831,15 @@ void tst_QWebEnginePage::editActionsWithFocusOnIframe() QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled()); page->load(QUrl("qrc:///resources/iframe2.html")); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE(loadFinishedSpy.size(), 1); QVERIFY(!page->action(QWebEnginePage::SelectAll)->isEnabled()); // Focusing an iframe. evaluateJavaScriptSync(page, "document.getElementsByTagName('iframe')[0].contentWindow.focus()"); - QTRY_COMPARE(actionChangedSpy.count(), 1); + QTRY_COMPARE(actionChangedSpy.size(), 1); QVERIFY(page->action(QWebEnginePage::SelectAll)->isEnabled()); view.page()->triggerAction(QWebEnginePage::SelectAll); - QTRY_COMPARE(selectionChangedSpy.count(), 1); + QTRY_COMPARE(selectionChangedSpy.size(), 1); QCOMPARE(page->hasSelection(), true); QCOMPARE(page->selectedText(), QStringLiteral("inner")); } @@ -4545,8 +4855,8 @@ void tst_QWebEnginePage::editActionsWithoutSelection() 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); + QTRY_COMPARE(loadFinishedSpy.size(), 1); + QTRY_COMPARE(actionChangedSpy.size(), 1); QVERIFY(!page->action(QWebEnginePage::Cut)->isEnabled()); QVERIFY(!page->action(QWebEnginePage::Copy)->isEnabled()); @@ -4558,7 +4868,7 @@ void tst_QWebEnginePage::editActionsWithoutSelection() QVERIFY(!page->action(QWebEnginePage::Unselect)->isEnabled()); page->triggerAction(QWebEnginePage::SelectAll); - QTRY_COMPARE(selectionChangedSpy.count(), 1); + QTRY_COMPARE(selectionChangedSpy.size(), 1); QCOMPARE(page->hasSelection(), true); QCOMPARE(page->selectedText(), QStringLiteral("foo bar")); @@ -4572,6 +4882,28 @@ void tst_QWebEnginePage::editActionsWithoutSelection() QVERIFY(page->action(QWebEnginePage::Unselect)->isEnabled()); } +struct PageWithNewWindowHandler : QWebEnginePage +{ + QScopedPointer<PageWithNewWindowHandler> newPage; + bool handleInSignal; + QWebEngineProfile *targetProfile = nullptr; + QSignalSpy loadSpy { this, &QWebEnginePage::loadFinished }; + PageWithNewWindowHandler(QWebEngineProfile *p, bool inSignal = false, QWebEngineProfile *tp = nullptr) + : QWebEnginePage(p), handleInSignal(inSignal), targetProfile(tp) { + if (handleInSignal) + connect(this, &QWebEnginePage::newWindowRequested, this, [this] (QWebEngineNewWindowRequest &r) { + newPage.reset(new PageWithNewWindowHandler(targetProfile ? targetProfile : profile(), handleInSignal)); + newPage->acceptAsNewWindow(r); + }); + } + QWebEnginePage *createWindow(WebWindowType) override { + if (handleInSignal) + return nullptr; + newPage.reset(new PageWithNewWindowHandler(targetProfile ? targetProfile : profile(), handleInSignal)); + return newPage.get(); + } +}; + void tst_QWebEnginePage::customUserAgentInNewTab() { HttpServer server; @@ -4584,55 +4916,84 @@ void tst_QWebEnginePage::customUserAgentInNewTab() }); QVERIFY(server.start()); - class Page : public QWebEnginePage { - public: - QWebEngineProfile *targetProfile = nullptr; - QScopedPointer<QWebEnginePage> newPage; - Page(QWebEngineProfile *profile) : QWebEnginePage(profile) {} - private: - QWebEnginePage *createWindow(WebWindowType) override - { - newPage.reset(new QWebEnginePage(targetProfile ? targetProfile : profile(), nullptr)); - return newPage.data(); - } - }; - QWebEngineProfile profile1, profile2; - profile1.setHttpUserAgent(QStringLiteral("custom 1")); - profile2.setHttpUserAgent(QStringLiteral("custom 2")); - Page page(&profile1); - QWebEngineView view; - view.resize(500, 500); - view.setPage(&page); - view.show(); + QString expectedUserAgent("custom 1"); + QWebEngineProfile profile; + profile.setHttpUserAgent(expectedUserAgent); + + PageWithNewWindowHandler page(&profile); + QWebEngineView view; view.resize(500, 500); view.setPage(&page); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - QSignalSpy spy(&page, &QWebEnginePage::loadFinished); // First check we can get the user-agent passed through normally page.setHtml(QString("<html><body><a id='link' target='_blank' href='") + server.url("/test1").toEncoded() + QString("'>link</a></body></html>")); - QTRY_COMPARE(spy.count(), 1); - QVERIFY(spy.takeFirst().value(0).toBool()); - QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), profile1.httpUserAgent()); + QTRY_COMPARE(page.loadSpy.size(), 1); + QVERIFY(page.loadSpy.takeFirst().value(0).toBool()); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), expectedUserAgent); QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); QTRY_VERIFY(page.newPage); + QTRY_COMPARE(page.newPage->loadSpy.size(), 1); QTRY_VERIFY(!lastUserAgent.isEmpty()); - QCOMPARE(lastUserAgent, profile1.httpUserAgent().toUtf8()); + QCOMPARE(lastUserAgent, expectedUserAgent); + QCOMPARE(evaluateJavaScriptSync(page.newPage.get(), QStringLiteral("navigator.userAgent")).toString(), expectedUserAgent); // Now check we can get the new user-agent of the profile page.newPage.reset(); - page.targetProfile = &profile2; - spy.clear(); + expectedUserAgent = "custom 2"; + profile.setHttpUserAgent(expectedUserAgent); + page.loadSpy.clear(); lastUserAgent = { }; page.setHtml(QString("<html><body><a id='link' target='_blank' href='") + server.url("/test2").toEncoded() + QString("'>link</a></body></html>")); - QTRY_COMPARE(spy.count(), 1); - QVERIFY(spy.takeFirst().value(0).toBool()); + QTRY_COMPARE(page.loadSpy.size(), 1); + QVERIFY(page.loadSpy.takeFirst().value(0).toBool()); QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); QTRY_VERIFY(page.newPage); + QTRY_COMPARE(page.newPage->loadSpy.size(), 1); QTRY_VERIFY(!lastUserAgent.isEmpty()); - QCOMPARE(lastUserAgent, profile2.httpUserAgent().toUtf8()); + QCOMPARE(lastUserAgent, expectedUserAgent); + QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), expectedUserAgent); + QCOMPARE(evaluateJavaScriptSync(page.newPage.get(), QStringLiteral("navigator.userAgent")).toString(), expectedUserAgent); +} + +void tst_QWebEnginePage::openNewTabInDifferentProfile_data() +{ + QTest::addColumn<bool>("handleInSignal"); + QTest::addRow("handleInSignal") << true; + QTest::addRow("handleInOverride") << false; +} + +void tst_QWebEnginePage::openNewTabInDifferentProfile() +{ + QFETCH(bool, handleInSignal); + + HttpServer server; + QStringList receivedRequests; + connect(&server, &HttpServer::newRequest, [&] (HttpReqRep *r) { + receivedRequests.append(r->requestPath()); + r->setResponseBody("DUMMY"); + r->sendResponse(); + }); + QVERIFY(server.start()); + + QWebEngineProfile profile1, profile2; + PageWithNewWindowHandler page(&profile1, handleInSignal, &profile2); + QWebEngineView view; view.setPage(&page); view.resize(320, 240); view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + page.setHtml(QString("<html><body><a id='link' target='_blank' href='%1'>link</a></body></html>").arg(server.url("/first.html").toEncoded())); + QTRY_COMPARE(page.loadSpy.size(), 1); + QVERIFY(page.loadSpy.takeFirst().value(0).toBool()); + + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); + QTRY_VERIFY(page.newPage); + QVERIFY(page.profile() == &profile1); + QVERIFY(page.newPage->profile() == &profile2); + // not load should occur or requests to server issued since web_contents is not expected to be adopted from other profile + QTRY_LOOP_IMPL(page.newPage->loadSpy.size() != 0, 1000, 100); + QVERIFY2(receivedRequests.isEmpty(), qPrintable(receivedRequests.join(", "))); } void tst_QWebEnginePage::renderProcessCrashed() @@ -4675,17 +5036,17 @@ void tst_QWebEnginePage::renderProcessPid() class FileSelectionTestPage : public QWebEnginePage { public: - FileSelectionTestPage() - { } + FileSelectionTestPage() : m_tempDir(QDir::tempPath() + "/tst_qwebenginepage-XXXXXX") { } QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles, const QStringList &acceptedMimeTypes) override { Q_UNUSED(oldFiles); chosenFileSelectionMode = mode; chosenAcceptedMimeTypes = acceptedMimeTypes; - return QStringList(); + return QStringList() << (m_tempDir.path() + "/file.txt"); } + QTemporaryDir m_tempDir; int chosenFileSelectionMode = -1; QStringList chosenAcceptedMimeTypes; }; @@ -4704,6 +5065,8 @@ void tst_QWebEnginePage::testChooseFilesParameters_data() << QWebEnginePage::FileSelectOpenMultiple << QStringList(); QTest::addRow("Folder upload") << QString("multiple webkitdirectory") << QString() << QWebEnginePage::FileSelectUploadFolder << QStringList(); + QTest::addRow("Save file") << QString("") << QString() + << QWebEnginePage::FileSelectSave << QStringList(); mimeTypes = QStringList() << "audio/*"; QTest::addRow("MIME type: audio") << QString() << QString("accept='%1'").arg(mimeTypes.join(',')) << QWebEnginePage::FileSelectOpen << mimeTypes; @@ -4737,11 +5100,18 @@ void tst_QWebEnginePage::testChooseFilesParameters() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - page.setHtml(QString("<html><body>" - "<input id='filePicker' type='file' name='filePicker' %1 %2 />" - "</body></html>").arg(uploadAttribute, mimeTypeAttribute)); + if (expectedFileSelectionMode != QWebEnginePage::FileSelectSave) { + page.setHtml(QString("<html><body>" + "<input id='filePicker' type='file' name='filePicker' %1 %2 />" + "</body></html>").arg(uploadAttribute, mimeTypeAttribute)); + } else { + page.setHtml(QString("<html><body>" + "<button id='filePicker' value='trigger' " + "onclick='window.showSaveFilePicker()'" + "</body></html>"), QString("qrc:/")); + } QVERIFY(spyFinished.wait()); - QTRY_COMPARE(spyFinished.count(), 1); + QTRY_COMPARE(spyFinished.size(), 1); evaluateJavaScriptSync(view.page(), "document.getElementById('filePicker').focus()"); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("filePicker")); @@ -4762,20 +5132,40 @@ void tst_QWebEnginePage::fileSystemAccessDialog() view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); - page.setHtml(QString("<html><body>" + connect(&page, &QWebEnginePage::fileSystemAccessRequested, + [](QWebEngineFileSystemAccessRequest request) { + QCOMPARE(request.accessFlags(), + QWebEngineFileSystemAccessRequest::Read + | QWebEngineFileSystemAccessRequest::Write); + request.accept(); + }); + + page.setHtml(QString("<html><head><script>" + "async function getTemporaryDir() {" + " const newHandle = await window.showSaveFilePicker();" + " const writable = await newHandle.createWritable();" + " await writable.write(new Blob(['New value']));" + " await writable.close();" + "" + " const fileData = await newHandle.getFile();" + " document.title = await fileData.text();" + "}" + "</script></head><body>" "<button id='triggerDialog' value='trigger' " - "onclick='window.showDirectoryPicker()'>" + "onclick='getTemporaryDir()'" "</body></html>"), QString("qrc:/")); QVERIFY(spyFinished.wait()); - QTRY_COMPARE(spyFinished.count(), 1); + QTRY_COMPARE(spyFinished.size(), 1); evaluateJavaScriptSync(view.page(), "document.getElementById('triggerDialog').focus()"); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("triggerDialog")); QTest::keyClick(view.focusProxy(), Qt::Key_Enter); - QTRY_COMPARE(page.chosenFileSelectionMode, QWebEnginePage::FileSelectUploadFolder); + QTRY_COMPARE(page.title(), "New value"); + + QTRY_COMPARE(page.chosenFileSelectionMode, QWebEnginePage::FileSelectSave); QTRY_COMPARE(page.chosenAcceptedMimeTypes, QStringList()); } @@ -4832,11 +5222,11 @@ void tst_QWebEnginePage::audioMuted() page.setAudioMuted(true); loadSync(&page, QUrl("about:blank")); QCOMPARE(page.isAudioMuted(), true); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QCOMPARE(spy[0][0], QVariant(true)); page.setAudioMuted(false); QCOMPARE(page.isAudioMuted(), false); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); QCOMPARE(spy[1][0], QVariant(false)); } @@ -4846,9 +5236,9 @@ void tst_QWebEnginePage::closeContents() QSignalSpy spyFinished(&page, &QWebEnginePage::loadFinished); QSignalSpy windowCreatedSpy(&page, &TestPage::windowCreated); page.setUrl(QUrl("about:blank")); - QTRY_COMPARE(spyFinished.count(), 1); + QTRY_COMPARE(spyFinished.size(), 1); page.runJavaScript("var dialog = window.open('', '', 'width=100, height=100');"); - QTRY_COMPARE(windowCreatedSpy.count(), 1); + QTRY_COMPARE(windowCreatedSpy.size(), 1); QWebEngineView *dialogView = new QWebEngineView; QWebEnginePage *dialogPage = page.createdWindows[0]; @@ -4875,8 +5265,8 @@ void tst_QWebEnginePage::isSafeRedirect_data() fileScheme += "/"; #endif - QString tempDir(fileScheme + QDir::tempPath()); - QTest::newRow(qPrintable(tempDir)) << QUrl(tempDir) << QUrl(tempDir + "/"); + QString tempDir(fileScheme + QDir::tempPath() + "/"); + QTest::newRow(qPrintable(tempDir)) << QUrl(tempDir) << QUrl(tempDir); QTest::newRow(qPrintable(tempDir + QString("/foo/bar"))) << QUrl(tempDir + "/foo/bar") << QUrl(tempDir + "/foo/bar"); QTest::newRow("filesystem:http://foo.com/bar") << QUrl("filesystem:http://foo.com/bar") << QUrl("filesystem:http://foo.com/bar/"); } @@ -4889,11 +5279,452 @@ void tst_QWebEnginePage::isSafeRedirect() TestPage page; QSignalSpy spy(&page, SIGNAL(loadFinished(bool))); page.setUrl(requestedUrl); - QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 20000); + QTRY_COMPARE_WITH_TIMEOUT(spy.size(), 1, 20000); QCOMPARE(page.url(), expectedUrl); spy.clear(); } +class LocalRemoteUrlSchemeHandler : public QWebEngineUrlSchemeHandler +{ +public: + LocalRemoteUrlSchemeHandler(QObject *parent = nullptr) + : QWebEngineUrlSchemeHandler(parent) + { + } + ~LocalRemoteUrlSchemeHandler() = default; + + void requestStarted(QWebEngineUrlRequestJob *job) override + { + QBuffer *buffer = new QBuffer(job); + buffer->setData("<html><body><a href='remote://test.html' id='link'>Click link</a></body></html>"); + job->reply("text/html", buffer); + loaded = true; + } + bool loaded = false; +}; + +void tst_QWebEnginePage::localToRemoteNavigation() +{ + LocalRemoteUrlSchemeHandler local; + LocalRemoteUrlSchemeHandler remote; + QWebEngineProfile profile; + profile.installUrlSchemeHandler("local", &local); + profile.installUrlSchemeHandler("remote", &remote); + + QWebEnginePage page(&profile); + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + QWebEngineView view; + view.resize(640, 480); + view.show(); + view.setPage(&page); + page.setUrl(QUrl("local://test.html")); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); + QVERIFY(local.loaded); + + // Should navigate: + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 2, 20000); + QVERIFY(remote.loaded); + local.loaded = false; + remote.loaded = false; + + page.setUrl(QUrl("local://test.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 3, 20000); + QVERIFY(local.loaded && !remote.loaded); + + // Should not navigate: + page.runJavaScript(QStringLiteral("document.getElementById(\"link\").click()")); + QTest::qWait(500); + QVERIFY(!remote.loaded); +} + +void tst_QWebEnginePage::clientHints_data() +{ + QTest::addColumn<bool>("clientHintsEnabled"); + QTest::addColumn<QString>("arch"); + QTest::addColumn<QString>("platform"); + QTest::addColumn<QString>("model"); + QTest::addColumn<bool>("isMobile"); + QTest::addColumn<QString>("fullVersion"); + QTest::addColumn<QString>("platformVersion"); + QTest::addColumn<QString>("bitness"); + QTest::addColumn<bool>("isWOW64"); + QTest::addColumn<QHash<QString, QString>>("fullVersionList"); + + QTest::newRow("Modify values") << true << "Abc" << "AmigaOS" << "Ultra" << true << "1.99" << "3" << "x64" << true << QHash<QString, QString>({{"APITest", "1.0.0"}, {"App", "5.0"}}); + QTest::newRow("Empty values") << true << "" << "" << "" << false << "" << "" << "" << false << QHash<QString, QString>(); + QTest::newRow("Disable headers") << false << "" << "" << "" << false << "" << "" << "" << false << QHash<QString, QString>(); +} + +void tst_QWebEnginePage::clientHints() +{ + QFETCH(bool, clientHintsEnabled); + QFETCH(QString, arch); + QFETCH(QString, platform); + QFETCH(QString, model); + QFETCH(bool, isMobile); + QFETCH(QString, fullVersion); + QFETCH(QString, platformVersion); + QFETCH(QString, bitness); + QFETCH(bool, isWOW64); + typedef QHash<QString, QString> brandVersionPairs; + QFETCH(brandVersionPairs, fullVersionList); + + QWebEnginePage page; + QSignalSpy loadSpy(&page, SIGNAL(loadFinished(bool))); + + QWebEngineClientHints *clientHints = page.profile()->clientHints(); + clientHints->setAllClientHintsEnabled(clientHintsEnabled); + + HttpServer server; + int requestCount = 0; + connect(&server, &HttpServer::newRequest, [&] (HttpReqRep *r) { + // Platform and Mobile hints are always sent and can't be disabled with this API + QVERIFY(r->hasRequestHeader("Sec-CH-UA-Platform")); + QVERIFY(r->hasRequestHeader("Sec-CH-UA-Mobile")); + if (!clientHintsEnabled) { + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Arch")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Model")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Full-Version")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Platform-Version")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Bitness")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Wow64")); + QVERIFY(!r->hasRequestHeader("Sec-CH-UA-Full-Version-List")); + } + + // The first request header won't contain any hints, only after a response with "Accept-CH" + if (requestCount > 1 && clientHintsEnabled) { + // All hint values are lower case in the headers + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Arch")).remove("\""), arch.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Platform")).remove("\""), platform.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Model")).remove("\""), model.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Mobile")).remove("\""), isMobile ? "?1" : "?0"); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Full-Version")).remove("\""), fullVersion.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Platform-Version")).remove("\""), platformVersion.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Bitness")).remove("\""), bitness.toLower()); + QCOMPARE(QString(r->requestHeader("Sec-CH-UA-Wow64")).remove("\""), isWOW64 ? "?1" : "?0"); + for (auto i = fullVersionList.cbegin(), end = fullVersionList.cend(); i != end; ++i) + QVERIFY(QString(r->requestHeader("Sec-CH-UA-Full-Version-List")).contains(i.key().toLower())); + } + + r->setResponseHeader("Accept-CH", "Sec-CH-UA-Arch, Sec-CH-UA-Bitness, Sec-CH-UA-Full-Version, Sec-CH-UA-Full-Version-List, Sec-CH-UA-Mobile, Sec-CH-UA-Model, Sec-CH-UA-Platform-Version, Sec-CH-UA-Platform, Sec-CH-UA-Wow64, Sec-CH-UA"); + r->sendResponse(); + requestCount++; + }); + QVERIFY(server.start()); + + clientHints->setArch(arch); + clientHints->setPlatform(platform); + clientHints->setModel(model); + clientHints->setIsMobile(isMobile); + clientHints->setFullVersion(fullVersion); + clientHints->setPlatformVersion(platformVersion); + clientHints->setBitness(bitness); + clientHints->setIsWow64(isWOW64); + clientHints->setFullVersionList(fullVersionList); + + page.setUrl(server.url()); + QTRY_COMPARE(loadSpy.size(), 1); + QVERIFY(loadSpy.takeFirst().value(0).toBool()); + + QCOMPARE(clientHints->arch(), arch); + QCOMPARE(clientHints->platform(), platform); + QCOMPARE(clientHints->model(), model); + QCOMPARE(clientHints->isMobile(), isMobile); + QCOMPARE(clientHints->fullVersion(), fullVersion); + QCOMPARE(clientHints->platformVersion(), platformVersion); + QCOMPARE(clientHints->bitness(), bitness); + QCOMPARE(clientHints->isWow64(), isWOW64); + for (auto i = fullVersionList.cbegin(), end = fullVersionList.cend(); i != end; ++i) + QCOMPARE(clientHints->fullVersionList()[i.key()], i.value()); + + // A new user agent string should not override/disable client hints + page.profile()->setHttpUserAgent(QStringLiteral("Custom user agent")); + page.triggerAction(QWebEnginePage::Reload); + QTRY_COMPARE(loadSpy.size(), 1); + + // Reset all to default values + clientHints->resetAll(); + QCOMPARE_NE(clientHints->arch(), arch); +#ifdef Q_OS_LINUX + QCOMPARE(clientHints->platform().toLower(), "linux"); +#elif defined (Q_OS_MACOS) + QCOMPARE(clientHints->platform().toLower(), "macos"); +#elif defined (Q_OS_WIN) + QCOMPARE(clientHints->platform().toLower(), "windows"); +#endif + QCOMPARE_NE(clientHints->fullVersion(), fullVersion); + QCOMPARE_NE(clientHints->platformVersion(), platformVersion); + QCOMPARE_NE(clientHints->bitness(), bitness); + for (auto i = fullVersionList.cbegin(), end = fullVersionList.cend(); i != end; ++i) + QVERIFY(!clientHints->fullVersionList().contains(i.key())); + QVERIFY(clientHints->fullVersionList().contains("Chromium")); +} + +void tst_QWebEnginePage::childFrameInput() +{ + HttpServer server; + server.setHostDomain("localhost"); + + // The cross-origin policy blocks scripting this frame with QWebEnginePage::runJavaScript. + // Use console messages to validate events. + QString innerHtml( + "<html><head><style>body{height:1200px;width:1200px;}</style></head><body>test<script>" + " let lastX, lastY = 0;" + " document.onscroll = (e) => {" + " if (window.scrollY > lastY) console.log(\"Down\");" + " if (window.scrollY < lastY) console.log(\"Up\");" + " if (window.scrollX > lastX) console.log(\"Right\");" + " if (window.scrollX < lastX) console.log(\"Left\");" + " lastX = window.scrollX;" + " lastY = window.scrollY;" + " };" + " window.onload = () => {console.log('loaded');};" + "</script></body></html>"); + + QVERIFY(server.start()); + connect(&server, &HttpServer::newRequest, [&](HttpReqRep *rr) { + if (rr->requestPath() == "/main.html") { + // the Origin-Agent-Cluster header enables dedicated processes for origins + rr->setResponseHeader("Origin-Agent-Cluster", "?1"); + // the same-site-cross-origin page forces to create the frame in a different process + server.setHostDomain("sub.localhost"); + rr->setResponseBody(("<html><body>" + "<iframe id=\"iframe\" width=90% height=90% src=\"" + + server.url().toString().toUtf8() + + "inner.html\"></iframe>" + "</body></html>")); + } + if (rr->requestPath() == "/inner.html") + rr->setResponseBody(innerHtml.toUtf8()); + rr->sendResponse(); + }); + + QWebEngineView view; + ConsolePage page; + view.setPage(&page); + view.resize(640, 480); + QSignalSpy loadSpy(&page, &QWebEnginePage::loadFinished); + page.load(server.url("/main.html")); + QTRY_COMPARE_WITH_TIMEOUT(loadSpy.size(), 1, 20000); + + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTRY_VERIFY(evaluateJavaScriptSync(&page, "window.originAgentCluster").toBool()); + + // make sure the frame is loaded + QTRY_COMPARE(page.messages.size(), 1); + QTRY_COMPARE(page.messages[0], QString("loaded")); + + // focus + evaluateJavaScriptSync(&page, "document.getElementById('iframe').contentWindow.focus()"); + QTRY_COMPARE(evaluateJavaScriptSync(&page, "document.activeElement.id").toString(), + QStringLiteral("iframe")); + + QPoint globalPos = view.windowHandle()->position(); + QPoint p = elementCenter(&page, QString("iframe")); + + // Even if the document is loaded, it is not necessarily drawn. + // Hit-testing (in Viz) for pointer events will be flacky in this scenario. + // Send keyClick events first so the target frame will be cached for wheel events. + QTest::keyClick(view.focusProxy(), Qt::Key_Down); + QTRY_COMPARE(page.messages.size(), 2); + QTRY_COMPARE(page.messages[1], QString("Down")); + + QTest::keyClick(view.focusProxy(), Qt::Key_Up); + QTRY_COMPARE(page.messages.size(), 3); + QTRY_COMPARE(page.messages[2], QString("Up")); + + QTest::keyClick(view.focusProxy(), Qt::Key_Right); + QTRY_COMPARE(page.messages.size(), 4); + QTRY_COMPARE(page.messages[3], QString("Right")); + + QTest::keyClick(view.focusProxy(), Qt::Key_Left); + QTRY_COMPARE(page.messages.size(), 5); + QTRY_COMPARE(page.messages[4], QString("Left")); + + makeScroll(view.focusProxy(), p, globalPos, QPoint(0, -120)); + QTRY_COMPARE(page.messages.size(), 6); + QTRY_COMPARE(page.messages[5], QString("Down")); + + makeScroll(view.focusProxy(), p, globalPos, QPoint(0, 120)); + QTRY_COMPARE(page.messages.size(), 7); + QTRY_COMPARE(page.messages[6], QString("Up")); + + makeScroll(view.focusProxy(), p, globalPos, QPoint(-120, 0)); + QTRY_COMPARE(page.messages.size(), 8); + QTRY_COMPARE(page.messages[7], QString("Right")); + + makeScroll(view.focusProxy(), p, globalPos, QPoint(120, 0)); + QTRY_COMPARE(page.messages.size(), 9); + QTRY_COMPARE(page.messages[8], QString("Left")); +} + +void tst_QWebEnginePage::openLinkInNewPageWithWebWindowType_data() +{ + QTest::addColumn<QWebEnginePage::WebWindowType>("webWindowType"); + QTest::addColumn<QString>("elementId"); + QTest::addColumn<Qt::MouseButton>("button"); + QTest::addColumn<Qt::KeyboardModifier>("keyboardModififer"); + QTest::newRow("webBrowserWindow") + << QWebEnginePage::WebBrowserWindow << "link" << Qt::LeftButton << Qt::ShiftModifier; + QTest::newRow("webBrowserTab") + << QWebEnginePage::WebBrowserTab << "link" << Qt::LeftButton << Qt::NoModifier; + QTest::newRow("webDialog") << QWebEnginePage::WebDialog << "openWindow" << Qt::LeftButton + << Qt::NoModifier; + QTest::newRow("webBrowserBackgroundTab") << QWebEnginePage::WebBrowserBackgroundTab << "link" + << Qt::MiddleButton << Qt::NoModifier; +} + +class WebWindowTypeTestPage : public QWebEnginePage +{ + Q_OBJECT + +public: + WebWindowType windowType; + +signals: + void windowCreated(); + +private: + QWebEnginePage *createWindow(WebWindowType type) override + { + windowType = type; + emit windowCreated(); + return nullptr; + } +}; + +void tst_QWebEnginePage::openLinkInNewPageWithWebWindowType() +{ + QFETCH(QWebEnginePage::WebWindowType, webWindowType); + QFETCH(QString, elementId); + QFETCH(Qt::MouseButton, button); + QFETCH(Qt::KeyboardModifier, keyboardModififer); + + WebWindowTypeTestPage page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + QSignalSpy windowCreatedSpy(&page, &WebWindowTypeTestPage::windowCreated); + QWebEngineView view(&page); + view.resize(640, 480); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + page.settings()->setAttribute(QWebEngineSettings::JavascriptEnabled, true); + page.settings()->setAttribute(QWebEngineSettings::JavascriptCanOpenWindows, true); + QString html = "<html><body>" + "<a id='link' href='hello' target='_blank'>link</a>" + "<br><br>" + "<button id='openWindow' onclick='myFunction()'>Try it</button>" + "<script>" + "function myFunction() {" + " const myWindow = window.open('', '', 'width=300,height=300');" + "}" + "</script>" + "</body></html>"; + + page.setHtml(html); + QVERIFY(loadFinishedSpy.wait()); + + QTest::mouseClick(view.focusProxy(), button, keyboardModififer, + elementCenter(&page, elementId)); + QVERIFY(windowCreatedSpy.wait()); + QCOMPARE(page.windowType, webWindowType); +} + +class DoNothingInterceptor : public QWebEngineUrlRequestInterceptor +{ +public: + DoNothingInterceptor() { } + + void interceptRequest(QWebEngineUrlRequestInfo &) override + { + ran = true; + } + bool ran = false; +}; + +void tst_QWebEnginePage::keepInterceptorAfterNewWindowRequested() +{ + DoNothingInterceptor interceptor; + QWebEnginePage page; + page.setUrlRequestInterceptor(&interceptor); + connect(&page, &QWebEnginePage::newWindowRequested, [&](QWebEngineNewWindowRequest &request) { + request.openIn(&page); + }); + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + + QWebEngineView view; + view.resize(500, 500); + view.setPage(&page); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + page.setHtml("<html><body>" + "<a id='link' href='hello' target='_blank'>link</a>" + "</body></html>"); + QTRY_COMPARE(loadFinishedSpy.size(), 1); + QVERIFY(loadFinishedSpy.takeFirst().value(0).toBool()); + QVERIFY(interceptor.ran); + interceptor.ran = false; + + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); + QTRY_COMPARE(loadFinishedSpy.size(), 1); + QVERIFY(loadFinishedSpy.takeFirst().value(0).toBool()); + QVERIFY(!interceptor.ran); + + page.setHtml("<html><body></body></html>"); + QTRY_COMPARE(loadFinishedSpy.size(), 1); + QVERIFY(loadFinishedSpy.takeFirst().value(0).toBool()); + QVERIFY(interceptor.ran); +} + +void tst_QWebEnginePage::chooseDesktopMedia() +{ +#if QT_CONFIG(webengine_extensions) && QT_CONFIG(webengine_webrtc) + HttpServer server; + server.setHostDomain("localhost"); + connect(&server, &HttpServer::newRequest, &server, [&] (HttpReqRep *r) { + if (r->requestMethod() == "GET") + r->setResponseBody("<html></html>"); + }); + QVERIFY(server.start()); + + QWebEnginePage page; + QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + page.settings()->setAttribute(QWebEngineSettings::ScreenCaptureEnabled, true); + + bool desktopMediaRequested = false; + bool permissionRequested = false; + + connect(&page, &QWebEnginePage::desktopMediaRequested, + [&](const QWebEngineDesktopMediaRequest &) { + desktopMediaRequested = true; + }); + + connect(&page, &QWebEnginePage::featurePermissionRequested, + [&](const QUrl &securityOrigin, QWebEnginePage::Feature feature) { + permissionRequested = true; + // Handle permission to 'complete' the media request + page.setFeaturePermission(securityOrigin, feature, + QWebEnginePage::PermissionGrantedByUser); + }); + + page.load(QUrl(server.url())); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 20000); + + const QString extensionId("nkeimhogjdpnpccoofpliimaahmaaome"); + page.runJavaScript(QString("(() => {" + " let port = chrome.runtime.connect(\"%1\", {name: \"chooseDesktopMedia\"});" + " port.postMessage({method: \"chooseDesktopMedia\"});" + "})()").arg(extensionId)); + + QTRY_VERIFY(desktopMediaRequested); + QTRY_VERIFY(permissionRequested); +#endif // QT_CONFIG(webengine_extensions) && QT_CONFIG(webengine_webrtc) +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) |