diff options
Diffstat (limited to 'tests/auto/widgets')
-rw-r--r-- | tests/auto/widgets/accessibility/tst_accessibility.cpp | 84 | ||||
-rw-r--r-- | tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp | 4 | ||||
-rw-r--r-- | tests/auto/widgets/origins/BLACKLIST | 3 | ||||
-rw-r--r-- | tests/auto/widgets/origins/tst_origins.cpp | 22 | ||||
-rw-r--r-- | tests/auto/widgets/proxypac/proxypac.pro | 4 | ||||
-rw-r--r-- | tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp | 48 | ||||
-rw-r--r-- | tests/auto/widgets/qwebenginepage/BLACKLIST | 12 | ||||
-rw-r--r-- | tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp | 335 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp | 56 | ||||
-rw-r--r-- | tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp | 287 | ||||
-rw-r--r-- | tests/auto/widgets/schemes/tst_schemes.cpp | 76 | ||||
-rw-r--r-- | tests/auto/widgets/spellchecking/tst_spellchecking.cpp | 8 | ||||
-rw-r--r-- | tests/auto/widgets/util.h | 2 |
13 files changed, 652 insertions, 289 deletions
diff --git a/tests/auto/widgets/accessibility/tst_accessibility.cpp b/tests/auto/widgets/accessibility/tst_accessibility.cpp index d69a4c0a7..5f472332f 100644 --- a/tests/auto/widgets/accessibility/tst_accessibility.cpp +++ b/tests/auto/widgets/accessibility/tst_accessibility.cpp @@ -20,9 +20,13 @@ #include <qtest.h> #include "../util.h" +#include <QHBoxLayout> +#include <QMainWindow> + #include <qaccessible.h> #include <qwebengineview.h> #include <qwebenginepage.h> +#include <qwebenginesettings.h> #include <qwidget.h> class tst_Accessibility : public QObject @@ -38,6 +42,8 @@ public Q_SLOTS: private Q_SLOTS: void noPage(); void hierarchy(); + void focusChild(); + void focusChild_data(); void text(); void value(); void roles_data(); @@ -142,6 +148,80 @@ void tst_Accessibility::hierarchy() QCOMPARE(input, child); } +void tst_Accessibility::focusChild_data() +{ + QTest::addColumn<QString>("interfaceName"); + QTest::addColumn<QVector<QAccessible::Role>>("ancestorRoles"); + + QTest::newRow("QWebEngineView") << QString("QWebEngineView") << QVector<QAccessible::Role>({QAccessible::Client}); + QTest::newRow("RenderWidgetHostViewQtDelegate") << QString("RenderWidgetHostViewQtDelegate") << QVector<QAccessible::Role>({QAccessible::Client}); + QTest::newRow("QMainWindow") << QString("QMainWindow") << QVector<QAccessible::Role>({QAccessible::Window, QAccessible::Client /* central widget */, QAccessible::Client /* view */}); +} + +void tst_Accessibility::focusChild() +{ + auto traverseToWebDocumentAccessibleInterface = [](QAccessibleInterface *iface) -> QAccessibleInterface * { + QFETCH(QVector<QAccessible::Role>, ancestorRoles); + for (int i = 0; i < ancestorRoles.size(); ++i) { + if (iface->childCount() == 0 || iface->role() != ancestorRoles[i]) + return nullptr; + iface = iface->child(0); + } + + if (iface->role() != QAccessible::WebDocument) + return nullptr; + + return iface; + }; + + QMainWindow mainWindow; + QWebEngineView *webView = new QWebEngineView; + QWidget *centralWidget = new QWidget; + QHBoxLayout *centralLayout = new QHBoxLayout; + centralWidget->setLayout(centralLayout); + mainWindow.setCentralWidget(centralWidget); + centralLayout->addWidget(webView); + + mainWindow.show(); + QVERIFY(QTest::qWaitForWindowExposed(&mainWindow)); + + webView->settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); + webView->setHtml("<html><body>" \ + "<input id='input1' type='text' value='some text'/>" \ + "</body></html>"); + webView->show(); + QSignalSpy spyFinished(webView, &QWebEngineView::loadFinished); + QVERIFY(spyFinished.wait()); + + QVERIFY(webView->focusWidget()); + QAccessibleInterface *iface = nullptr; + QFETCH(QString, interfaceName); + if (interfaceName == "QWebEngineView") + iface = QAccessible::queryAccessibleInterface(webView); + else if (interfaceName == "RenderWidgetHostViewQtDelegate") + iface = QAccessible::queryAccessibleInterface(webView->focusWidget()); + else if (interfaceName == "QMainWindow") + iface = QAccessible::queryAccessibleInterface(&mainWindow); + QVERIFY(iface); + + // Make sure the input field does not have the focus. + evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').blur()"); + QTRY_VERIFY(evaluateJavaScriptSync(webView->page(), "document.activeElement.id").toString().isEmpty()); + + QVERIFY(iface->focusChild()); + QTRY_COMPARE(iface->focusChild()->role(), QAccessible::WebDocument); + QCOMPARE(traverseToWebDocumentAccessibleInterface(iface), iface->focusChild()); + + // Set active focus on the input field. + evaluateJavaScriptSync(webView->page(), "document.getElementById('input1').focus()"); + QTRY_COMPARE(evaluateJavaScriptSync(webView->page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + + QVERIFY(iface->focusChild()); + QTRY_COMPARE(iface->focusChild()->role(), QAccessible::EditableText); + // <html> -> <body> -> <input> + QCOMPARE(traverseToWebDocumentAccessibleInterface(iface)->child(0)->child(0), iface->focusChild()); +} + void tst_Accessibility::text() { QWebEngineView webView; @@ -259,7 +339,7 @@ void tst_Accessibility::roles_data() QTest::newRow("AX_ROLE_ABBR") << QString("<abbr>a</abbr>") << false << QAccessible::StaticText; QTest::newRow("AX_ROLE_ALERT") << QString("<div role='alert'>alert</div>") << true << QAccessible::AlertMessage; QTest::newRow("AX_ROLE_ALERT_DIALOG") << QString("<div role='alertdialog'>alert</div>") << true << QAccessible::AlertMessage; - //QTest::newRow("AX_ROLE_ANCHOR") << QString("<a>target</a>") << false << QAccessible::Link; // FIXME: The test case might be wrong (see https://codereview.chromium.org/2713193003) + QTest::newRow("AX_ROLE_ANCHOR") << QString("<a id='a'>Chapter a</a>") << false << QAccessible::Link; QTest::newRow("AX_ROLE_ANNOTATION") << QString("<rt>a</rt>") << false << QAccessible::StaticText; QTest::newRow("AX_ROLE_APPLICATION") << QString("<div role='application'>landmark</div>") << true << QAccessible::Document; QTest::newRow("AX_ROLE_ARTICLE") << QString("<article>a</article>") << true << QAccessible::Section; @@ -365,7 +445,7 @@ void tst_Accessibility::roles_data() //QTest::newRow("AX_ROLE_TABLE_HEADER_CONTAINER"); // No mapping to ARIA role QTest::newRow("AX_ROLE_TAB") << QString("<div role='tab'>a</div>") << true << QAccessible::PageTab; QTest::newRow("AX_ROLE_TAB_LIST") << QString("<div role='tablist'>a</div>") << true << QAccessible::PageTabList; - QTest::newRow("AX_ROLE_TAB_PANEL") << QString("<div role='tab'>a</div>") << true << QAccessible::PageTab; + QTest::newRow("AX_ROLE_TAB_PANEL") << QString("<div role='tabpanel'>a</div>") << true << QAccessible::Pane; QTest::newRow("AX_ROLE_TERM") << QString("<div role='term'>a</div>") << true << QAccessible::StaticText; QTest::newRow("AX_ROLE_TEXT_FIELD") << QString("<input type='text'></input>") << false << QAccessible::EditableText; QTest::newRow("AX_ROLE_TIME") << QString("<time>a</time>") << false << QAccessible::Clock; diff --git a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp index 1469ddb15..46038cdc6 100644 --- a/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp +++ b/tests/auto/widgets/faviconmanager/tst_faviconmanager.cpp @@ -522,10 +522,10 @@ void tst_FaviconManager::touchIconWithSameURL() "<link rel='icon' type='image/png' href='" + icon + "'/>" "<link rel='apple-touch-icon' type='image/png' href='" + icon + "'/>" "</html>"); - QTRY_COMPARE(loadFinishedSpy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); // The default favicon has to be loaded even if its URL is also set as a touch icon while touch icons are disabled. - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.count(), 1, 30000); + QTRY_COMPARE(iconUrlChangedSpy.count(), 1); QCOMPARE(m_page->iconUrl().toString(), icon); QTRY_COMPARE(iconChangedSpy.count(), 1); diff --git a/tests/auto/widgets/origins/BLACKLIST b/tests/auto/widgets/origins/BLACKLIST new file mode 100644 index 000000000..db858f11e --- /dev/null +++ b/tests/auto/widgets/origins/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-81556 +[mixedXHR] +* diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp index c63f4d690..e3927f763 100644 --- a/tests/auto/widgets/origins/tst_origins.cpp +++ b/tests/auto/widgets/origins/tst_origins.cpp @@ -481,6 +481,8 @@ void tst_Origins::subdirWithoutAccess() { ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/subdir/index.html"))); QCOMPARE(eval(QSL("msg[0]")), QVariant()); QCOMPARE(eval(QSL("msg[1]")), QVariant()); @@ -507,22 +509,28 @@ void tst_Origins::mixedSchemes() QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/mixedSchemes.html"))); eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("qrc:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("tst:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')")); @@ -531,36 +539,47 @@ void tst_Origins::mixedSchemes() QVERIFY(verifyLoad(QSL("PathSyntax:/resources/mixedSchemes.html"))); eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("PathSyntax-LocalAccessAllowed:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/mixedSchemes.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource"))); eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemes.html"))); eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); } @@ -569,14 +588,17 @@ void tst_Origins::mixedSchemes() void tst_Origins::mixedSchemesWithCsp() { QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemesWithCsp.html"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy"))); eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy"))); eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); QVERIFY(verifyLoad(QSL("HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemesWithCsp.html"))); eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess"))); + QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError"))); eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://b/resources/mixedSchemes_frame.html')")); QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess"))); } diff --git a/tests/auto/widgets/proxypac/proxypac.pro b/tests/auto/widgets/proxypac/proxypac.pro index 4dbcd9365..2aacb4366 100644 --- a/tests/auto/widgets/proxypac/proxypac.pro +++ b/tests/auto/widgets/proxypac/proxypac.pro @@ -4,8 +4,10 @@ HEADERS += proxyserver.h SOURCES += proxyserver.cpp proxy_pac.name = QTWEBENGINE_CHROMIUM_FLAGS + +win32:proxy_pac.value = --proxy-pac-url="file:///$$PWD/proxy.pac" +else:proxy_pac.value = --proxy-pac-url="file://$$PWD/proxy.pac" boot2qt:proxy_pac.value = "--single-process --no-sandbox --proxy-pac-url=file://$$PWD/proxy.pac" -else: proxy_pac.value = --proxy-pac-url="file://$$PWD/proxy.pac" QT_TOOL_ENV += proxy_pac diff --git a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp index d34e3cefe..55d8ac6e8 100644 --- a/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp +++ b/tests/auto/widgets/qwebenginedownloaditem/tst_qwebenginedownloaditem.cpp @@ -80,6 +80,7 @@ private Q_SLOTS: #if QT_DEPRECATED_SINCE(5, 14) void downloadPathValidation(); #endif + void downloadToDirectoryWithFileName_data(); void downloadToDirectoryWithFileName(); private: @@ -622,14 +623,17 @@ void tst_QWebEngineDownloadItem::downloadTwoLinks() void tst_QWebEngineDownloadItem::downloadPage_data() { + QTest::addColumn<bool>("saveWithPageAction"); QTest::addColumn<QWebEngineDownloadItem::SavePageFormat>("savePageFormat"); - QTest::newRow("SingleHtmlSaveFormat") << QWebEngineDownloadItem::SingleHtmlSaveFormat; - QTest::newRow("CompleteHtmlSaveFormat") << QWebEngineDownloadItem::CompleteHtmlSaveFormat; - QTest::newRow("MimeHtmlSaveFormat") << QWebEngineDownloadItem::MimeHtmlSaveFormat; + QTest::newRow("SingleHtmlSaveFormat") << false << QWebEngineDownloadItem::SingleHtmlSaveFormat; + QTest::newRow("CompleteHtmlSaveFormat") << false << QWebEngineDownloadItem::CompleteHtmlSaveFormat; + QTest::newRow("MimeHtmlSaveFormat") << false << QWebEngineDownloadItem::MimeHtmlSaveFormat; + QTest::newRow("SavePageAction") << true << QWebEngineDownloadItem::MimeHtmlSaveFormat; } void tst_QWebEngineDownloadItem::downloadPage() { + QFETCH(bool, saveWithPageAction); QFETCH(QWebEngineDownloadItem::SavePageFormat, savePageFormat); // Set up HTTP server @@ -649,12 +653,12 @@ void tst_QWebEngineDownloadItem::downloadPage() // Set up profile and download handler QTemporaryDir tmpDir; QVERIFY(tmpDir.isValid()); - QString downloadPath = tmpDir.path() + QStringLiteral("/test.html"); + QString downloadFileName("test.html"), downloadPath = tmpDir.filePath(downloadFileName); QUrl downloadUrl = m_server->url("/"); int acceptedCount = 0; int finishedCount = 0; ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { - QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadInProgress); + QCOMPARE(item->state(), saveWithPageAction ? QWebEngineDownloadItem::DownloadRequested : QWebEngineDownloadItem::DownloadInProgress); QCOMPARE(item->isFinished(), false); QCOMPARE(item->totalBytes(), -1); QCOMPARE(item->receivedBytes(), 0); @@ -663,11 +667,19 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(item->isSavePageDownload(), true); // FIXME(juvaldma): why is mimeType always the same? QCOMPARE(item->mimeType(), QStringLiteral("application/x-mimearchive")); - QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); QCOMPARE(item->savePageFormat(), savePageFormat); QCOMPARE(item->url(), downloadUrl); QCOMPARE(item->page(), m_page); - // no need to call item->accept() + + if (saveWithPageAction) { + QVERIFY(!item->downloadDirectory().isEmpty()); + QVERIFY(!item->downloadFileName().isEmpty()); + item->setDownloadDirectory(tmpDir.path()); + item->setDownloadFileName(downloadFileName); + item->accept(); + } // save with explicit path accepts download automatically + + QCOMPARE(QDir(item->downloadDirectory()).filePath(item->downloadFileName()), downloadPath); connect(item, &QWebEngineDownloadItem::finished, [&, item]() { QCOMPARE(item->state(), QWebEngineDownloadItem::DownloadCompleted); @@ -697,7 +709,11 @@ void tst_QWebEngineDownloadItem::downloadPage() QCOMPARE(indexRequestCount, 1); // Save some HTML - m_page->save(downloadPath, savePageFormat); + if (saveWithPageAction) + m_page->triggerAction(QWebEnginePage::SavePage); + else + m_page->save(downloadPath, savePageFormat); + QTRY_COMPARE(acceptedCount, 1); QTRY_COMPARE(finishedCount, 1); QFile file(downloadPath); @@ -1256,8 +1272,17 @@ void tst_QWebEngineDownloadItem::downloadPathValidation() } #endif +void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName_data() +{ + QTest::addColumn<bool>("setDirectoryFirst"); + + QTest::newRow("setDirectoryFirst") << true; + QTest::newRow("setFileNameFirst") << false; +} + void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName() { + QFETCH(bool, setDirectoryFirst); QString downloadDirectory; QString downloadFileName; QString downloadedFilePath; @@ -1287,7 +1312,7 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName() // Set up profile and download handler ScopedConnection sc2 = connect(m_profile, &QWebEngineProfile::downloadRequested, [&](QWebEngineDownloadItem *item) { - if (!downloadDirectory.isEmpty()) { + if (!downloadDirectory.isEmpty() && setDirectoryFirst) { item->setDownloadDirectory(downloadDirectory); QCOMPARE(item->downloadDirectory(), downloadDirectory); } @@ -1297,6 +1322,11 @@ void tst_QWebEngineDownloadItem::downloadToDirectoryWithFileName() QCOMPARE(item->downloadFileName(), downloadFileName); } + if (!downloadDirectory.isEmpty() && !setDirectoryFirst) { + item->setDownloadDirectory(downloadDirectory); + QCOMPARE(item->downloadDirectory(), downloadDirectory); + } + QCOMPARE(item->path(), QDir(item->downloadDirectory()).filePath(item->downloadFileName())); item->accept(); diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST index 7857ee818..3053876d4 100644 --- a/tests/auto/widgets/qwebenginepage/BLACKLIST +++ b/tests/auto/widgets/qwebenginepage/BLACKLIST @@ -3,6 +3,14 @@ osx [mouseMovementProperties] windows +macos # Can't move cursor (QTBUG-76312) -[fullScreenRequested] -windows +# QTBUG-81614 +[setHtmlWithBaseURL] +* + +[devTools] +msvc-2019 + +[setLifecycleStateWithDevTools] +msvc-2019 diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 27aa7a1f7..7fdf897ca 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -225,9 +225,14 @@ private Q_SLOTS: void editActionsWithoutSelection(); void customUserAgentInNewTab(); + void renderProcessCrashed(); + void renderProcessPid(); 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; @@ -754,20 +759,39 @@ void tst_QWebEnginePage::textSelection() void tst_QWebEnginePage::backActionUpdate() { QWebEngineView view; + view.resize(640, 480); + view.show(); + QWebEnginePage *page = view.page(); + QSignalSpy loadSpy(page, &QWebEnginePage::loadFinished); QAction *action = page->action(QWebEnginePage::Back); QVERIFY(!action->isEnabled()); - QSignalSpy loadSpy(page, SIGNAL(loadFinished(bool))); - QUrl url = QUrl("qrc:///resources/framedindex.html"); - page->load(url); + + page->load(QUrl("qrc:///resources/framedindex.html")); QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000); QVERIFY(!action->isEnabled()); - QTest::mouseClick(&view, Qt::LeftButton, 0, QPoint(10, 10)); - QEXPECT_FAIL("", "Behavior change: Load signals are emitted only for the main frame in QtWebEngine.", Continue); - QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 2, 100); - QEXPECT_FAIL("", "FIXME: Mouse events aren't passed from the QWebEngineView down to the RWHVQtDelegateWidget", Continue); - QVERIFY(action->isEnabled()); + auto firstAnchorCenterInFrame = [](QWebEnginePage *page, const QString &frameName) { + QVariantList rectList = evaluateJavaScriptSync(page, + "(function(){" + "var frame = document.getElementsByName('" + frameName + "')[0];" + "var anchor = frame.contentDocument.getElementsByTagName('a')[0];" + "var rect = anchor.getBoundingClientRect();" + "return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" + "})()").toList(); + + if (rectList.count() != 2) { + qWarning("firstAnchorCenterInFrame failed."); + return QPoint(); + } + + return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); + }; + + QVERIFY(evaluateJavaScriptSync(page, "document.getElementsByName('frame_b')[0].contentDocument == undefined").toBool()); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, firstAnchorCenterInFrame(page, "frame_c")); + QTRY_VERIFY(evaluateJavaScriptSync(page, "document.getElementsByName('frame_b')[0].contentDocument != undefined").toBool()); + QTRY_VERIFY(action->isEnabled()); } void tst_QWebEnginePage::localStorageVisibility() @@ -947,7 +971,7 @@ void tst_QWebEnginePage::findText() { CallbackSpy<bool> callbackSpy; QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); - m_view->findText("", 0, callbackSpy.ref()); + m_view->findText("", {}, callbackSpy.ref()); QVERIFY(callbackSpy.wasCalled()); QCOMPARE(signalSpy.count(), 1); QTRY_COMPARE(m_view->selectedText(), QString("foo bar")); @@ -958,7 +982,7 @@ void tst_QWebEnginePage::findText() { CallbackSpy<bool> callbackSpy; QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); - m_view->findText("Will not be found", 0, callbackSpy.ref()); + m_view->findText("Will not be found", {}, callbackSpy.ref()); QCOMPARE(callbackSpy.waitForResult(), false); QTRY_COMPARE(signalSpy.count(), 1); auto result = signalSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); @@ -975,7 +999,7 @@ void tst_QWebEnginePage::findText() { CallbackSpy<bool> callbackSpy; QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); - m_view->findText("foo", 0, callbackSpy.ref()); + m_view->findText("foo", {}, callbackSpy.ref()); QVERIFY(callbackSpy.waitForResult()); QTRY_COMPARE(signalSpy.count(), 1); QTRY_VERIFY(m_view->selectedText().isEmpty()); @@ -986,11 +1010,24 @@ void tst_QWebEnginePage::findText() { CallbackSpy<bool> callbackSpy; QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); - m_view->findText("", 0, callbackSpy.ref()); + m_view->findText("", {}, callbackSpy.ref()); QTRY_VERIFY(callbackSpy.wasCalled()); QTRY_COMPARE(signalSpy.count(), 1); QTRY_COMPARE(m_view->selectedText(), QString("foo")); } + + // Invoking startFinding operation for the same text twice. Without any wait, the second one + // should interrupt the first one. + { + QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished); + m_view->findText("foo", {}); + m_view->findText("foo", {}); + QTRY_COMPARE(signalSpy.count(), 2); + QTRY_VERIFY(m_view->selectedText().isEmpty()); + + QCOMPARE(signalSpy.at(0).value(0).value<QWebEngineFindTextResult>().numberOfMatches(), 0); + QCOMPARE(signalSpy.at(1).value(0).value<QWebEngineFindTextResult>().numberOfMatches(), 1); + } } void tst_QWebEnginePage::findTextResult() @@ -1039,11 +1076,11 @@ void tst_QWebEnginePage::findTextSuccessiveShouldCallAllCallbacks() 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); - m_page->findText("abcde", 0, spy1.ref()); - m_page->findText("abcd", 0, spy2.ref()); - m_page->findText("abc", 0, spy3.ref()); - m_page->findText("ab", 0, spy4.ref()); - m_page->findText("a", 0, spy5.ref()); + m_page->findText("abcde", {}, spy1.ref()); + m_page->findText("abcd", {}, spy2.ref()); + m_page->findText("abc", {}, spy3.ref()); + m_page->findText("ab", {}, spy4.ref()); + m_page->findText("a", {}, spy5.ref()); spy5.waitForResult(); QVERIFY(spy1.wasCalled()); QVERIFY(spy2.wasCalled()); @@ -1064,10 +1101,10 @@ void tst_QWebEnginePage::findTextCalledOnMatch() // CALLBACK bool callbackCalled = false; - m_view->page()->findText("foo", 0, [this, &callbackCalled](bool found) { + m_view->page()->findText("foo", {}, [this, &callbackCalled](bool found) { QVERIFY(found); - m_view->page()->findText("bar", 0, [&callbackCalled](bool found) { + m_view->page()->findText("bar", {}, [&callbackCalled](bool found) { QVERIFY(found); callbackCalled = true; }); @@ -1101,7 +1138,7 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal() // Iterate over all "foo" matches. for (int i = 1; i <= 3; ++i) { - m_view->page()->findText("foo", 0); + m_view->page()->findText("foo", {}); QTRY_COMPARE(findTextSpy.count(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 3); @@ -1109,7 +1146,7 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal() } // The last match is followed by the fist one. - m_view->page()->findText("foo", 0); + m_view->page()->findText("foo", {}); QTRY_COMPARE(findTextSpy.count(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 3); @@ -1123,14 +1160,14 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal() QCOMPARE(result.activeMatch(), 3); // Finding another word resets the activeMatch. - m_view->page()->findText("bar", 0); + m_view->page()->findText("bar", {}); QTRY_COMPARE(findTextSpy.count(), 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", 0); + m_view->page()->findText("bla", {}); QTRY_COMPARE(findTextSpy.count(), 1); result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>(); QCOMPARE(result.numberOfMatches(), 0); @@ -1668,156 +1705,51 @@ void tst_QWebEnginePage::openWindowDefaultSize() QCOMPARE(requestedGeometry.height(), 100); } -class JavaScriptCallbackBase +bool tst_QWebEnginePage::isFalseJavaScriptResult(QWebEnginePage *page, const QString &javaScript) { -public: - JavaScriptCallbackBase() - { - if (watcher) - QMetaObject::invokeMethod(watcher, "add"); - } - - void operator() (const QVariant &result) - { - check(result); - if (watcher) - QMetaObject::invokeMethod(watcher, "notify"); - } - -protected: - virtual void check(const QVariant &result) = 0; - -private: - friend class JavaScriptCallbackWatcher; - static QPointer<QObject> watcher; -}; - -QPointer<QObject> JavaScriptCallbackBase::watcher = 0; - -class JavaScriptCallback : public JavaScriptCallbackBase -{ -public: - JavaScriptCallback() { } - JavaScriptCallback(const QVariant& _expected) : expected(_expected) { } - - void check(const QVariant& result) override - { - QVERIFY(result.isValid()); - QCOMPARE(result, expected); - } - -private: - QVariant expected; -}; - -class JavaScriptCallbackNull : public JavaScriptCallbackBase -{ -public: - void check(const QVariant& result) override - { - QVERIFY(result.isNull()); -// FIXME: Returned null values are currently invalid QVariants. -// QVERIFY(result.isValid()); - } -}; + QVariant result = evaluateJavaScriptSync(page, javaScript); + return !result.isNull() && result.isValid() && result == QVariant(false); +} -class JavaScriptCallbackUndefined : public JavaScriptCallbackBase +bool tst_QWebEnginePage::isTrueJavaScriptResult(QWebEnginePage *page, const QString &javaScript) { -public: - void check(const QVariant& result) override - { - QVERIFY(result.isNull()); - QVERIFY(!result.isValid()); - } -}; + QVariant result = evaluateJavaScriptSync(page, javaScript); + return !result.isNull() && result.isValid() && result == QVariant(true); +} -class JavaScriptCallbackWatcher : public QObject +bool tst_QWebEnginePage::isEmptyListJavaScriptResult(QWebEnginePage *page, const QString &javaScript) { - Q_OBJECT -public: - JavaScriptCallbackWatcher() - { - Q_ASSERT(!JavaScriptCallbackBase::watcher); - JavaScriptCallbackBase::watcher = this; - } - - Q_INVOKABLE void add() - { - available++; - } - - Q_INVOKABLE void notify() - { - called++; - if (called == available) - emit allCalled(); - } - - bool wait(int maxSeconds = 30) - { - if (called == available) - return true; - - QTestEventLoop loop; - connect(this, SIGNAL(allCalled()), &loop, SLOT(exitLoop())); - loop.enterLoop(maxSeconds); - return !loop.timeout(); - } - -signals: - void allCalled(); - -private: - int available = 0; - int called = 0; -}; - + QVariant result = evaluateJavaScriptSync(page, javaScript); + return !result.isNull() && result.isValid() && result == QList<QVariant>(); +} void tst_QWebEnginePage::runJavaScript() { TestPage page; - JavaScriptCallbackWatcher watcher; - - JavaScriptCallback callbackBool(QVariant(false)); - page.runJavaScript("false", QWebEngineCallback<const QVariant&>(callbackBool)); - - JavaScriptCallback callbackInt(QVariant(2)); - page.runJavaScript("2", QWebEngineCallback<const QVariant&>(callbackInt)); - - JavaScriptCallback callbackDouble(QVariant(2.5)); - page.runJavaScript("2.5", QWebEngineCallback<const QVariant&>(callbackDouble)); - - JavaScriptCallback callbackString(QVariant(QStringLiteral("Test"))); - page.runJavaScript("\"Test\"", QWebEngineCallback<const QVariant&>(callbackString)); - - QVariantList list; - JavaScriptCallback callbackList(list); - page.runJavaScript("[]", QWebEngineCallback<const QVariant&>(callbackList)); - + QVariant result; QVariantMap map; - map.insert(QStringLiteral("test"), QVariant(2)); - JavaScriptCallback callbackMap(map); - page.runJavaScript("var el = {\"test\": 2}; el", QWebEngineCallback<const QVariant&>(callbackMap)); - JavaScriptCallbackNull callbackNull; - page.runJavaScript("null", QWebEngineCallback<const QVariant&>(callbackNull)); + QVERIFY(isFalseJavaScriptResult(&page, "false")); + QCOMPARE(evaluateJavaScriptSync(&page, "2").toInt(), 2); + QCOMPARE(evaluateJavaScriptSync(&page, "2.5").toDouble(), 2.5); + QCOMPARE(evaluateJavaScriptSync(&page, "\"Test\"").toString(), "Test"); + QVERIFY(isEmptyListJavaScriptResult(&page, "[]")); - JavaScriptCallbackUndefined callbackUndefined; - page.runJavaScript("undefined", QWebEngineCallback<const QVariant&>(callbackUndefined)); + map.insert(QStringLiteral("test"), QVariant(2)); + QCOMPARE(evaluateJavaScriptSync(&page, "var el = {\"test\": 2}; el").toMap(), map); - JavaScriptCallback callbackDate(QVariant(42.0)); - page.runJavaScript("new Date(42000)", QWebEngineCallback<const QVariant&>(callbackDate)); + QVERIFY(evaluateJavaScriptSync(&page, "null").isNull()); - JavaScriptCallback callbackBlob(QVariant(QByteArray(8, 0))); - page.runJavaScript("new ArrayBuffer(8)", QWebEngineCallback<const QVariant&>(callbackBlob)); + result = evaluateJavaScriptSync(&page, "undefined"); + QVERIFY(result.isNull() && !result.isValid()); - JavaScriptCallbackUndefined callbackFunction; - page.runJavaScript("(function(){})", QWebEngineCallback<const QVariant&>(callbackFunction)); + QCOMPARE(evaluateJavaScriptSync(&page, "new Date(42000)").toDate(), QVariant(42.0).toDate()); + QCOMPARE(evaluateJavaScriptSync(&page, "new ArrayBuffer(8)").toByteArray(), QByteArray(8, 0)); - JavaScriptCallback callbackPromise(QVariant(QVariantMap{})); - page.runJavaScript("new Promise(function(){})", QWebEngineCallback<const QVariant&>(callbackPromise)); + result = evaluateJavaScriptSync(&page, "(function(){})"); + QVERIFY(result.isNull() && !result.isValid()); - QVERIFY(watcher.wait()); + QCOMPARE(evaluateJavaScriptSync(&page, "new Promise(function(){})"), QVariant(QVariantMap{})); } void tst_QWebEnginePage::runJavaScriptDisabled() @@ -1860,7 +1792,6 @@ void tst_QWebEnginePage::runJavaScriptFromSlot() void tst_QWebEnginePage::fullScreenRequested() { - JavaScriptCallbackWatcher watcher; QWebEngineView view; QWebEnginePage* page = view.page(); view.show(); @@ -1871,9 +1802,8 @@ void tst_QWebEnginePage::fullScreenRequested() page->load(QUrl("qrc:///resources/fullscreen.html")); QTRY_COMPARE(loadSpy.count(), 1); - page->runJavaScript("document.webkitFullscreenEnabled", JavaScriptCallback(true)); - page->runJavaScript("document.webkitIsFullScreen", JavaScriptCallback(false)); - QVERIFY(watcher.wait()); + QTRY_VERIFY(isTrueJavaScriptResult(page, "document.webkitFullscreenEnabled")); + QVERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen")); // FullscreenRequest must be a user gesture bool acceptRequest = true; @@ -1883,17 +1813,15 @@ void tst_QWebEnginePage::fullScreenRequested() }); QTest::keyPress(view.focusProxy(), Qt::Key_Space); - QTRY_VERIFY(evaluateJavaScriptSync(page, "document.webkitIsFullScreen").toBool()); - page->runJavaScript("document.webkitExitFullscreen()", JavaScriptCallbackUndefined()); - QVERIFY(watcher.wait()); + QTRY_VERIFY(isTrueJavaScriptResult(page, "document.webkitIsFullScreen")); + page->runJavaScript("document.webkitExitFullscreen()"); + QTRY_VERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen")); acceptRequest = false; - page->runJavaScript("document.webkitFullscreenEnabled", JavaScriptCallback(true)); + QVERIFY(isTrueJavaScriptResult(page, "document.webkitFullscreenEnabled")); QTest::keyPress(view.focusProxy(), Qt::Key_Space); - QVERIFY(watcher.wait()); - page->runJavaScript("document.webkitIsFullScreen", JavaScriptCallback(false)); - QVERIFY(watcher.wait()); + QTRY_VERIFY(isFalseJavaScriptResult(page, "document.webkitIsFullScreen")); } void tst_QWebEnginePage::quotaRequested() @@ -2026,7 +1954,8 @@ void tst_QWebEnginePage::urlChange() QUrl testUrl("http://test.qt.io/"); m_view->setHtml(QStringLiteral("<h1>Test</h1"), testUrl); - QTRY_COMPARE(urlSpy.size(), 1); + QTRY_COMPARE(urlSpy.size(), 2); + QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), QUrl("data:text/html;charset=UTF-8,%3Ch1%3ETest%3C%2Fh1")); QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), testUrl); } @@ -2086,7 +2015,7 @@ private Q_SLOTS: void continueError() { - emit error(this->error()); + emit error(this->networkError()); emit finished(); } }; @@ -2767,14 +2696,14 @@ void tst_QWebEnginePage::setUrlUsingStateObject() evaluateJavaScriptSync(m_page, "window.history.pushState(null, 'push', 'navigate/to/here')"); expectedUrlChangeCount++; - QCOMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.count(), 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++; - QCOMPARE(urlChangedSpy.count(), expectedUrlChangeCount); + QTRY_COMPARE(urlChangedSpy.count(), expectedUrlChangeCount); QCOMPARE(m_page->url(), QUrl("qrc:/resources/navigate/to/another/location")); QCOMPARE(m_page->history()->count(), 2); QVERIFY(!m_page->history()->canGoForward()); @@ -2823,8 +2752,8 @@ void tst_QWebEnginePage::setUrlThenLoads() const QUrl urlToLoad2("qrc:/resources/test1.html"); m_page->load(urlToLoad1); - QCOMPARE(m_page->url(), urlToLoad1); - QCOMPARE(m_page->requestedUrl(), urlToLoad1); + QTRY_COMPARE(m_page->url(), urlToLoad1); + 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); @@ -2838,8 +2767,8 @@ void tst_QWebEnginePage::setUrlThenLoads() QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1)); m_page->load(urlToLoad2); - QCOMPARE(m_page->url(), urlToLoad2); - QCOMPARE(m_page->requestedUrl(), urlToLoad2); + QTRY_COMPARE(m_page->url(), urlToLoad2); + QTRY_COMPARE(m_page->requestedUrl(), urlToLoad2); QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1)); QTRY_COMPARE(startedSpy.count(), 3); @@ -3352,7 +3281,7 @@ void tst_QWebEnginePage::dataURLFragment() QTRY_COMPARE(loadFinishedSpy.count(), 1); QSignalSpy urlChangedSpy(m_page, SIGNAL(urlChanged(QUrl))); - QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, elementCenter(m_page, "link")); + QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link")); QVERIFY(urlChangedSpy.wait()); QCOMPARE(m_page->url().fragment(), QStringLiteral("anchor")); @@ -3362,7 +3291,7 @@ void tst_QWebEnginePage::dataURLFragment() "</body></html>", QUrl("http://test.qt.io/mytest.html")); QTRY_COMPARE(loadFinishedSpy.count(), 2); - QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, elementCenter(m_page, "link")); + QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link")); QVERIFY(urlChangedSpy.wait()); QCOMPARE(m_page->url(), QUrl("http://test.qt.io/mytest.html#anchor")); } @@ -3384,7 +3313,7 @@ void tst_QWebEnginePage::devTools() QCOMPARE(devToolsPage.devToolsPage(), nullptr); QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage1); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000); QVERIFY(spy.takeFirst().value(0).toBool()); devToolsPage.setInspectedPage(&inspectedPage2); @@ -3396,7 +3325,7 @@ void tst_QWebEnginePage::devTools() QCOMPARE(devToolsPage.devToolsPage(), nullptr); QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage2); - QTRY_COMPARE(spy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000); QVERIFY(spy.takeFirst().value(0).toBool()); devToolsPage.setInspectedPage(nullptr); @@ -3432,7 +3361,7 @@ void tst_QWebEnginePage::openLinkInDifferentProfile() QTRY_COMPARE(spy1.count(), 1); QVERIFY(spy1.takeFirst().value(0).toBool()); page1.targetPage = &page2; - QTest::mouseClick(view.focusProxy(), Qt::MiddleButton, 0, elementCenter(&page1, "link")); + QTest::mouseClick(view.focusProxy(), Qt::MiddleButton, {}, elementCenter(&page1, "link")); QTRY_COMPARE(spy2.count(), 1); QVERIFY(spy2.takeFirst().value(0).toBool()); } @@ -3876,9 +3805,9 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools() // Ensure pages are initialized inspectedPage.load(QStringLiteral("about:blank")); devToolsPage.load(QStringLiteral("about:blank")); - QTRY_COMPARE(inspectedSpy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(inspectedSpy.count(), 1, 30000); QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true)); - QTRY_COMPARE(devToolsSpy.count(), 1); + QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 30000); QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true)); // Open DevTools with Frozen inspectedPage @@ -4389,7 +4318,7 @@ void tst_QWebEnginePage::customUserAgentInNewTab() QTRY_COMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().value(0).toBool()); QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), profile1.httpUserAgent()); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link")); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); QTRY_VERIFY(page.newPage); QTRY_VERIFY(!lastUserAgent.isEmpty()); QCOMPARE(lastUserAgent, profile1.httpUserAgent().toUtf8()); @@ -4404,12 +4333,50 @@ void tst_QWebEnginePage::customUserAgentInNewTab() QString("'>link</a></body></html>")); QTRY_COMPARE(spy.count(), 1); QVERIFY(spy.takeFirst().value(0).toBool()); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link")); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link")); QTRY_VERIFY(page.newPage); QTRY_VERIFY(!lastUserAgent.isEmpty()); QCOMPARE(lastUserAgent, profile2.httpUserAgent().toUtf8()); } +void tst_QWebEnginePage::renderProcessCrashed() +{ + using Status = QWebEnginePage::RenderProcessTerminationStatus; + QWebEngineProfile profile; + QWebEnginePage page(&profile); + bool done = false; + Status status; + connect(&page, &QWebEnginePage::renderProcessTerminated, [&](Status newStatus) { + status = newStatus; + done = true; + }); + page.load(QUrl("chrome://crash")); + QTRY_VERIFY_WITH_TIMEOUT(done, 20000); + // The status depends on whether stack traces are enabled. With + // --disable-in-process-stack-traces we get an AbnormalTerminationStatus, + // otherwise a CrashedTerminationStatus. + QVERIFY(status == QWebEnginePage::CrashedTerminationStatus || + status == QWebEnginePage::AbnormalTerminationStatus); +} + +void tst_QWebEnginePage::renderProcessPid() +{ + QCOMPARE(m_page->renderProcessPid(), 0); + + m_page->load(QUrl("about:blank")); + QSignalSpy spyFinished(m_page, &QWebEnginePage::loadFinished); + QVERIFY(spyFinished.wait()); + + QVERIFY(m_page->renderProcessPid() > 1); + + bool crashed = false; + connect(m_page, &QWebEnginePage::renderProcessTerminated, [&]() { crashed = true; }); + m_page->load(QUrl("chrome://crash")); + QTRY_VERIFY_WITH_TIMEOUT(crashed, 20000); + + QCOMPARE(m_page->renderProcessPid(), 0); +} + static QByteArrayList params = {QByteArrayLiteral("--use-fake-device-for-media-stream")}; W_QTEST_MAIN(tst_QWebEnginePage, params) diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp index a7a5ba62a..1dd8a38c8 100644 --- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp +++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp @@ -67,6 +67,7 @@ private Q_SLOTS: void urlSchemeHandlerInstallation(); void urlSchemeHandlerXhrStatus(); void urlSchemeHandlerScriptModule(); + void urlSchemeHandlerLongReply(); void customUserAgent(); void httpAcceptLanguage(); void downloadItem(); @@ -153,17 +154,17 @@ void tst_QWebEngineProfile::testProfile() void tst_QWebEngineProfile::clearDataFromCache() { - QWebEnginePage page; - QDir cacheDir("./tst_QWebEngineProfile_cacheDir"); cacheDir.makeAbsolute(); if (cacheDir.exists()) cacheDir.removeRecursively(); cacheDir.mkpath(cacheDir.path()); - QWebEngineProfile *profile = page.profile(); - profile->setCachePath(cacheDir.path()); - profile->setHttpCacheType(QWebEngineProfile::DiskHttpCache); + QWebEngineProfile profile(QStringLiteral("Test")); + profile.setCachePath(cacheDir.path()); + profile.setHttpCacheType(QWebEngineProfile::DiskHttpCache); + + QWebEnginePage page(&profile, nullptr); QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); page.load(QUrl("http://qt-project.org")); @@ -180,7 +181,7 @@ void tst_QWebEngineProfile::clearDataFromCache() QSignalSpy directoryChangedSpy(&fileSystemWatcher, SIGNAL(directoryChanged(const QString &))); // It deletes most of the files, but not all of them. - profile->clearHttpCache(); + profile.clearHttpCache(); QTest::qWait(1000); QTRY_VERIFY(directoryChangedSpy.count() > 0); @@ -294,7 +295,7 @@ protected: memcpy(data, m_data.constData() + m_bytesRead, len); m_bytesAvailable -= len; m_bytesRead += len; - } else if (m_data.size() > 0) + } else if (atEnd()) return -1; return len; @@ -714,6 +715,31 @@ void tst_QWebEngineProfile::urlSchemeHandlerScriptModule() QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("test")).toString(), QStringLiteral("SUCCESS")); } +class LongReplyUrlSchemeHandler : public QWebEngineUrlSchemeHandler +{ +public: + LongReplyUrlSchemeHandler(QObject *parent = nullptr) : QWebEngineUrlSchemeHandler(parent) {} + ~LongReplyUrlSchemeHandler() {} + + void requestStarted(QWebEngineUrlRequestJob *job) + { + QBuffer *buffer = new QBuffer(job); + buffer->setData(QByteArray(128 * 1024, ' ') + + "<html><head><title>Minify this!</title></head></html>"); + job->reply("text/html", buffer); + } +}; + +void tst_QWebEngineProfile::urlSchemeHandlerLongReply() +{ + LongReplyUrlSchemeHandler handler; + QWebEngineProfile profile; + profile.installUrlSchemeHandler("aviancarrier", &handler); + QWebEnginePage page(&profile); + page.load(QUrl("aviancarrier:/")); + QTRY_COMPARE(page.title(), QString("Minify this!")); +} + void tst_QWebEngineProfile::customUserAgent() { QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent(); @@ -815,26 +841,32 @@ void tst_QWebEngineProfile::initiator() InitiatorSpy handler; QWebEngineProfile profile; profile.installUrlSchemeHandler("foo", &handler); - QWebEnginePage page(&profile); + QWebEnginePage page(&profile, nullptr); QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool))); + page.load(QUrl("about:blank")); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + loadFinishedSpy.clear(); // about:blank has a unique origin, so initiator should be QUrl("null") evaluateJavaScriptSync(&page, "window.location = 'foo:bar'"); - QVERIFY(loadFinishedSpy.wait()); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + loadFinishedSpy.clear(); QCOMPARE(handler.initiator, QUrl("null")); page.setHtml("", QUrl("http://test:123/foo%20bar")); - QVERIFY(loadFinishedSpy.wait()); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + loadFinishedSpy.clear(); // baseUrl determines the origin, so QUrl("http://test:123") evaluateJavaScriptSync(&page, "window.location = 'foo:bar'"); - QVERIFY(loadFinishedSpy.wait()); + QTRY_COMPARE(loadFinishedSpy.count(), 1); + loadFinishedSpy.clear(); QCOMPARE(handler.initiator, QUrl("http://test:123")); // Directly calling load/setUrl should have initiator QUrl(), meaning // browser-initiated, trusted. page.load(QUrl("foo:bar")); - QVERIFY(loadFinishedSpy.wait()); + QTRY_COMPARE(loadFinishedSpy.count(), 1); QCOMPARE(handler.initiator, QUrl()); } diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 044fac9d7..f15a65469 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -60,6 +60,8 @@ do { \ QCOMPARE((__expr), __expected); \ } while (0) +static QTouchDevice* s_touchDevice = nullptr; + static QPoint elementCenter(QWebEnginePage *page, const QString &id) { const QString jsCode( @@ -165,6 +167,9 @@ private Q_SLOTS: void keyboardEvents(); void keyboardFocusAfterPopup(); void mouseClick(); + void touchTap(); + void touchTapAndHold(); + void touchTapAndHoldCancelled(); void postData(); void inputFieldOverridesShortcuts(); @@ -210,6 +215,7 @@ private Q_SLOTS: // It is only called once. void tst_QWebEngineView::initTestCase() { + s_touchDevice = QTest::createTouchDevice(); } // This will be called after the last test function is executed. @@ -531,7 +537,7 @@ void tst_QWebEngineView::focusInputTypes() // 'text' field QPoint textInputCenter = elementCenter(webView.page(), "textInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -539,7 +545,7 @@ void tst_QWebEngineView::focusInputTypes() // 'password' field QPoint passwordInputCenter = elementCenter(webView.page(), "passwordInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -547,7 +553,7 @@ void tst_QWebEngineView::focusInputTypes() // 'tel' field QPoint telInputCenter = elementCenter(webView.page(), "telInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, telInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, telInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("telInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDialableCharactersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -555,7 +561,7 @@ void tst_QWebEngineView::focusInputTypes() // 'number' field QPoint numberInputCenter = elementCenter(webView.page(), "numberInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, numberInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, numberInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("numberInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -563,7 +569,7 @@ void tst_QWebEngineView::focusInputTypes() // 'email' field QPoint emailInputCenter = elementCenter(webView.page(), "emailInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, emailInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, emailInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("emailInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -571,28 +577,28 @@ void tst_QWebEngineView::focusInputTypes() // 'url' field QPoint urlInputCenter = elementCenter(webView.page(), "urlInput"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, urlInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, urlInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("urlInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase)); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'password' field - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability); // 'text' type - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool()); // 'password' field - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText)); QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -600,7 +606,7 @@ void tst_QWebEngineView::focusInputTypes() // 'text area' field QPoint textAreaCenter = elementCenter(webView.page(), "textArea"); - QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textAreaCenter); + QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textAreaCenter); QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textArea")); VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhMultiLine | Qt::ImhPreferLowercase)); QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); @@ -689,12 +695,12 @@ void tst_QWebEngineView::horizontalScrollbarTest() QSignalSpy scrollSpy(view.page(), SIGNAL(scrollPositionChanged(QPointF))); // Note: The test below assumes that the layout direction is Qt::LeftToRight. - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, QPoint(550, 595)); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, QPoint(550, 595)); scrollSpy.wait(); QVERIFY(view.page()->scrollPosition().x() > 0); // Note: The test below assumes that the layout direction is Qt::LeftToRight. - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, QPoint(20, 595)); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, QPoint(20, 595)); scrollSpy.wait(); QVERIFY(view.page()->scrollPosition() == QPoint(0, 0)); } @@ -1465,7 +1471,7 @@ void tst_QWebEngineView::mouseClick() QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); textInputCenter = elementCenter(view.page(), "input"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); QCOMPARE(selectionChangedSpy.count(), 0); QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty()); @@ -1486,7 +1492,7 @@ void tst_QWebEngineView::mouseClick() QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("Company")); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 2); QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty()); @@ -1507,12 +1513,178 @@ void tst_QWebEngineView::mouseClick() QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("The Qt Company")); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 3); QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty()); } +void tst_QWebEngineView::touchTap() +{ +#if defined(Q_OS_MACOS) + QSKIP("Synthetic touch events are not supported on macOS"); +#endif + + QWebEngineView view; + view.show(); + view.resize(200, 200); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished); + + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + view.setHtml("<html><body>" + "<p id='text' style='width: 150px;'>The Qt Company</p>" + "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>" + "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + + auto singleTap = [](QWidget* target, const QPoint& tapCoords) -> void { + QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target); + QTest::touchEvent(target, s_touchDevice).stationary(1); + QTest::touchEvent(target, s_touchDevice).release(1, tapCoords, target); + }; + + // Single tap on text doesn't trigger a selection + singleTap(view.focusProxy(), elementCenter(view.page(), "text")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + QTRY_VERIFY(!view.hasSelection()); + + // Single tap inside the input field focuses it without selecting the text + singleTap(view.focusProxy(), elementCenter(view.page(), "input")); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); + QTRY_VERIFY(!view.hasSelection()); + + // Single tap on the div clears the input field focus + singleTap(view.focusProxy(), elementCenter(view.page(), "notext")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + + // Double tap on text still doesn't trigger a selection + singleTap(view.focusProxy(), elementCenter(view.page(), "text")); + singleTap(view.focusProxy(), elementCenter(view.page(), "text")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + QTRY_VERIFY(!view.hasSelection()); + + // Double tap inside the input field focuses it and selects the word under it + singleTap(view.focusProxy(), elementCenter(view.page(), "input")); + singleTap(view.focusProxy(), elementCenter(view.page(), "input")); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); + QTRY_COMPARE(view.selectedText(), QStringLiteral("Company2")); + + // Double tap outside the input field behaves like a single tap: clears its focus and selection + singleTap(view.focusProxy(), elementCenter(view.page(), "notext")); + singleTap(view.focusProxy(), elementCenter(view.page(), "notext")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + QTRY_VERIFY(!view.hasSelection()); +} + +void tst_QWebEngineView::touchTapAndHold() +{ +#if defined(Q_OS_MACOS) + QSKIP("Synthetic touch events are not supported on macOS"); +#endif + + QWebEngineView view; + view.show(); + view.resize(200, 200); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished); + + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + view.setHtml("<html><body>" + "<p id='text' style='width: 150px;'>The Qt Company</p>" + "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>" + "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + + auto tapAndHold = [](QWidget* target, const QPoint& tapCoords) -> void { + QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target); + QTest::touchEvent(target, s_touchDevice).stationary(1); + QTest::qWait(1000); + QTest::touchEvent(target, s_touchDevice).release(1, tapCoords, target); + }; + + // Tap-and-hold on text selects the word under it + tapAndHold(view.focusProxy(), elementCenter(view.page(), "text")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + QTRY_COMPARE(view.selectedText(), QStringLiteral("Company")); + + // Tap-and-hold inside the input field focuses it and selects the word under it + tapAndHold(view.focusProxy(), elementCenter(view.page(), "input")); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input")); + QTRY_COMPARE(view.selectedText(), QStringLiteral("Company2")); + + // Only test the page context menu on Windows, as Linux doesn't handle context menus consistently + // and other non-desktop platforms like Android may not even support context menus at all +#if defined(Q_OS_WIN) + // Tap-and-hold clears the text selection and shows the page's context menu + QVERIFY(QApplication::activePopupWidget() == nullptr); + tapAndHold(view.focusProxy(), elementCenter(view.page(), "notext")); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + QTRY_VERIFY(!view.hasSelection()); + QTRY_VERIFY(QApplication::activePopupWidget() != nullptr); + + QApplication::activePopupWidget()->close(); + QVERIFY(QApplication::activePopupWidget() == nullptr); +#endif +} + +void tst_QWebEngineView::touchTapAndHoldCancelled() +{ +#if defined(Q_OS_MACOS) + QSKIP("Synthetic touch events are not supported on macOS"); +#endif + + QWebEngineView view; + view.show(); + view.resize(200, 200); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + + QSignalSpy loadFinishedSpy(&view, &QWebEngineView::loadFinished); + + view.settings()->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, false); + view.setHtml("<html><body>" + "<p id='text' style='width: 150px;'>The Qt Company</p>" + "<div id='notext' style='width: 150px; height: 100px; background-color: #f00;'></div>" + "<form><input id='input' width='150px' type='text' value='The Qt Company2' /></form>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty()); + + auto cancelledTapAndHold = [](QWidget* target, const QPoint& tapCoords) -> void { + QTest::touchEvent(target, s_touchDevice).press(1, tapCoords, target); + QTest::touchEvent(target, s_touchDevice).stationary(1); + QTest::qWait(1000); + QWindowSystemInterface::handleTouchCancelEvent(target->windowHandle(), s_touchDevice); + }; + + // A cancelled tap-and-hold should cancel text selection, but currently doesn't + cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "text")); + QEXPECT_FAIL("", "Incorrect Chromium selection behavior when cancelling tap-and-hold on text", Continue); + QTRY_VERIFY_WITH_TIMEOUT(!view.hasSelection(), 100); + + // A cancelled tap-and-hold should cancel input field focusing and selection, but currently doesn't + cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "input")); + QEXPECT_FAIL("", "Incorrect Chromium selection behavior when cancelling tap-and-hold on input field", Continue); + QTRY_VERIFY_WITH_TIMEOUT(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty(), 100); + QEXPECT_FAIL("", "Incorrect Chromium focus behavior when cancelling tap-and-hold on input field", Continue); + QTRY_VERIFY_WITH_TIMEOUT(!view.hasSelection(), 100); + + // Only test the page context menu on Windows, as Linux doesn't handle context menus consistently + // and other non-desktop platforms like Android may not even support context menus at all +#if defined(Q_OS_WIN) + // A cancelled tap-and-hold cancels the context menu + QVERIFY(QApplication::activePopupWidget() == nullptr); + cancelledTapAndHold(view.focusProxy(), elementCenter(view.page(), "notext")); + QVERIFY(QApplication::activePopupWidget() == nullptr); +#endif +} + void tst_QWebEngineView::postData() { QMap<QString, QString> postData; @@ -1657,6 +1829,7 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() view.setHtml(QString("<html><body>" "<button id=\"btn1\" type=\"button\">push it real good</button>" "<input id=\"input1\" type=\"text\" value=\"x\">" + "<input id=\"pass1\" type=\"password\" value=\"x\">" "</body></html>")); QVERIFY(loadFinishedSpy.wait()); @@ -1668,6 +1841,11 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() "document.getElementById('input1').value").toString(); }; + auto passwordFieldValue = [&view] () -> QString { + return evaluateJavaScriptSync(view.page(), + "document.getElementById('pass1').value").toString(); + }; + // The input form is not focused. The action is triggered on pressing Shift+Delete. action->setShortcut(Qt::SHIFT + Qt::Key_Delete); QTest::keyClick(view.windowHandle(), Qt::Key_Delete, Qt::ShiftModifier); @@ -1691,8 +1869,20 @@ void tst_QWebEngineView::inputFieldOverridesShortcuts() QTRY_COMPARE(inputFieldValue(), QString("yxx")); QVERIFY(!actionTriggered); + // The password input form is focused. The action is not triggered, and the form's text changed. + evaluateJavaScriptSync(view.page(), "document.getElementById('pass1').focus();"); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("pass1")); + actionTriggered = false; + QTest::keyClick(view.windowHandle(), Qt::Key_Y); + QTRY_COMPARE(passwordFieldValue(), QString("yx")); + QTest::keyClick(view.windowHandle(), Qt::Key_X); + QTRY_COMPARE(passwordFieldValue(), QString("yxx")); + QVERIFY(!actionTriggered); + // The input form is focused. Make sure we don't override all short cuts. // A Ctrl-1 action is no default Qt key binding and should be triggerable. + evaluateJavaScriptSync(view.page(), "document.getElementById('input1').focus();"); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); action->setShortcut(Qt::CTRL + Qt::Key_1); QTest::keyClick(view.windowHandle(), Qt::Key_1, Qt::ControlModifier); QTRY_VERIFY(actionTriggered); @@ -1800,7 +1990,7 @@ void tst_QWebEngineView::softwareInputPanel() QVERIFY(loadFinishedSpy.wait()); QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); // This part of the test checks if the SIP (Software Input Panel) is triggered, @@ -1819,7 +2009,7 @@ void tst_QWebEngineView::softwareInputPanel() QTRY_VERIFY(!testContext.isInputPanelVisible()); testContext.hideInputPanel(); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_VERIFY(testContext.isInputPanelVisible()); view.setHtml("<html><body><p id='para'>nothing to input here</p></body></html>"); @@ -1827,7 +2017,7 @@ void tst_QWebEngineView::softwareInputPanel() testContext.hideInputPanel(); QPoint paraCenter = elementCenter(view.page(), "para"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, paraCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, paraCenter); QVERIFY(!testContext.isInputPanelVisible()); @@ -1839,7 +2029,7 @@ void tst_QWebEngineView::softwareInputPanel() QVERIFY(loadFinishedSpy.wait()); QPoint btnDivCenter = elementCenter(view.page(), "btnDiv"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, btnDivCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, btnDivCenter); QVERIFY(!testContext.isInputPanelVisible()); } @@ -1864,7 +2054,7 @@ void tst_QWebEngineView::inputContextQueryInput() // Set focus on an input field. QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(testContext.infos.count(), 2); QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); foreach (const InputMethodInfo &info, testContext.infos) { @@ -2013,7 +2203,7 @@ void tst_QWebEngineView::inputMethods() QTRY_COMPARE(loadFinishedSpy.size(), 1); QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); // ImCursorRectangle @@ -2114,7 +2304,7 @@ void tst_QWebEngineView::textSelectionInInputField() // LEFT to RIGHT selection // Mouse click event moves the current cursor to the end of the text QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11); QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11); @@ -2156,7 +2346,7 @@ void tst_QWebEngineView::textSelectionInInputField() // RIGHT to LEFT selection // Deselect the selection (this moves the current cursor to the end of the text) - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 2); @@ -2196,7 +2386,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QVERIFY(view.page()->selectedText().isEmpty()); // Simple click should not update text selection, however it updates selection bounds in Chromium - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center()); QCOMPARE(selectionChangedSpy.count(), 0); QVERIFY(!view.hasSelection()); QVERIFY(view.page()->selectedText().isEmpty()); @@ -2209,7 +2399,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QCOMPARE(view.page()->selectedText(), QString("This is a text")); // Deselect text by mouse click - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center()); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 2); QVERIFY(!view.hasSelection()); @@ -2256,7 +2446,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() // Remove selection by clicking into an input field QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); QCOMPARE(selectionChangedSpy.count(), 2); @@ -2271,7 +2461,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField() QCOMPARE(view.page()->selectedText(), QString("QtWebEngine")); // Deselect input field's text by mouse click - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center()); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center()); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 4); QVERIFY(!view.hasSelection()); @@ -2292,14 +2482,14 @@ void tst_QWebEngineView::hiddenText() QVERIFY(loadFinishedSpy.wait()); QPoint passwordInputCenter = elementCenter(view.page(), "password1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, passwordInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("password1")); QVERIFY(!view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); QVERIFY(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText); QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); QVERIFY(!(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText)); } @@ -2917,7 +3107,7 @@ void tst_QWebEngineView::globalMouseSelection() // Deselect the selection (this moves the current cursor to the end of the text) QPoint textInputCenter = elementCenter(view.page(), "input1"); - QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter); QVERIFY(selectionChangedSpy.wait()); QCOMPARE(selectionChangedSpy.count(), 2); QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty()); @@ -2958,36 +3148,55 @@ void tst_QWebEngineView::noContextMenu() void tst_QWebEngineView::contextMenu_data() { QTest::addColumn<int>("childrenCount"); + QTest::addColumn<bool>("isCustomMenu"); QTest::addColumn<Qt::ContextMenuPolicy>("contextMenuPolicy"); - QTest::newRow("defaultContextMenu") << 1 << Qt::DefaultContextMenu; - QTest::newRow("customContextMenu") << 1 << Qt::CustomContextMenu; - QTest::newRow("preventContextMenu") << 0 << Qt::PreventContextMenu; + QTest::newRow("defaultContextMenu") << 1 << false << Qt::DefaultContextMenu; + QTest::newRow("customContextMenu") << 1 << true << Qt::CustomContextMenu; + QTest::newRow("preventContextMenu") << 0 << false << Qt::PreventContextMenu; } void tst_QWebEngineView::contextMenu() { QFETCH(int, childrenCount); + QFETCH(bool, isCustomMenu); QFETCH(Qt::ContextMenuPolicy, contextMenuPolicy); QWebEngineView view; + QMenu *customMenu = nullptr; if (contextMenuPolicy == Qt::CustomContextMenu) { - connect(&view, &QWebEngineView::customContextMenuRequested, [&view](const QPoint &pt) { - QMenu* menu = new QMenu(&view); - menu->addAction("Action1"); - menu->addAction("Action2"); - menu->popup(pt); + connect(&view, &QWebEngineView::customContextMenuRequested, [&view, &customMenu] (const QPoint &pt) { + Q_ASSERT(!customMenu); + customMenu = new QMenu(&view); + customMenu->addAction("Action1"); + customMenu->addAction("Action2"); + customMenu->popup(pt); }); } view.setContextMenuPolicy(contextMenuPolicy); + + // input is supposed to be skipped before first real navigation in >= 79 + QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished); + view.load(QUrl("about:blank")); view.resize(640, 480); view.show(); + QTRY_COMPARE(loadSpy.count(), 1); QVERIFY(view.findChildren<QMenu *>().isEmpty()); QTest::mouseMove(view.windowHandle(), QPoint(10,10)); QTest::mouseClick(view.windowHandle(), Qt::RightButton); - QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount); + + // verify for zero children will always succeed, so should be tested with at least minor timeout + if (childrenCount <= 0) { + QVERIFY(!QTest::qWaitFor([&view] () { return view.findChildren<QMenu *>().count() > 0; }, 500)); + } else { + QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount); + if (isCustomMenu) { + QCOMPARE(view.findChildren<QMenu *>().first(), customMenu); + } + } + QCOMPARE(!!customMenu, isCustomMenu); } void tst_QWebEngineView::mouseLeave() diff --git a/tests/auto/widgets/schemes/tst_schemes.cpp b/tests/auto/widgets/schemes/tst_schemes.cpp index 1b6093571..a4a0e34ff 100644 --- a/tests/auto/widgets/schemes/tst_schemes.cpp +++ b/tests/auto/widgets/schemes/tst_schemes.cpp @@ -38,6 +38,7 @@ class tst_Schemes : public QObject Q_OBJECT private Q_SLOTS: + void unknownUrlSchemePolicy_data(); void unknownUrlSchemePolicy(); }; @@ -58,8 +59,27 @@ public: } }; +Q_DECLARE_METATYPE(QWebEngineSettings::UnknownUrlSchemePolicy) + +void tst_Schemes::unknownUrlSchemePolicy_data() +{ + QTest::addColumn<QWebEngineSettings::UnknownUrlSchemePolicy>("policy"); + QTest::addColumn<bool>("userAction"); + QTest::newRow("DisallowUnknownUrlSchemes, script") << QWebEngineSettings::DisallowUnknownUrlSchemes << false; + QTest::newRow("DisallowUnknownUrlSchemes, user") << QWebEngineSettings::DisallowUnknownUrlSchemes << true; + QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, script") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << false; + QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, user") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << true; + QTest::newRow("AllowAllUnknownUrlSchemes, script") << QWebEngineSettings::AllowAllUnknownUrlSchemes << false; + QTest::newRow("AllowAllUnknownUrlSchemes, user") << QWebEngineSettings::AllowAllUnknownUrlSchemes << true; + QTest::newRow("default UnknownUrlSchemePolicy, script") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << false; + QTest::newRow("default UnknownUrlSchemePolicy, user") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << true; +} + void tst_Schemes::unknownUrlSchemePolicy() { + QFETCH(QWebEngineSettings::UnknownUrlSchemePolicy, policy); + QFETCH(bool, userAction); + QWebEngineView view; AcceptNavigationRequestHandler page; QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished); @@ -71,41 +91,31 @@ void tst_Schemes::unknownUrlSchemePolicy() settings->setAttribute(QWebEngineSettings::ErrorPageEnabled, true); settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true); - QWebEngineSettings::UnknownUrlSchemePolicy policies[6] = {QWebEngineSettings::DisallowUnknownUrlSchemes, - QWebEngineSettings::DisallowUnknownUrlSchemes, - QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, - QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, - QWebEngineSettings::AllowAllUnknownUrlSchemes, - QWebEngineSettings::AllowAllUnknownUrlSchemes}; - // even iterations are for navigation-requests from javascript, - // odd iterations are for navigations-requests from user-interaction - for (int i = 0; i < 8; i++) { - if (i <= 5) - settings->setUnknownUrlSchemePolicy(policies[i]); - else - settings->resetUnknownUrlSchemePolicy(); - loadFinishedSpy.clear(); - page.acceptNavigationRequestCalls = 0; - bool shouldAccept; - - if (i % 2 == 0) { // navigation request coming from javascript - shouldAccept = (4 <= i && i <= 5); // only case AllowAllUnknownUrlSchemes - view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>"); - } else { // navigation request coming from user interaction - shouldAccept = (2 <= i); // all cases except DisallowUnknownUrlSchemes - view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>"); - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000); - // focus and trigger the link - view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) { - Q_UNUSED(result); - QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); - QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); - }); - } + if (policy > 0) + settings->setUnknownUrlSchemePolicy(policy); + else + settings->resetUnknownUrlSchemePolicy(); + loadFinishedSpy.clear(); + page.acceptNavigationRequestCalls = 0; + bool shouldAccept; - QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000); - QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0); + if (!userAction) { // navigation request coming from javascript + shouldAccept = (policy == QWebEngineSettings::AllowAllUnknownUrlSchemes); + view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>"); + } else { // navigation request coming from user interaction + shouldAccept = (policy != QWebEngineSettings::DisallowUnknownUrlSchemes); + view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>"); + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000); + // focus and trigger the link + view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) { + Q_UNUSED(result); + QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier); + }); } + + QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000); + QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0); } QTEST_MAIN(tst_Schemes) diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp index 64df05d89..801e2a76c 100644 --- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp +++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp @@ -41,10 +41,10 @@ public: void activateMenu(QWidget *widget, const QPoint &position) { QTest::mouseMove(widget, position); - QTest::mousePress(widget, Qt::RightButton, 0, position); + QTest::mousePress(widget, Qt::RightButton, {}, position); QContextMenuEvent evcont(QContextMenuEvent::Mouse, position, mapToGlobal(position)); event(&evcont); - QTest::mouseRelease(widget, Qt::RightButton, 0, position); + QTest::mouseRelease(widget, Qt::RightButton, {}, position); } const QWebEngineContextMenuData& data() @@ -175,8 +175,8 @@ void tst_Spellchecking::spellcheck() //type text, spellchecker needs time QTest::mouseMove(m_view->focusWidget(), QPoint(20,20)); - QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20)); - QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20)); + QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20)); + QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20)); QString text("I lowe Qt ...."); for (int i = 0; i < text.length(); i++) { QTest::keyClicks(m_view->focusWidget(), text.at(i)); diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h index eba974f33..20241be8b 100644 --- a/tests/auto/widgets/util.h +++ b/tests/auto/widgets/util.h @@ -132,7 +132,7 @@ static inline QString toHtmlSync(QWebEnginePage *page) static inline bool findTextSync(QWebEnginePage *page, const QString &subString) { CallbackSpy<bool> spy; - page->findText(subString, 0, spy.ref()); + page->findText(subString, {}, spy.ref()); return spy.waitForResult(); } |